33. 包装类型是什么?基本类型和包装类型有什么区别?
33. 包装类型是什么?基本类型和包装类型有什么区别?
包装类型就是把基本数据类型封装为对象的类。它允许基本数据类型具备对象的特性(方法调用,泛型支持等)
Java对每个基本数据类型都提供了包装类
原始类型:byte,short,int,long,float,double,boolean,char
包装类型:Byte,Short,Integer,Long,Float,Double,Boolean,Character
区别:
- 包装类型可以为null,基本数据类型不可以为null;在《阿里巴巴Java开发手册》里有详细讲到在数据库中查询结果有可能为null,如果使用基本类型,因为要自动拆箱,会把Integer转换为int类型,而基本数据类型不能为null,就会报出空指针异常(NullPointerException)
- 包装类可以用于泛型,基本类型不可以。泛型在编译时会进行类型擦除,最后只能是Object类或其子类。
- 基本数据类型比包装类更高效。基本数据类型会直接存储在栈中,存储具体的内容;而包装类是一个对象,会在堆里开辟一个空间,然后再取出对象的引用。
存储方式
基本类型 | 包装类型 |
---|---|
存储在栈内存中,直接存储值。 | 存储在堆内存中,变量存储的是对象的引用。 |
示例:int a = 5; (直接存储值 5 ) | 示例:Integer b = new Integer(5); (存储指向堆中对象的引用) |
默认值
基本类型 | 包装类型 |
---|---|
有默认值(如 int 默认为 0 ,boolean 默认为 false )。 | 未赋值时默认为 null (因为是引用类型)。 |
示例:int a; → a = 0 | 示例:Integer b; → b = null |
是否可以为 null
基本类型 | 包装类型 |
---|---|
不可为 null (直接存储值)。 | 可以为 null (引用类型)。 |
示例:int a = 5; → a 不能为 null | 示例:Integer b = null; → 合法 |
泛型支持
基本类型 | 包装类型 |
---|---|
不能用于泛型(泛型要求类型为对象)。 | 可以用于泛型(是对象类型)。 |
示例:List<int> list = new ArrayList<>(); → 编译错误 | 示例:List<Integer> list = new ArrayList<>(); → 合法 |
方法与操作
基本类型 | 包装类型 |
---|---|
只能存储值,没有方法或属性。 | 提供了许多方法(如类型转换、比较、解析等)。 |
示例:int a = 5; → 无法调用方法 | 示例:Integer b = 5; → 可以调用 b.toString() 或 b.compareTo() |
比较方式
基本类型 | 包装类型 |
---|---|
使用 == 比较值是否相等。 | 使用 == 比较引用地址,使用 .equals() 比较值是否相等。 |
示例:int a = 5, b = 5; → a == b 为 true | 示例:Integer a = new Integer(5); Integer b = new Integer(5); → a == b 为 false ,a.equals(b) 为 true |
性能
基本类型 | 包装类型 |
---|---|
效率更高(直接操作值,无需额外开销)。 | 效率较低(涉及堆内存分配和垃圾回收)。 |
示例:数值计算优先使用基本类型 | 示例:集合类(如 List )中必须使用包装类型 |
解释一下自动装箱和自动拆箱
自动装箱:
public class Test {public static void main(String[] args) {// 声明一个Integer对象,用到了自动的装箱:解析为:Integer num =Integer.valueOf(9);Integer num = 9;}}
9 是一个基本数据类型,原则上它是不可以被赋值给一个对象Integer的。有了自动装箱,就可以把基本数据类型直接转换为对象,这样就可以对对象进行操作。
自动拆箱:
public class Test {public static void main(String[] args) {/ /声明一个Integer对象Integer num = 9;// 进行计算时隐含的有自动拆箱System.out.print(num--);}}
把对象转换为一个基本数据类型,对象本身是不可以进行运算的,转换为基本数据类型之后,就可以进行运算了。
int 和 Integer 有什么区别
int 是基本数据类型, Integer 是它的包装类。int 不能为null,而Integer 可以;Integer 是一个对象,必须先实例化之后才能使用,而 int 不需要;int 是存在栈中的直接数据,Integer 是一个对象,会存在堆中,而我们只能拿到它的引用。
两个new生成的Integer变量对比
Integer i = new Integer(10000);
Integer j = new Integer(10000);
System.out.print(i == j); //false
Integer 是一个对象,new会在堆中开辟一个新的空间,而new两个对象,他们的内存地址肯定是不一样的。所有这两个对象不相等。
Integer 变量和 int 变量的对比
int a = 10000;
Integer b = new Integer(10000);
Integer c=10000;
System.out.println(a == b);//true
System.out.println(a == c); // true
在比较时,Integer 会自动拆箱,转换成int类型;所以就会变成基本数据类型之间的比较,所以它们的值相等。
非new生成的Integer变量和new的Integer变量的对比
Integer b = new Integer(10000);
Integer c=10000;
System.out.println(b == c); // false
new的Integer会在堆中开辟一个空间,而非new的Integer会在常量池里取出内存地址。new的Integer和非new的Integer它们的内存地址不同,所以不相等。
两个非new生成的Integer对象的对比
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false
两个非new的Integer对象在比较时,如果值在-128~127之间,结果为true,否则不相等。
Integer 会在值在-128~127之间进行自动拆箱,把值放入缓存中,如果再有相同的值,就会从缓存中取出。缓存是通过Integer的内部类IntegerCache来完成的。超过这个值就会new出来一个对象。给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf,源码如下:
public static Integer valueOf(String s, int radix) throws NumberFormatException
{return Integer.valueOf(parseInt(s,radix));
}/*** (1)在-128~127之内:静态常量池中cache数组是static final类型,cache数组对象会被存储于静态常量池中。* cache数组里面的元素却不是static final类型,而是cache[k] = new Integer(j++),* 那么这些元素是存储于堆中,只是cache数组对象存储的是指向了堆中的Integer对象(引用地址)** (2)在-128~127 之外:新建一个 Integer对象,并返回。*/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);
}
IntegerCache是Integer的内部类,源码如下:
/*** 缓存支持自动装箱的对象标识语义 -128和127(含)。* 缓存在第一次使用时初始化。 缓存的大小可以由-XX:AutoBoxCacheMax = <size>选项控制。* 在VM初始化期间,java.lang.Integer.IntegerCache.high属性可以设置并保存在私有系统属性中*/
private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++) {cache[k] = new Integer(j++); // 创建一个对象}}private IntegerCache() {}
}