1、编译期常量与运行期常量
引例:判断MyParent3会不会初始化?
import java.util.UUID;
public class MyTest3 {
public static void main(String[] args) {
System.out.println(MyParent3.str);
}
}
class MyParent3 {
public static final String str = UUID.randomUUID().toString();
static {
System.out.println("MyParent3 static code");
}
}
我的想法:
我的知识只能支撑我这样想:这个例子跟上节课的例子没有区别。静态常量会放在引用他的那个方法所在的类的常量池,所以Myparent3不会初始化。
实际输出:
MyParent3 static code
0e1b29c7-bd80-4b9c-ba7c-58c5de10cd9a
静态代码块执行了,脸又被打肿了。
分析:在本例中,str的值在编译期间是不知道的,只有运行的时候才知道(即str是运行期常量)。所以MyParents会初始化。这时候,如果把MYParent的class文件删除掉,则会抛出异常。
当一个常量的值并非编译期间可以确定的,那么其值就不会被放到调用类的常量池中,这时在程序运行时,会导致主动使用这个常量所在的类,显然会导致这个类被初始化。
2、创建实例引起的主动使用
引例1:判断MyParent4中的静态代码块会不会被执行?
public class MyTest4 {
public static void main(String[] args) {
MyParent4 myParent4 = new MyParent4();
}
}
class MyParent4 {
static {
System.out.println("MyParent4 static block");
}
}
我的想法:会被执行,因为这里创建了类的实例啊,肯定会被执行的。
实际结果:
MyParent4 static block
引例2: 了解首次主动调用
public class MyTest4 {
public static void main(String[] args) {
MyParent4 myParent4 = new MyParent4();
System.out.println("---");
MyParent4 myParent5 = new MyParent4();
}
}
class MyParent4 {
static {
System.out.println("MyParent4 static block");
}
}
实际结果:
MyParent4 static block
---
对比引例1,说明只有在首次主动调用的时候才会初始化。
3、数组
引例:判断静态代码块会不会执行?
public class MyTest4 {
public static void main(String[] args) {
MyParent4[] myParent4s = new MyParent4[1];
}
}
class MyParent4 {
static {
System.out.println("MyParent4 static block");
}
}
我的想法:
不知道,没想法。
实际结果:无输出。
分析:说明数组那行代码不代表对类的主动使用。
疑问:new数组的那行代码应该是创建实例了,但是静态代码块没执行,说明肯定MyParent4的实例没创建,那new的是啥玩意?
在数组初始化代码下面加上如下代码:
System.out.println(myParent4s.getClass());
输出如下:
class [Lcom.jvm.classloader.MyParent4;
说明是[Lcom.jvm.classloader.MyParent4
类,但是这个类我没创建过。这个类型是java虚拟机在运行期帮我们创建出来的。
引申:二维数组呢?
public class MyTest4 {
public static void main(String[] args) {
MyParent4[] myParent4s = new MyParent4[1];
System.out.println(myParent4s.getClass());
System.out.println(myParent4s.getClass().getSuperclass());
MyParent4[][] myParent4s1 = new MyParent4[1][1];
System.out.println(myParent4s1.getClass());
System.out.println(myParent4s1.getClass().getSuperclass());
System.out.println("======");
int[] ints = new int[1];
System.out.println(ints.getClass());
System.out.println(ints.getClass().getSuperclass());
char[] chars = new char[1];
System.out.println(chars.getClass());
System.out.println(chars.getClass().getSuperclass());
boolean[] booleans = new boolean[1];
System.out.println(booleans.getClass());
System.out.println(booleans.getClass().getSuperclass());
short[] shorts = new short[1];
System.out.println(shorts.getClass());
System.out.println(shorts.getClass().getSuperclass());
byte[] bytes = new byte[1];
System.out.println(bytes.getClass());
System.out.println(bytes.getClass().getSuperclass());
}
}
class MyParent4 {
static {
System.out.println("MyParent4 static block");
}
}
运行结果:
class [Lcom.jvm.classloader.MyParent4;
class java.lang.Object
class [[Lcom.jvm.classloader.MyParent4;
class java.lang.Object
======
class [I
class java.lang.Object
class [C
class java.lang.Object
class [Z
class java.lang.Object
class [S
class java.lang.Object
class [B
分析:静态代码块依旧没有执行,类型变了。
结论:对于数组实例来说,其类型是由JVM在运行期动态生成的,表示为[Lcom.jvm.classloader.MyParent4
这种形式。动态生成的类型,其父类型就是Object。
对于数组来说,JavaDoc经常将构成数组的元素为Component,实际上就是将数组降低一个维度后的类型。
4、数组类型解密
反编译MyTest4:javap -c target/classes/com/jvm/classloader/MyTest4.class
结果如下:
public class com.jvm.classloader.MyTest4 {
public com.jvm.classloader.MyTest4();
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: anewarray #2 // class com/jvm/classloader/MyParent4
4: astore_1
5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
8: aload_1
9: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
12: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
15: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
18: aload_1
19: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
22: invokevirtual #6 // Method java/lang/Class.getSuperclass:()Ljava/lang/Class;
25: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
28: iconst_1
29: iconst_1
30: multianewarray #7, 2 // class "[[Lcom/jvm/classloader/MyParent4;"
34: astore_2
35: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
38: aload_2
39: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
42: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
45: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
48: aload_2
49: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
52: invokevirtual #6 // Method java/lang/Class.getSuperclass:()Ljava/lang/Class;
55: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
58: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
61: ldc #8 // String ======
63: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
66: iconst_1
67: newarray int
69: astore_3
70: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
73: aload_3
74: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
77: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
80: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
83: aload_3
84: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
87: invokevirtual #6 // Method java/lang/Class.getSuperclass:()Ljava/lang/Class;
90: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
93: iconst_1
94: newarray char
96: astore 4
98: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
101: aload 4
103: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
106: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
109: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
112: aload 4
114: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
117: invokevirtual #6 // Method java/lang/Class.getSuperclass:()Ljava/lang/Class;
120: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
123: iconst_1
124: newarray boolean
126: astore 5
128: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
131: aload 5
133: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
136: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
139: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
142: aload 5
144: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
147: invokevirtual #6 // Method java/lang/Class.getSuperclass:()Ljava/lang/Class;
150: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
153: iconst_1
154: newarray short
156: astore 6
158: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
161: aload 6
163: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
166: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
169: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
172: aload 6
174: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
177: invokevirtual #6 // Method java/lang/Class.getSuperclass:()Ljava/lang/Class;
180: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
183: iconst_1
184: newarray byte
186: astore 7
188: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
191: aload 7
193: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
196: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
199: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
202: aload 7
204: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
207: invokevirtual #6 // Method java/lang/Class.getSuperclass:()Ljava/lang/Class;
210: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
213: return
}
分析:
1、iconst_1表示的是数组长度的那个1
2、anewarray 表示的新的这个数组
3、newarray表示创建一个指定的原始类型(int,float,char等)的数组,并将其引用值压入栈顶
助记符:
1、anewarray :表示创建一个引用类型的(类、接口、数组)的数组,并将其引用值压入栈顶。
2、newarray:表示创建一个指定的原始类型(int,float,char等)的数组,并将其引用值压入栈顶