Java一共包含8中基本数据类型,即boolean、byte、char、short、int、float、long、double,每种基本类型都有其对应的包装类型(如boolean对应Boolean,特殊地,int对应的是Integer、char对应的是Character)。以上8中类型对应的大小分别为1、8、16、16、32、32、64、64位。要注意的是,boolean类型可以用1bit进行存储,但JVM会将其用int表示,1表示true,0表示false)
低精度数据可以隐式地转成高精度数据,即自动向上转型
int a = 10;
long b = a; // a是int类型的,会自动向上转型成long类型,传递给b
但高精度数据不能自动向上转型成低精度数据,但可以通过强制方式进行转型,但向下转型容易造成精度丢失
long a = 10;
// int b = a; // 这里会报错,因为a是long类型,不能自动转型成int类型
int b = (int)a; // 可以通过强制转型的方式将a转成long类型后赋给b
特殊地,++和+=这类运算可以自动向下转型
short a = 10;
//a = a + 1; // 这一句会报错,因为short+int的结果会自动向上转型成int类型,而a是short类型
a++;
a += 1; //这两句不会报错,因为默认执行了a = (short)(a + 1);
如何理解包装类和基本类?可以看下源码:
private final int value;
/**
* Constructs a newly allocated {@code Integer} object that
* represents the specified {@code int} value.
*
* @param value the value to be represented by the
* {@code Integer} object.
*/
public Integer(int value) {
this.value = value;
}
其实,包装类不过是把基本类型的值和一些常用的方法封装在了一起。包装类的核心是里面的成员value,这个value的类型就是基本类型。
拆箱意思是把包装类型转换成基本类型(实际上就是把包装类里的value成员变量的值赋给基本类型);装箱则是把基本类型转换成包装类型(即将包装里的value成员初始化成对应的基本类型的值)。
Integer a = 10; // 10是基本类型,自动装箱
int b = a; // a是包装类型,b是基本类型,这里完成了自动拆箱
使用new Integer()这一构造方法来创建Integer对象时,每次都会创建一个新的对象
Integer a = new Integer(3);
Integer b = new Integer(3);
System.out.println(a == b); // 返回false,因为创建了两个不同的对象
需要注意的是,内存中有常量池(Constants Pool),里面缓存了一些常用的常量对象,当调用valueOf()方法时,如果常量池中存在要创建的对象,则直接返回该引用。Integer默认缓存[-128,127]
Integer a = Integer.valueOf(127);
Integer b = Integer.valueOf(127);
System.out.println(a == b); // 返回true,因为a和b指向同一个对象
Integer c = Integer.valueOf(128);
Integer d = Integer.valueOf(128);
System.out.println(c == d); // 返回false,128超出了缓存范围,不在常量池中,会重新创建新的对
//象,所以c和d是对不同对象的引用
自动装箱过程
//自动装箱过程实际上调用了valueOf方法,即Integer m = Integer.valueOf(10);而10在缓存中,所以
//会直接返回对象的引用
Integer m = 10;
Integer n = 10;
System.out.println(m == n); // 返回true,两者是对同一个对象的引用