《深入理解Java虚拟机》Java语法糖
1.自动拆装箱
如下的代码
public static void main(String[] args) {
ArrayList<Integer> its = new ArrayList<>();
its.add(0);
int result = its.get(0);
System.out.println("result = " + result);
}
对应的字节码
0 new #2 <java/util/ArrayList>
3 dup
4 invokespecial #3 <java/util/ArrayList.<init> : ()V>
7 astore_1
8 aload_1
9 iconst_0
10 invokestatic #4 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;>
13 invokevirtual #5 <java/util/ArrayList.add : (Ljava/lang/Object;)Z>
16 pop
17 aload_1
18 iconst_0
19 invokevirtual #6 <java/util/ArrayList.get : (I)Ljava/lang/Object;>
22 checkcast #7 <java/lang/Integer>
25 invokevirtual #8 <java/lang/Integer.intValue : ()I>
28 istore_2
29 getstatic #9 <java/lang/System.out : Ljava/io/PrintStream;>
32 new #10 <java/lang/StringBuilder>
35 dup
36 invokespecial #11 <java/lang/StringBuilder.<init> : ()V>
39 ldc #12 <result = >
41 invokevirtual #13 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
44 iload_2
45 invokevirtual #14 <java/lang/StringBuilder.append : (I)Ljava/lang/StringBuilder;>
48 invokevirtual #15 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
51 invokevirtual #16 <java/io/PrintStream.println : (Ljava/lang/String;)V>
54 return
可以看偏移量10 和 偏移量25的指令 ,通过调用对应包装类的ValueOf方法完成装箱,调用intValue方法完成拆箱
invokestatic #4 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;>
25 invokevirtual #8 <java/lang/Integer.intValue : ()I>
2. 泛型与类型擦除
0 new #2 <java/util/ArrayList>
3 dup
4 invokespecial #3 <java/util/ArrayList.<init> : ()V>
7 astore_1
8 aload_1
9 iconst_0
10 invokestatic #4 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;>
13 invokevirtual #5 <java/util/ArrayList.add : (Ljava/lang/Object;)Z>
16 pop
17 aload_1
18 iconst_0
19 invokevirtual #6 <java/util/ArrayList.get : (I)Ljava/lang/Object;>
22 checkcast #7 <java/lang/Integer>
25 invokevirtual #8 <java/lang/Integer.intValue : ()I>
28 istore_2
29 getstatic #9 <java/lang/System.out : Ljava/io/PrintStream;>
32 new #10 <java/lang/StringBuilder>
35 dup
36 invokespecial #11 <java/lang/StringBuilder.<init> : ()V>
39 ldc #12 <result = >
41 invokevirtual #13 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
44 iload_2
45 invokevirtual #14 <java/lang/StringBuilder.append : (I)Ljava/lang/StringBuilder;>
48 invokevirtual #15 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
51 invokevirtual #16 <java/io/PrintStream.println : (Ljava/lang/String;)V>
54 return
我们创建的集合指定的泛型为Integer,而查看字节码信息,发现却变成了Object
13 invokevirtual #5 <java/util/ArrayList.add : (Ljava/lang/Object;)Z>
19 invokevirtual #6 <java/util/ArrayList.get : (I)Ljava/lang/Object;>
这是因为对JVM来说,不存在泛型。Java编译器会将泛型转化为当前泛型所能指代的类中的最高父类。
如果有声明继承的类的泛型,将转换为声明父类的类型
public static void main(String[] args) {
ArrayList<Dog> its = new ArrayList<>();
Dog e = new Example().new Dog();
its.add(e);
}
class Dog {
}
0 new #2 <java/util/ArrayList>
3 dup
4 invokespecial #3 <java/util/ArrayList.<init> : ()V>
7 astore_1
8 new #4 <Example$Dog>
11 dup public static void main(String[] args) {
ArrayList<Dog> its = new ArrayList<>();
Dog e = new Example().new Dog();
its.add(e);
}
class Dog extends Animal{
}
12 new #5 <Example>
15 dup
16 invokespecial #6 <Example.<init> : ()V>
19 dup
20 invokevirtual #7 <java/lang/Object.getClass : ()Ljava/lang/Class;>
23 pop
24 invokespecial #8 <Example$Dog.<init> : (LExample;)V>
27 astore_2
28 aload_1
29 aload_2
30 invokevirtual #9 <java/util/ArrayList.add : (Ljava/lang/Object;)Z>
33 pop
34 return
public static void main(String[] args) {
ArrayList<Dog> its = new ArrayList<>();
Dog e = new Example().new Dog();
its.add(e);
}
class Dog extends Animal{
}
class Animal{
}
0 aload_0
1 aload_1
2 putfield #1 <Example$Dog.this$0 : LExample;>
5 aload_0
6 aload_1
7 invokespecial #2 <Example$Animal.<init> : (LExample;)V>
10 return