标签:bin strong 修改 ring 定义 默认值 源码 顺序 实现
类的加载过程.png
加载
将 Class 文件以二进制的形式加载到内存中
验证
校验 Class 文件是否安全,是否被正确的修改等
准备
为类变量申请内存,设置默认值,(初始化变量的默认值,比如int初始化为0,reference初始化为null) 但是达到类的初始化之前都没有初始化为真正的值。
零值.png
解析
将符号引用转换为直接引用
初始化
搜集并执行static代码块,以及
使用
为新对象申请内存, 为示例变量初始化默认值,为实例对象正确的设置初值;生成
卸载
在运行的时候加上虚拟机参数
+XX:+TraceClassLoading
可以详细的看到类加载的信息,同样的要看类卸载的信息,可以使用-XX:TraceClassUnloading
静态变量
或者 静态方法
,并不会初始化父类。 通过子类引用父类的静态属性,表示对父类的主动使用,而非对子类的主动使用class SuperClass {
public static String msg = "Hello,World";
static {
System.out.println("SuperClass.static initializer");
}
}
class SubClass extends SuperClass {
public static String msg2 = "Hello,World";
static {
System.out.println("SubClass.static initializer");
}
}
// 验证通过子类引用父类的常量并不会初始化子类
System.out.println(SubClass.msg);
System.out.println(SubClass.msg2);
对于数组类型,其类型是JVM运行期间动态生成的,类型为[Lxxxx.xxxx.xxxx.xxxx.SubClasss; 其父类为Object,同理二维数组类型为[[Lxxx.xxx.xxx.SubClass; 其父类型为Object;
SubClass[] subClasses = new SubClass[1];
public class ReferenceExample002 {
public static void main(String[] args) {
// 实际运行的是 System.out.println(Hello, World);
// 对于只有运行期才能确定的值,仍然会初始化类
System.out.println(ExampleClass.msg);
}
}
class ExampleClass {
public static final String msg = "Hello, World";
static {
System.out.println("ExampleClass.static initializer");
}
}
public class ReferenceExample002 {
public ReferenceExample002() {
}
public static void main(String[] args) {
System.out.println("Hello, World");
}
}
反编译命令如: javap -c xxx.xxx.xxx
public class com.zhoutao.example.ReferenceExample002 {
public com.zhoutao.example.ReferenceExample002();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String Hello, World
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
package com.zhoutao.classload;
import java.util.UUID;
public class ReferenceExample003 {
public static void main(String[] args) {
System.out.println(ExampleClass.uuid);
}
static class ExampleClass {
// 此处引用的并非真正的常量值
public static final String uuid = UUID.randomUUID().toString();
static {
System.out.println("ExampleClass.static initializer");
}
}
}
ExampleClass 的静态代码块将会被执行: uuid 的值在编译器并不能确定,所以仍然会初始化对应的类,注意和编译期间确定的常量值进行区分。
? 当一个接口初始化时候,并不要求其父接口都完成初始化,然后类的初始化的时候要求父类完成初始化,而类的初始化的时候要求父类完成初始化
public class ReferenceExample005 {
public static void main(String[] args) {
System.out.println(SubInterface.b);
}
static interface ParentInterface {
public static int a = 1;
}
static interface SubInterface extends ParentInterface {
public static int b = 2;
}
}
JVM 中父接口并不会因为子接口或者其实现类的初始化而初始化,其仅仅在使用该接口的静态变量的时候才会进行初始化
Java 会为每个类生成
public class ReferenceExample006 {
public static void main(String[] args) {
ExampleClass exampleClass = ExampleClass.getInstance();
System.out.println("a = " + ExampleClass.a);
System.out.println("b = " + ExampleClass.b);
}
static class ExampleClass {
public static int a;
public static int b = 0;
private static ExampleClass exampleClass = new ExampleClass();
private ExampleClass() {
a++;
b++;
}
public static ExampleClass getInstance() {
return exampleClass;
}
}
}
对于上面的代码,可以很简单的知道,其输出值为:
a = 1
b = 1
如果将 ExampleClass 中的定义 b 放置于ExampleClass 的私有构造方法之后,那么其输出的值将为:
a = 1
b = 0
这是因为在public static int b = 0;
又重新的将 b 定义为1
本文由博客群发一文多发等运营工具平台 OpenWrite 发布
标签:bin strong 修改 ring 定义 默认值 源码 顺序 实现
原文地址:https://www.cnblogs.com/zhoutao825638/p/12388864.html