JVM学习之类的加载连接和初始化过程详解

闲言少叙,先说知识点

1.JAVA程序对类的使用方式可分为主动使用使用和被动使用两种

2.所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用”时才初始化他们

3.类的加载、连接和初始化中主动使用分为以下七种
    (1)、创建类的实例
    (2)、访问某个类或接口的静态变量,或者对该静态变量赋值
    (3)、调用类的静态方法。
    (4)、反射。
    (5)、初始化一个类的子类(算是对父类的主动使用)。
    (6)、Java虚拟机启动时被表明为启动类的类(Java Test)
    (7)、JDK1.7开始提供的动态语言支持(了解)。
4.除上面七种之外,都被视为类的被动使用,不会被初始化。

5.类的加载指的是将.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内然后在内存中创建一个java.lang.Class对象(规范未说明Class对象位于哪里,HotSpot虚拟机将其放在方法区中)用来封装类的方法区内的数据结构

6.加载.class文件的方式(一般从磁盘中),还可以从网上下载、从压缩包中、将Java源文件动态编译为.class文件等方式。

如果以上的内容你不理解,先忘掉它,咱们看两个例子

No1:

public class Main {
    public static  void main(String args[]){
        System.out.println(Parent.str);
    }
}
class Parent {
    public static String str = "Parent" ;
    static {
        System.out.println("这里是Parent");
    }
}
class Child extends Parent {
    public static  String str = "Child";
    static {
        System.out.println("这里是Child");
    }
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

你猜测以下会输出什么,结合上面提到的知识点。

好,接下来咱们看一下运行的结果

JVM学习之类的加载连接和初始化过程详解_第1张图片

哎?为什么Child中没有输出结果呢?难道Child没有被初始化。 

没错,咱们上面提到过只有主动使用的时候才会被初始化,观察上面七种主动使用

Main类运行作为启动类,里面的代码理应被初始化,符合条件6。

Main类中调用Parent的静态变量,Parent类理应被初始化,符合条件2,没毛病。

所以真的是Child类没有被初始化

No2:

public class Main {
    public static  void main(String args[]){
        System.out.println(Child.str);
    }
}
class Parent {
    public static String str = "Parent" ;
    static {
        System.out.println("这里是Parent");
    }
}
class Child extends Parent {
    public static  String str = "Child";
    static {
        System.out.println("这里是Child");
    }
}

与第一个例子相比,更改了Main类中输出的值

大家思考一下......

JVM学习之类的加载连接和初始化过程详解_第2张图片

很明显这次不光初始化了Child类,还初始化了parent类

根据上例的理解,Child类被初始化很正常,因为Main函数调用了Child的静态变量,但是Parent类为什么会被初始化呢?

这是因为条件5,初始化Child类时,一定会先初始化其父类,又因为Java类采用单继承模式,所以你可以简单的记做“当对一个

初始化时,要求其所有父类都已经初始化了。”

师从圣思源张龙,大家再见

你可能感兴趣的:(JVM成长之路)