Practical test of JVM class loading process
-
-
-
- 1. Constant value test
- 2. Static variable value test
- 3. Create object test
- 4. Create object array data test
- 5. Create a basic type of array data test
- 6. Use the example of the singleton pattern to simulate the process of class loading
- 7. Initialize when testing interface inheritance
- 8. Initialize a test class inheritance
- 9. Initialize two when testing class inheritance
-
-
1. Constant value test
class ClassLoaderTest {
public static final String str = UUID.randomUUID().toString();
static {
System.out.println("ClassLoaderTest Block");
}
}
class ClassLoaderTest1 {
public static final String str = "I Am ClassLoaderTest1";
static {
System.out.println("ClassLoaderTest1 Block");
}
}
@Test
public void test() {
System.out.println(ClassLoaderTest.str);
System.out.println("-------------------------");
System.out.println(ClassLoaderTest1.str);
}
输出结果:
ClassLoaderTest Block
6799db17-6d67-4195-9b13-b2c4c082d86c
-------------------------
I Am ClassLoaderTest1
The conclusion is :
- The constant value will be stored in the constant pool of the called class, so the called class will not be used actively, so the called class will not be initialized. The
UUID.randomUUID().toString()
value of this statement is not fixed during compilation, so it will not be like the one mentioned before(public static final String str = "I Am ClassLoaderTest1";)
- The constant value will be stored in the constant pool of the calling class, so the called class will not be used actively, so the called class will not be initialized
2. Static variable value test
class ClassLoaderStatic {
public static int x = 3;
static {
System.out.println("FinalTest static block");
}
}
@Test
public void testStatic() {
System.out.println(ClassLoaderStatic.x);
}
输出结果:
FinalTest static block
3
The conclusion is:
- Accessing the static variables of a certain class or interface is equivalent to the active use of the class (explained in the previous article), so that the called class will be actively used, so the called class will be initialized and output
FinalTest static block
- Note that static variables are not the same as constants
3. Create object test
class ClassLoaderTest2 {
public static final String str = "I Am ClassLoaderTest2";
static {
System.out.println("ClassLoaderTest2 Block");
}
}
@Test
public void testCreateNewObject() {
ClassLoaderTest2 c = new ClassLoaderTest2();
System.out.println("------------------------------");
ClassLoaderTest2 c1 = new ClassLoaderTest2();
输出结果:
ClassLoaderTest2 Block
------------------------------
}
The conclusion is:
- A class will actively use the called class (ClassLoaderTest2) when new an object, and a class will only be initialized once when new an object
4. Create object array data test
class ClassLoaderTest2 {
public static final String str = "I Am ClassLoaderTest2";
static {
System.out.println("ClassLoaderTest2 Block");
}
}
@Test
public void testCreateObjectArray() {
ClassLoaderTest2[] cArray = new ClassLoaderTest2[1];
System.out.println(cArray.getClass());
System.out.println(cArray.getClass().getSuperclass());
System.out.println("------------------");
/** 二维数组*/
ClassLoaderTest2[][] c2Array = new ClassLoaderTest2[1][];
System.out.println(c2Array.getClass());
System.out.println(c2Array.getClass().getSuperclass());
输出结果:
class [LclassLoader.ClassLoaderTest2;
class java.lang.Object
------------------
class [[LclassLoader.ClassLoaderTest2;
class java.lang.Object
}
The conclusion is:
- The
ClassLoaderTest2 Block
word does not appear as expected , so all classes except the array class are created by the class loader. The data type is dynamically generated by the jvm runtime, and***[LclassLoader.ClassLoaderTest2t;
the words expressed as a two-digit array are [[ ** (Note: there is a semicolon after it). The dynamically generated type, the super type is.java.lang.Object
For arrays, JavaDoc often refers to the elements that make up the array as Component, which is actually the type after the array is reduced by one dimension
5. Create a basic type of array data test
@Test
public void testCreateBaseArray() {
int[] ints = new int[1];
System.out.println(ints.getClass());
System.out.println(ints.getClass().getSuperclass());
输出结果:
class [I
class java.lang.Object
}
in conclusion:
- The super type is
java.lang.Object
for arrays. JavaDoc often refers to the elements constituting the array as Component, which is actually the type after the array is reduced by one dimension
6. Use the example of the singleton pattern to simulate the process of class loading
class SingletonDemo1 {
public static int counter1;
public static int counter2 = 0;
private static SingletonDemo1 singleton = new SingletonDemo1();
private SingletonDemo1() {
counter1++;
counter2++;
}
public static SingletonDemo1 getInstance() {
return singleton;
}
}
@Test
public void testSingletonLoad() {
SingletonDemo1 singleton1 = SingletonDemo1.getInstance();
System.out.println("SingletonDemo1 counter1: " + singleton1.counter1);
System.out.println("SingletonDemo1 counter2: " + singleton1.counter2);
输出结果:
SingletonDemo1 counter1: 1
SingletonDemo1 counter2: 1
/* 流程分析:
* 加载:执行 SingletonDemo1.getInstance() 第一步进行 SingletonDemo1的类加载
* 连接:
* 1.验证:字节码文件的正确性
* 2.准备:将类的静态变量进行赋值(counter1,counter2 都进行空间分配再赋予初始的值 0 0)
* 3.解析:将符号引用变成直接引用
* 初始化:
* counter1++; 变成 1
* counter2++; 变成 1
*/
}
class SingletonDemo2 {
public static int counter1;
private static SingletonDemo2 singleton = new SingletonDemo2();
private SingletonDemo2() {
counter1++;
counter2++;
}
public static int counter2 = 0;
public static SingletonDemo2 getInstance() {
return singleton;
}
@Test
public void testSingletonLoad() {
SingletonDemo2 singleton2 = SingletonDemo2.getInstance();
System.out.println("SingletonDemo2 counter1: " + singleton2.counter1);
System.out.println("SingletonDemo2 counter2: " + singleton2.counter2);
输出结果:
SingletonDemo2 counter1: 1
SingletonDemo2 counter2: 0
/**
* 流程分析:
* 加载:执行 SingletonDemo1.getInstance() 第一步进行 SingletonDemo2
* 连接:
* 1.验证:字节码文件的正确性
* 2.准备:将类的静态变量进行赋值(counter1,counter2 都进行空间分配再赋予初始的值 0 0)
* 3.解析:将符号引用变成直接引用
* 初始化:
* counter1++; 变成 1
* counter2++; 变成 1
* 重点: public static int counter2 = 0;
* 再一次的将 counter2 进行 0 赋值所以 counter2 的值变成了 0
*/
}
7. Initialize when testing interface inheritance
interface ClassLoaderTest3 {
/**
* public static final 接口中定义的变量默认就是常量
*/
public static final String str = "i am interface parent";
}
interface ClassLoaderChild extends ClassLoaderTest3 {
public static final String str = "i am interface child";
}
/**
在运行之前将编译后的 ClassLoaderTest3.class 文件删除
*/
@Test
public void testInterface() {
System.out.println(ClassLoaderChild.str);
System.out.println("------------------");
System.out.println(ClassLoaderTest3.str);
输出结果:
i am interface child
------------------
Error:(95, 24) java: 找不到符号
符号: 变量 ClassLoaderTest3
位置: 类 classLoader.JuintTestTest
* 所以得出结论是:
* 只有在真正使用到父接口的时候(如引用接口中定义的常量时),才会初始化。注意如果是类与类继承的时候如果子类进行初始化的时候
* 父类必须进行初始化
*/
}
in conclusion:
- That is, the child interface has nothing to do with the parent interface, so it is concluded that the initialization of the child interface does not necessarily require the parent interface to complete the initialization.
- Only when the parent interface is actually used (such as when referencing a constant defined in the interface) will it be initialized.
- Note that if the class is inherited from the class, the parent class must be initialized when the subclass is initialized
8. Initialize a test class inheritance
class ClassLoaderStaticParent{
public static final int x = 1;
static {
System.out.println("i am ClassLoaderStaticParent");
}
}
class ClassLoaderStaticChild extends ClassLoaderStaticParent{
public static int x = 2;
static {
System.out.println("i am ClassLoaderStaticChild");
}
}
@Test
public void ClassLoaderStaticParentAndChild() {
ClassLoaderStaticParent parent;
System.out.println("-------------------");
parent = new ClassLoaderStaticParent();
System.out.println("------------------");
System.out.println(parent.x);
System.out.println("------------------");
System.out.println(ClassLoaderStaticChild.x);
输出结果:
-------------------
i am ClassLoaderStaticParent
------------------
1
------------------
i am ClassLoaderStaticChild
2
}
The conclusion is:
- When an object is new, the current class will be initialized, but the premise is that the current class has not been initialized (introduced in the previous chapter)
- Actively access the static variables of this class, and the called class will also be actively initialized (described above)
9. Initialize two when testing class inheritance
class ClassLoaderPorpertyAndMethodParent{
public static int a = 3;
static{
System.out.println("Parent static block");
}
static void doSomeThing(){
System.out.println("I am doSomeThing methed");
}
}
class ClassLoaderPorpertyAndMethodChild extends ClassLoaderPorpertyAndMethodParent{
static {
System.out.println("i am ClassLoaderPorpertyAndMethodChild block");
}
}
@Test
public void ClassLoaderPorpertyAndMethodParent() {
System.out.println(ClassLoaderPorpertyAndMethodChild.a);
System.out.println("-------------------------");
ClassLoaderPorpertyAndMethodChild.doSomeThing();
输出结果:
Parent static block
3
-------------------------
I am doSomeThing methed
}
The conclusion is:
-
Actively access the static variables of this class, and the called class will also be actively initialized (described above)
-
Calling the static method of the class is also an active use of the class, but the class has already been initialized once when the static variable is called, so the second time the class will not be initialized, it will not be output
Parent static block
At this point, everyone should understand the general process of class loading. If you have any questions, I hope to leave a message
Pay attention to me, I will continue to output... Looking forward to the next issue of JVM learning.
Encourage with you...