Java自动拆装箱问题整理

一、概念

java基础数据类型有:byte,char,short,int,long,float,double,boolean
其对应的包装类型有:Byte,Character,Short,Integer,Long,Float,Double,Boolean
自动装箱:基本类型转换为包装类型。
自动装箱的作用:可以将基本数据类型按照对象来使用,以调用其方法。
自动拆箱:包装类型转换为基本类型。
自动拆箱的作用:可以使对象变成基本数据类型进行加减乘除。

举例:

//在jdk1.5之前定义一个Integer对象:
   Integer a=new Integer(10);
//从jdk1.5开始定义一个Integer对象,即自动装箱;
   Integer b=10;
//自动拆箱;
   int c=b;

享元模式:在自动装箱时对于值从–128到127之间的值,它们被装箱为Integer对象后,会存在内存中被重用,始终只存在一个对象,而如果超过了从–128到127之间的值,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个 Integer对象(Byte、Short、Integer、Long适用,Float、Double不适用)。
如源码所示:

/** 
     * Returns a Integer instance representing the specified 
     * int value. 
     * If a new Integer instance is not required, this method 
     * should generally be used in preference to the constructor 
     * {@link #Integer(int)}, as this method is likely to yield 
     * significantly better space and time performance by caching 
     * frequently requested values. 
     * 
     * @param  i an int value. 
     * @return a Integer instance representing i. 
     * @since  1.5 
     */  
    public static Integer valueOf(int i) {
       
        if(i >= -128 && i <= IntegerCache.high)  
            return IntegerCache.cache[i + 128];  
        else  
            return new Integer(i);  
    }  

二、在基本数据类型中的举例运用(Integer,Long)

1.基础

  • Integer是int的包装类,int则是java的一种基本数据类型
  • Integer变量必须实例化后才能使用,int则不需要。
  • Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值。
  • .Integer的默认值为null,int的默认值是0。
  • int等基本类型的变量存储在栈中。Integer等包装类型存储在堆中。

2.实例

int a=1;
Integer b=1;
Integer b1=1;
Integer c=2;
Integer e=300;
Integer f=300;
Long g=3L;
Long h=2L;
Integer i = new Integer(1);
Integer j = new Integer(1);
  1. int和int比较:int直接存储的数据值,因此直接比较值即可。
  2. Integer和Integer的比较
    1)由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。
     Integer i = new Integer(1);
     Integer j = new Integer(1);
     System.out.print(i == j); //false
    
    2)非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)
    //Integer和New Integer()比较值:
     Integer a=300;
     Integer b = new Integer(300);
     System.out.print(a == b); //false
    
    3)对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false。
       //Integer和Integer的值在区间-128到127之间比较值:
       Integer a=1;
       Integer b=1;
       Integer c=2;
       Integer d=3;
       System.out.print(a == b); //true
       System.out.print(d == (b+c)); //true
       System.out.print(d.equals(b+c)); //bcd全部是是Integer,所以b+c的结果是Integer对象,自然返回Ture;
       //nteger和Integer的值不在区间-128到127之间比较值:
       Integer e=300;
       Integer f=300;
       System.out.print(e == f); //false
    

3) int和Integer的比较:Integer变量和int变量比较时,只要两个变量的值是向等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)

int a=1;
Integer b=1;
Integer c = new Integer(1);
//int和Integer比较值:
System.out.print(a == b); //true
//int和New Integer()比较值:
System.out.print(a ==c); //true
//

3、Integer 和 Long

这是Integer和Long的equals方法的源码:

public boolean equals(Object obj) {
     
if (obj instanceof Integer) {
     
return value == ((Integer)obj).intValue();
}
return false;
}
public boolean equals(Object obj) {
     
if (obj instanceof Long) {
     
return value == ((Long)obj).longValue();
}
return false;
}

下面来看例子:

Integer a = 1;
Integer b = 2;
Long c = 3L;
Long d = 2L;
// “==”比较的并不是内容,而是其内存地址,即引用对象是否是同一个;a,b均来源与缓存区,自然地址一样(不是数字一样);
System.out.print(c == (a+b)); //true
//计算a+b的结果是Integer,所以为直接返回False
System.out.print(c.equals(a+b)); //false 
//计算a+d的过程中发生了类型提升,结果为Long,所以就调用了longValue(),自然为True;
System.out.print(c.equals(a+d)); //true

4、String类中的自动拆装箱

String str = "sl";
//代替下面的声明方式
String str = new String("sl");

问题String s = new String(“hello”)String s = “hello”; 的区别?

String的值都在方法区的常量池中,前者要在堆中创建s对象和常量池中创建hello对象。后者只需要在常量池中创建hello对象;前者会创建2个对象,后者创建1个对象
看一下程序的结果:

public class St {
     
    public static void main(String[] args) {
     
        String s1 = "hello";
        String s2 = "world";
        String s3 = "helloworld";
        String s4 = "hello";
        String s5 = new String("world");
        System.out.println(s3 == s1 + s2);// false 地址不一样
        System.out.println(s3.equals((s1 + s2)));// true 值相等
        System.out.println(s3 == "hello" + "world");// true  常量池中有
        System.out.println(s3.equals("hello" + "world"));// true  值相等
        System.out.println(s4 ==s1);// true 常量池中有
        System.out.println(s5 == s2);//false 地址不一样
    }

字符串如果是变量相加,先开辟空间,再拼接。字符串如果是常量相加,是先拼接,然后再常量池找,如果有就直接返回,否则,就创建。

参考:
https://blog.csdn.net/wangxundeng/article/details/52091378
https://blog.csdn.net/qq_39949109/article/details/80207492

你可能感兴趣的:(Java基础)