zoukankan      html  css  js  c++  java
  • jvm学习:类的加载、连接、初始化、常量

    类在jvm中有这几个过程类的加载、连接、初始化、使用、卸载

    类的加载

    类的加载是将class文件中的二进制数据加载到内存中,将其放在运行时的数据区:方法区内,然后在内存中创建一个
    java.lang.Class对象用来封装类在方法区内的数据结构。规范没有规定Class对象放在哪里,hotspot虚拟机将其放在了方法区中。
    加载.class文件的方式
    从本地系统中加载
    从网络下载.class文件
    从zip jar文件中加载
    将java原文件动态的编译为.class文件,比如jsp

    类的使用

    java的类主动使用,才会执行初始化
    主动使用
    创建类的实例
    访问某个类或者接口的非final变量、对改静态变量的赋值
    调用类的静态方法
    反射
    初始化一个类的子类
    表明为启动类比如main方法
    java1.7动态语言支持

    例子

    运行下面的例子可以先打印str1,然后打印str2。

    package com.javalearn.jvm.classloader;
    
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * 对于静态字段来说,只有直接使用定义了该字段的类才会被初始化
     * 当一个类加载要求父类加载完毕
     */
    @Slf4j
    public class MyTest {
    
        public static void main(String[] args) {
            log.info(MyChild1.str2);
        }
    }
    
    @Slf4j
    class MyParent1 {
        public static String str1 = "hello";
    
        static {
            log.info("my parent static block");
        }
    }
    
    @Slf4j
    class MyChild1 extends MyParent1 {
        public static String str2 ="hello child2";
        static {
            log.info("my child1 static block");
        }
    }
    

    结果

    22:47:54.901 [main] INFO com.javalearn.jvm.classloader.MyParent1 - my parent static block
    22:47:54.905 [main] INFO com.javalearn.jvm.classloader.MyChild1 - my child1 static block
    22:47:54.905 [main] INFO com.javalearn.jvm.classloader.MyTest - hello child2
    
    

    使用反射是主动使用,会初始化类,但ClassLoader不是主动使用

    package com.learn.java.javabase.jvm.classloader;
    
    public class ClassLoaderTest012 {
        public static void main(String[] args) {
            ClassLoader classLoader=ClassLoader.getSystemClassLoader();
            Class<?>  c1;
            try {
                c1 = classLoader.loadClass("com.learn.java.javabase.jvm.classloader.Test012");
                System.out.println(c1);
                System.out.println("--------");
                c1=Class.forName("com.learn.java.javabase.jvm.classloader.Test012");
                System.out.println(c1);
                System.out.println("--------");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            System.out.println("--------");
    
    
        }
    }
    class Test012{
        static {
            System.out.println("test012");
        }
    }
    
    

    运行结果

    class com.learn.java.javabase.jvm.classloader.Test012
    --------
    test012
    class com.learn.java.javabase.jvm.classloader.Test012
    --------
    --------
    

    初始化

    类初始化的时候,会首先初始化它的父类,比如Object类
    接口初始化的时候,不会初始化它的父接口
    初始化是按照上下文的顺序初始化

    package com.learn.java.javabase.jvm.classloader;
    
    import java.util.Random;
    
    public class ClassLoaderInterfaceTest {
        public static void main(String[] args) {
    //        Paraent01 paraent01 =new Paraent01();
    //        Paraent01 paraent02 =new Paraent01();
               // Child01 child01 =new Child01();
            //System.out.println(Paraent01.paraent01);
            System.out.println(Child01.childInt);
        }
    }
    
    class Paraent01 {
        //常量会在编译期间放到调用类的常量池中
        public static final int  paraent01=10;
        //public static  int  paraent01=10;
        //静态代码块随着类的加载只会执行一次
    
        static {
            System.out.println("paraent01");
        }
    }
    
    class Child01 extends Paraent01 {
        public static int childInt =5;
        static {
            System.out.println("child01");
        }
    }
    
    
    

    结果

    paraent01
    child01
    5
    

    常量

    常量会在编译期加载使用类的常量池中
    下面的例子Child01的常量在test类使用的时候,已经放入到常量池。说明
    final变量的调用不是主动使用,并不会导致父类的初始化

    package com.learn.java.javabase.jvm.classloader;
    
    import java.util.Random;
    
    public class ClassLoaderInterfaceTest {
        public static void main(String[] args) {
    //        Paraent01 paraent01 =new Paraent01();
    //        Paraent01 paraent02 =new Paraent01();
               // Child01 child01 =new Child01();
            //System.out.println(Paraent01.paraent01);
            System.out.println(Child01.childInt);
        }
    }
    
    class Paraent01 {
        //常量会在编译期间放到调用类的常量池中
        public static final int  paraent01=10;
        //public static  int  paraent01=10;
        //静态代码块随着类的加载只会执行一次
    
        static {
            System.out.println("paraent01");
        }
    }
    
    class Child01 extends Paraent01 {
        public static final int childInt =5;
        static {
            System.out.println("child01");
        }
    }
    
    

    输出结果

    5
    
  • 相关阅读:
    深入理解JavaScript系列(45):代码复用模式(避免篇)
    深入理解JavaScript系列(38):设计模式之职责链模式
    深入理解JavaScript系列(43):设计模式之状态模式
    认识js中的function和this
    深入理解JavaScript系列(29):设计模式之装饰者模式
    javascript的内存分配
    详细解读Jquery各Ajax函数
    javascript 杂谈之哪种写法你更喜欢?
    深入理解JavaScript系列(28):设计模式之工厂模式
    深入理解JavaScript系列(30):设计模式之外观模式
  • 原文地址:https://www.cnblogs.com/JuncaiF/p/12008480.html
Copyright © 2011-2022 走看看