Java基本类型与引⽤类型
Java 基本类型与引⽤类型
⼀、基本数据类型
java 中⼀共分为 8 种基本数据类型:byte、short、int、long、float、double、char、boolean,
其中 byte、short、int、long 是整型。float、double 是浮点型,char 是字符型,boolean 是布尔型。
⼆、引⽤类型
java 为每种基本类型都提供了对应的封装类型,分别为:Byte、Short、Integer、Long、Float、Double、Character、Boolean。引⽤类型是⼀种对象类型,它的值是指向内存空间的引⽤,就是地址。
三、基本类型与引⽤类型的区别
1. 默认值
整型 byte、short、int、long 的默认值都为 0,浮点型 float、double 的默认值为 0.0,boolean 默认值为 false,char 默认值为空。对应的包装类型默认值都为 null。
2. 内存分配
基本数据类型的变量是存储在栈内存中,⽽引⽤类型变量存储在栈内存中,保存的是实际对象在堆内存中的地址,实际对象中保存这内容。
3. ⾃动装箱、⾃动拆箱
Java 从 jdk1.5 开始引⼊⾃动装箱和拆箱,使得基本数据类型与引⽤类型之间相互转换变得简单。
⾃动装箱: java ⾃动将原始类型转化为引⽤类型的过程,⾃动装箱时编译器会调⽤ valueOf ⽅法,将原始类型转化为对象类型。
⾃动拆箱: java ⾃动将引⽤类型转化为原始类型的过程,⾃动拆箱时编译器会调⽤ intValue(),doubleValue() 这类的⽅法将对象转换成原始类型值。
⾃动装箱主要发⽣在两种情况:⼀种是赋值时,⼀种是⽅法调⽤时。
a.赋值
Integer a =3;//⾃动装箱
int b = a;//⾃动拆箱
b.⽅法调⽤
public Integer query(Integer a){
java valueofreturn a;
}
query(3);//⾃动装箱
int result =query(3);//⾃动拆箱
4. ⾃动装箱、拆箱带来的问题
(1)程序的性能
由于装箱会隐式地创建对象创建,因此千万不要在⼀个循环中进⾏⾃动装箱的操作,下⾯就是⼀个循环中进⾏⾃动装箱的例⼦,会额外创建多余的对象,增加 GC 的压⼒,影响程序的性能:
Integer sum =0;
for(int i=0; i<1000; i++){
sum+=i;
}
(2)空指针异常
注意拆箱过程中可能产⽣的空指针异常,⼀个简单的例⼦:
Object obj = null;
int i =(Integer)obj;
(3)对象相等⽐较时
先来看⼀个常见的例⼦:
Integer a =120;
int b =120;
Integer c =120;
Integer d =new Integer(120);
System.out.println(a == b);//true    t1
System.out.println(a == c);//true    t2
System.out.println(a == d);//false  t3
Integer e =128;
Integer f =128;
System.out.println(e == f);//false    t4
返回结果是不是出乎⼤家的意料,解释⼀下每种结果的原因:
我们先反编译⼀下⽣成字节码:
Integer a = Integer.valueOf(120);
int b =120;
Integer c = Integer.valueOf(120);
Integer d =new Integer(120);
System.out.println(a.intValue()== b);
System.out.println(a == c);
System.out.println(a == d);
Integer e = Integer.valueOf(127);
Integer f = Integer.valueOf(127);
System.out.println(e == f);
Integer e1 = Integer.valueOf(128);
Integer f1 = Integer.valueOf(128);
System.out.println(e1 == f1);
可以看到变量 a、c 在初始化的时候编译器调⽤了 valueOf 进⾏⾃动装箱,在 a==b 时对变量 a 调⽤了 intValue() ⽅法进⾏了⾃动拆箱操作,这就很好解释 t1~t4 的结果了。
t1 产⽣的原因是编译器编译时会调⽤ intValue() ⾃动的将 a 进⾏了拆箱,结果肯定是 true;
t2 跟 t4 的结果⽐较难理解:这是因为初始化时,编译器会调⽤装箱类的 valueOf() ⽅法,查看 jdk 的源码:
public static Integer valueOf(int i){
assert IntegerCache.high >=127;
if(i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i +(-IntegerCache.low)];
return new Integer(i);
}
发现 jdk 对 -128 ~ 127 之间的值做了缓存,对于 -128~127 之间的值会取缓存中的引⽤,通过缓存经常请求的值⽽显著提⾼空间和时间性能。
这就能解释 t2 结果返回 true,⽽ t4 由于 128 不在缓存区间内,编译器调⽤ valueOf ⽅法会重新创建新的对象,两个不同的对象返回false。
t3 结果⽆论如何都不会相等的,因为 new Integer(120) 构造器会创建新的对象。
Byte、Short、Integer、Long、Char 这⼏个装箱类的 valueOf() ⽅法都会做缓存,⽽ Float、Double 则不会,原因也很简单,因为byte、Short、integer、long、char 在某个范围内的整数个数是有限的,但是 float、double 这两个浮点数却不是。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。