美文网首页
深入JVM内核8 类连接和初始化

深入JVM内核8 类连接和初始化

作者: 香沙小熊 | 来源:发表于2021-01-22 18:54 被阅读0次

    1.类连接

    1.1 类连接主要验证的内容
    • 类文件结构检查:按照JVM规范规定的类文件结构进行
    • 元数据验证:对字节码描述的信息进行语义分析,保证其符合Java语言规范要求
    • 字节码验证:通过对数据流和控制流进行分析,确保程序语义是合法和符合逻辑的。这里主要对方法进行校验
    • 符号引用验证:对类自身以外的信息,也就是常量池中的各种符号引用,进行匹配校验

    1.2 类连接中的解析

    所谓解析就是把常量池中的符号引用转换成直接引用的过程,包括:符号引用:以一组无歧义的符号来描述所引用的目标,与虚拟机的实现无关

    • 直接引用:直接指向目标的指针、相对偏移量、或是能间接定位到目标的句柄,是和虚拟机实现相关的。
    • 主要针对:类、接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符

    2.类的初始化

    类的初始化就是为类的静态变量赋初始值,或者说是执行类构造器<clinit>方法的过程

    1. 如果类还没有加载和连接,就先加载和连接
    2. 如果类存在父类,且父类没有初始化,就先初始化父类
    public class MyParent {
        static {
            System.out.println("my parent class init");
        }
    }
    
    public class MyChild extends MyParent {
        static {
            System.out.println("my child class init");
        }
    }
    
    public class Test {
    
        public static void main(String[] args) {
            MyChild myChild = new MyChild();
    
        }
    }
    
    my parent class init
    my child class init
    
    1. 如果类中存在初始化语句,就依次执行这些初始化语句
    public class MyChild extends MyParent {
    
    
        static {
            System.out.println("my child class init");
        }
    
        static {
            System.out.println("my child class block 1");
        }
        private static final int a = 5;
        static {
            System.out.println("my child class block 2 a="+a);
        }
    }
    
    my parent class init
    my child class init
    my child class block 1
    my child class block 2 a=5
    
    1. 如果是接口的话:
      • 初始化一个类的时候,并不会先初始化它实现的接口
      • 初始化一个接口时,并不会初始化它的父接口
      • 只有当程序首次使用接口里面的变量或者是调用接口方法的时候,才会导致接口初始化
    public interface Api {
        public static String str = "now in api";
    
        public void t1();
    }
    
    public class MyChild extends MyParent implements Api{
    
    
        static {
            System.out.println("my child class init");
        }
    
        static {
            System.out.println("my child class block 1");
        }
        private static final int a = 5;
        static {
            System.out.println("my child class block 2 a="+a);
        }
    
        @Override
        public void t1() {
    
            System.out.println("now in mychild t1");
        }
    }
    
    public class Test1 {
    
        public static void main(String[] args) {
            MyChild myChild = new MyChild();
    
            System.out.println("mychild.str=="+myChild.str);
        }
    }
    
    my parent class init
    my child class init
    my child class block 1
    my child class block 2 a=5
    mychild.str==now in api
    

    ZHI
    5.调用Classloader类的loadClass方法来转载一个类,并不会初始化这个类,不是对类的主动调用

        public static void main(String[] args) throws ClassNotFoundException {
            MyClassLoader  myClassLoader = new MyClassLoader("myClassloader1");
            Class cls1 = myClassLoader.loadClass("com.kpioneer.demo.jvm.classinit.MyChild");
            System.out.println("over=======");
        }
    
    over=======
    
    Classloader调用MyChild,里面的静态代码块,并没有被调用。
    2.1.类的初始化时机

    Java程序对类的使用方式分成:主动使用和被动使用,JVM必须在每个类或接口"首次主动使用"时才初始化它们;被动使用类不会导致类的初始化,主动使用的情况:
    1)创建类实例
    2)访问某个类或接口的静态变量
    3)调用类的静态方法

    public class MyChild extends MyParent implements Api {
    
    
        private static final int a = 5;
    
        static {
            System.out.println("my child class init");
        }
    
        static {
            System.out.println("my child class block 1");
        }
    
        static {
            System.out.println("my child class block 2 a=" + a);
        }
    
        public static void t2() {
            System.out.println("now in mychild t2");
        }
    
        @Override
        public void t1() {
    
            System.out.println("now in mychild t1");
        }
    }
    
        public static void main(String[] args) throws ClassNotFoundException {
    
            MyChild.t2();
    
        }
    
    my parent class init
    my child class init
    my child class block 1
    my child class block 2 a=5
    now in mychild t2
    

    4)反射某个类

        public static void main(String[] args) throws ClassNotFoundException {
    
            Class cls = Class.forName("com.kpioneer.demo.jvm.classinit.MyChild");
        }
    
    my parent class init
    my child class init
    my child class block 1
    my child class block 2 a=5
    

    5)初始化某个类的子类,而父类还没有初始化
    6)JVM启动的时候运行的主类

    public class Test {
    
        static {
            System.out.println("now Test class init");
        }
    
        public static void main(String[] args) throws ClassNotFoundException {
    
    
            Class cls = Class.forName("com.kpioneer.demo.jvm.classinit.MyChild");
        }
    }
    
    now Test class init
    my parent class init
    my child class init
    my child class block 1
    my child class block 2 a=5
    

    7)定义了default方法的接口,当接口实现类初始化时

        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            Api api = (Api)(Class.forName("com.kpioneer.demo.jvm.classinit.MyChild").newInstance());
            api.t3();
        }
    
    my parent class init
    my child class init
    my child class block 1
    my child class block 2 a=5
    now in api t3()
    

    3.类的卸载

    • 当代表一个类的Class对象不在引用,那么Class对象的生命周期就结束了,对应的在方法区中的数据也会被卸载
    • JVM自带的类加载器装载的类,是不是会卸载的,有用户自定义的类加载器加载的类是可以卸载的

    相关文章

      网友评论

          本文标题:深入JVM内核8 类连接和初始化

          本文链接:https://www.haomeiwen.com/subject/dzokzktx.html