java语法糖--自动装箱拆箱与遍历循环

参考来源:《深入理解Java虚拟机》 周志明 著

上一章:java语法糖–泛型和类型擦除

自动装箱拆箱和遍历循环也是我们在java里面使用的最多的。
让我们先从例子出发吧


public class Test {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5);

        int sum = 0;

        for (int i:list){
            sum+=i;
        }
        System.out.println(sum);
    }
}

看一下javap -c解析出来的结果,如果你和我一样不熟悉java字节码字节码指令,没事,看注释就好,这里我联合idea它本身的反编译插件反编译出来的结果以及书中的编译结果来作对比分析(笔者懒得去找一款真正算得上标准的反编译器了)
在这里插入图片描述
书中反编译结果

public static void main(String[] args){
	List list=Arrrays.asList(new Integer[]{
		Integer.valueOf(1),
		Integer.valueOf(2),
		Integer.valueOf(3),
		Integer.valueOf(4),
		Integer.valueOf(5)
	});
	int sum = 0;
	for(Iterator localItrerator=list.iterator();localIterator.haoNext();){
		int i = ((Integer)localIterator.next()).intValue();
		sum+=i;
	}
	System.out.println(sum);	
}

这段代码的反编译结果中涉及到了泛型、自动装箱、自动拆箱、遍历循环、以及变长参数。泛型的类型擦除我在这里就不去详细描述了,那么我在这里简单的说一下自动装箱和自动拆箱:
自动装箱:
从上面的代码里面我们可以看到,装箱无非就是把一个基本的数据类型包装成一个对象(基本数据类型 如 byte,short,char,int,long,float,double等对应的包装类Byte,Short,Character,Integer,Long,Float,Double),这样就能在使用对象的地方使用它们,这个过程不是我们认为的操作,而是底层操作,如本例中调用Integer.valueOf方法,故称为 自动装箱。
自动拆箱:
既然有装箱,那就会有拆箱,拆箱的操作与装箱是相反的,也就是需要用到基本数据类型的操作时,相对于的包装类对象就会拆箱,也就是褪去自己对象的属性,变成一个基本数据类型,这也是底层操作,如本例中自己调用Integer.intValue方法,故称为自动拆箱
那么也许我们都会思考,它们会在什么时候发生呢?
一般会发生在:需要参数为对象的方法,你传了一个基本的数据类型,那么底层将会帮你自动装箱,或需要参数为基本数据类型,你传了一个是某个基本的数据类型的包装类对象,那么它也会发生自动拆箱操作。
关于变长参数和遍历循环:
变长参数的实现是通过传递数组对象来实现的,如例子中的Integer[]
遍历循环就是转换成迭代器的实现,所以一般要使用就必须实现Iterable接口。

上面的几个知识都是相对简单的,很容易就能够理解它的意思,感觉是没有任何我们值得注意的地方
不过,这里有个坑

 public static void main(String[] args) {
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;  
        System.out.println(c == d);
        System.out.println(e == f);
        System.out.println(c == (a + b));
        System.out.println(c.equals(a + b));
        System.out.println(g == (a + b));
        System.out.println(g.equals(a + b));
    }

结果是这样的

true
false
true
true
true
false

首先看第一对
true false
显然表示的是一个指向的对象是同一个,一个是不同的对象,这是为什么呢?
看一下自动装箱的valueOf的源码:
在这里插入图片描述
那么这里的low和high分别是多少呢?
在这里插入图片描述
就是-128,127,在这个范围内是指向IntegerCache中已经存在对象的引用,而超过就是会new一个Integer,故才会有上面的结果

后面的几个我就一并说吧
注意点:包装类的“==”运算在不遇到算术运算的情况下不会自动拆箱(言外之意就是只有在遇到算术运算的情况才会拆箱),以及它们的equals方法并不处理数据转型的问题
也就是说,“==”如果不拆箱,那么比较的是是否是同一对象,拆箱之后比较的就是值了,理解这里就好办了。
我们可以看一下equals的源码:

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

故在euals会先里面的算术运算先开始拆箱,运算完后传参又自动装箱,又因为里面会比较对象,故第一个equals返回的是true(c是Integer,a+b装箱之后也是Integer)
第二个equals返回的则是false(g是Long)
所以,你懂了吗?
后面给你们抛个反编译的字节码执行指令吧

Compiled from "Test.java"
public class kexie.test.Test {
  public kexie.test.Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1
       1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       4: astore_1
       5: iconst_2
       6: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       9: astore_2
      10: iconst_3
      11: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      14: astore_3
      15: iconst_3
      16: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      19: astore        4
      21: sipush        321
      24: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      27: astore        5
      29: sipush        321
      32: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      35: astore        6
      37: ldc2_w        #3                  // long 3l
      40: invokestatic  #5                  // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
      43: astore        7
      45: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      48: aload_3
      49: aload         4
      51: if_acmpne     58
      54: iconst_1
      55: goto          59
      58: iconst_0
      59: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
      62: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      65: aload         5
      67: aload         6
      69: if_acmpne     76
      72: iconst_1
      73: goto          77
      76: iconst_0
      77: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
      80: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      83: aload_3
      84: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
      87: aload_1
      88: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
      91: aload_2
      92: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
      95: iadd
      96: if_icmpne     103
      99: iconst_1
     100: goto          104
     103: iconst_0
     104: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
     107: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
     110: aload_3
     111: aload_1
     112: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     115: aload_2
     116: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     119: iadd
     120: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     123: invokevirtual #9                  // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z
     126: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
     129: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
     132: aload         7
     134: invokevirtual #10                 // Method java/lang/Long.longValue:()J
     137: aload_1
     138: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     141: aload_2
     142: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     145: iadd
     146: i2l
     147: lcmp
     148: ifne          155
     151: iconst_1
     152: goto          156
     155: iconst_0
     156: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
     159: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
     162: aload         7
     164: aload_1
     165: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     168: aload_2
     169: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     172: iadd
     173: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     176: invokevirtual #11                 // Method java/lang/Long.equals:(Ljava/lang/Object;)Z
     179: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
     182: return
}
发布了19 篇原创文章 · 获赞 3 · 访问量 3819

猜你喜欢

转载自blog.csdn.net/weixin_42792088/article/details/100170401
今日推荐