自动装箱和自动拆箱

什么是自动拆装箱

自动装箱:Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,

自动拆箱:反之将Integer对象转换成int类型值,这个过程叫做拆箱。

简单来说,装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱.

//自动装箱
Integer total = 99; 
//自定拆箱
int totalprim = total;

自动拆箱和装箱是从JDK5.0才开始有的,它方便了基本数据类型和其对应的包装类型之间的转换。

 java中有8中基本的数据类型,这八种基本的数据类型都有对应的封装类型,

下面是对应关系:

 


 

进行自动拆装箱的时候,是有一个范围的,一旦超出这个范围,那么指向的就不是同一个对象,而是返回一个新创建的对象了,这个范围在Integer类中的一个内部私有类IntegerCache可以体现出来 。

注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。
Double、Float的valueOf方法的实现是类似的。

integer源码:

public static Integer valueOf(int i) {
  return  i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
 }

上面我们看到在Integer的构造函数中,它分两种情况: 

1、i >= 128 || i < -128 =====> new Integer(i) 
2、i < 128 && i >= -128 =====> SMALL_VALUES[i + 128]

private static final Integer[] SMALL_VALUES = new Integer[256];

 SMALL_VALUES本来已经被创建好,也就是说在i >= 128 || i < -128是会创建不同的对象,在i < 128 && i >= -128(即-128-127)会根据i的值返回已经创建好的指定的对象。

public class Main {
    public static void main(String[] args) {

        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;

        System.out.println(i1==i2);  //true
        System.out.println(i3==i4);  //false
    }
}

i1和i2会进行自动装箱,执行了valueOf函数,它们的值在(-128,128]这个范围内,它们会拿到SMALL_VALUES数组里面的同一个对象SMALL_VALUES[228],它们引用到了同一个Integer对象,所以它们肯定是相等的。

i3和i4也会进行自动装箱,执行了valueOf函数,它们的值大于128,所以会执行new Integer(200),也就是说它们会分别创建两个不同的对象,所以它们肯定不等。

 

public class Main {
    public static void main(String[] args) {

        Double i1 = 100.0;
        Double i2 = 100.0;
        Double i3 = 200.0;
        Double i4 = 200.0;

        System.out.println(i1==i2); //false
        System.out.println(i3==i4); //false
    }
}
 public static Double valueOf(double d) {
     return new Double(d);
 }

看看上面的执行结果,跟Integer不一样,这样也不必奇怪,因为它们的valueOf实现不一样,结果肯定不一样,那为什么它们不统一一下呢? 
这个很好理解,因为对于Integer,在(-128,128]之间只有固定的256个值,所以为了避免多次创建对象,我们事先就创建好一个大小为256的Integer数组SMALL_VALUES,所以如果值在这个范围内,就可以直接返回我们事先创建好的对象就可以了。

但是对于Double类型来说,我们就不能这样做,因为它在这个范围内个数是无限的。 
总结一句就是:在某个范围内的整型数值的个数是有限的,而浮点数却不是。

所以在Double里面的做法很直接,就是直接创建一个对象,所以每次创建的对象都不一样。

 

总结:这些进行自动拆装箱的基本类型的范围如下:

1. boolean类型的值

2.所有的byte的值

3.在-128~127的short类型的值

4.在-128~127的int类型的值

5.在\ u0000~\ u00ff 之间的char类型的值

而其中double和float又有所不同

即 Java对部分经常使用的数据采用缓存技术,即第一次使用该数据则创建该数据对象并对其进行缓存,当再次使用等值对象时直接从缓存中获取,从而提高了程序执行性能。

Java中的==有两种作用:如果是基本数据类型则用于判断其值是否相等;如果为引用类型则用于判断两者的地址是否相同。此处均为引用类型,所以在缓存中的会引用的是同一块地址,所以使用==判断时其结果为true。不在缓存范围的为false。

而下面代码为创建新的对象,不储存在缓存中:

boolean flag = new Integer(100)==new Integer(100);
System.out.println(flag); //false

总体来说,基本类型的包装类类似于String类。

而下面代码:

int x=1000;
Integer y=new Integer(1000);
boolean flag = x==y;
System.out.println(flag); //true

基本数据类型和其封装型进行“==”运算符的比较基本型封装型将会自动拆箱变为基本型后再进行比较,因此Integer y会自动拆箱为int类型再进行比较,显然返回true

java为什么要引入自动装箱和拆箱的功能?

举个例子:主要是用于java集合中,List<Inteter> list=new ArrayList<Integer>();

list集合如果要放整数的话,只能放对象,不能放基本类型,

因此需要将整数自动装箱成对象,基本数据类型。

如int,float,double,boolean,char,byte,不具备对象的特征,不能调用方法。

注意点(弊端):

容易生成无用对象,因为自动装箱会隐式地创建对象,像前面提到的那样,如果在一个循环体中,会创建无用的中间对象,这样会增加GC压力,拉低程序的性能。所以在写循环时一定要注意代码,避免引入不必要的自动装箱操作.

 

<think>好的,我现在要解释自动装箱自动拆箱的概念。首先,我需要确认用户对这些术语的了解程度。可能他们听说过Java的自动型转换,但不太清楚具体细节。自动装箱拆箱是Java中的特性,所以需要结合Java的基本数据包装来讲解。 用户之前问过面向对象面向过程的区别,所以可能有一定的编程基础,但可能需要用更易懂的例子来说明。首先,我需要明确自动装箱(Autoboxing)自动拆箱(Unboxing)的定义。自动装箱是将基本数据自动转换为对应的包装对象,而自动拆箱则是相反的过程,将包装对象自动转换为基本数据型。 接下来,我应该举一些例子,比如将int转换为Integer,或者将Integer转换为int。比如,当把一个int值赋给Integer对象时,Java会自动进行装箱操作,反之亦然。这样用户可以通过代码示例更直观地理解。 同时,需要提到Java引入这些特性的目的,主要是为了简化代码,让开发者在基本包装之间转换时不需要手动调用方法,比如Integer.valueOf()或者intValue()。这样可以减少代码的冗余,提高可读性。 另外,需要注意自动装箱拆箱可能带来的性能问题。虽然它们方便,但在大量循环或高频操作中,频繁的装箱拆箱可能会影响性能,因为涉及到对象的创建销毁。这时候可能需要提醒用户注意使用场景,避免不必要的性能损耗。 可能用户还会想知道这些特性在哪些Java版本中引入的,我记得是从Java 5(JDK 1.5)开始支持的。这一点也需要提到,以增加回答的准确性。 然后,我需要考虑用户可能的疑问,比如为什么要有包装?这时候可以解释基本数据型无法用于泛型,比如集合如ArrayList只能存储对象,所以需要包装。而自动装箱拆箱让这种转换变得无缝,方便使用。 另外,可能存在的陷阱,比如自动拆箱时的空指针异常。例如,如果一个Integer对象为null,尝试拆箱为int时会抛出NullPointerException。这也是需要注意的地方,应该在回答中提醒用户。 最后,总结一下自动装箱拆箱的优缺点,以及适用场景,帮助用户全面理解。确保语言简洁明了,避免使用过多技术术语,让不同层次的读者都能理解。</think>以下通过「快递打包」的比喻解释自动装箱自动拆箱: $$ \begin{cases} \text{自动装箱} = \text{把商品装进快递盒} \\ \text{自动拆箱} = \text{拆快递取出商品} \end{cases} $$ **一、基础概念** 1. **基本数据型**:直接存储值的简单型 (如:`int`、`double`、`boolean`) 2. **包装**:包裹基本数据型的对象 (如:`Integer`、`Double`、`Boolean`) **二、核心机制演示** ```java // 自动装箱(JDK1.5+自动完成) Integer boxed = 42; // 相当于 Integer.valueOf(42) // 自动拆箱 int unboxed = boxed; // 相当于 boxed.intValue() ``` **三、底层实现原理** 1. **装箱过程** $$ \text{int} \xrightarrow{\text{valueOf()}} \text{Integer} $$ - 触发场景:将基本型赋值给包装 - 实际调用`Integer.valueOf()`方法 2. **拆箱过程** $$ \text{Integer} \xrightarrow{\text{xxxValue()}} \text{int} $$ - 触发场景:将包装赋值给基本型 - 实际调用`intValue()`方法 **四、典型应用场景** 1. **集合存储** ```java List<Integer> numbers = new ArrayList<>(); numbers.add(100); // 自动装箱 int first = numbers.get(0); // 自动拆箱 ``` 2. **泛型参数传递** ```java public static <T> void process(T param) {} process(3.14); // 自动装箱为Double ``` **五、注意事项** 1. **缓存机制** ```java Integer a = 127; Integer b = 127; System.out.println(a == b); // true(使用缓存对象) Integer c = 128; Integer d = 128; System.out.println(c == d); // false(新建对象) ``` 2. **性能损耗** ```java // 循环中频繁装箱拆箱(不推荐) Long sum = 0L; for(int i=0; i<100000; i++){ sum += i; // 每次循环发生自动装箱 } ``` 3. **空指针风险** ```java Integer num = null; int value = num; // 运行时抛出NullPointerException ``` **六、不同型对照表** | 基本型 | 包装 | 装箱方法 | 拆箱方法 | |----------|-------------|-------------------|----------------| | byte | Byte | Byte.valueOf() | byteValue() | | short | Short | Short.valueOf() | shortValue() | | int | Integer | Integer.valueOf() | intValue() | | long | Long | Long.valueOf() | longValue() | | float | Float | Float.valueOf() | floatValue() | | double | Double | Double.valueOf() | doubleValue() | | char | Character | Character.valueOf() | charValue() | | boolean | Boolean | Boolean.valueOf() | booleanValue() | **七、特殊场景处理** 1. **三目运算符陷阱** ```java Integer result = condition ? 100 : null; // 当condition为false时,自动拆箱导致NPE ``` 2. **方法重载优先级** ```java void test(int x) { System.out.println("基本型"); } void test(Integer x) { System.out.println("包装"); } test(10); // 输出"基本型"(优先选择基本型重载) ``` 理解自动装箱/拆箱就像掌握快递打包技巧:合理使用能提升效率,但要注意包装成本(性能)空包裹风险(NPE)。在开发中应根据场景选择直接操作基本型还是使用包装
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值