0

    原来如此啊!在jvm中类是这样被加载的

    2023.07.09 | admin | 118次围观

    前言

    学习了类加载过程jar找不到或无法加载主类,可以更加方便我们理解反射的机制和原理。

    一、类加载过程

    1、加载(load)

    将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类地java.lang.Class对象。

    2、链接(link)

    将类的二进制数据合并到 JRE 中。

    3、初始化(Initialize):JVM虚拟机负责对类进行初始化

    public class test01 {
        public static void main(String[] args) {
            A a = new A();
            System.out.println(A.num);
        }
    }
    class A{
        static {
            System.out.println("静态代码块初始化!");
            num = 500;
        }
        static Integer num = 100;
        public A(){
            System.out.println("无参构造初始化!");
        }
    }
    

    执行结果如下:

    结论:

    ①先执行静态代码块,这时候给num赋值为500

    ②然后执行无参构造函数,其实就是我们new的操作。

    ③执行num = 100;

    ④可以简单的得出类的加载先后顺序!

    二、类初始化

    前置代码:

    public class test01 {
        static {
            System.out.println("我是main类的静态代码块。main类被加载啦~");
        }
        public static void main(String[] args) {
            
        }
    }
    class A{
        static int b = 2;
        static {
            System.out.println("父类A被加载~");
        }
    }
    class B extends A{
        static {
            System.out.println("子类B被加载~");
            b = 500;
        }
        static int m = 100;
        static final int M = 1;
    }
    

    可以分两种情况来讨论这个问题:

    1、类的主动引用(一定会发生类的初始化)

    public static void main(String[] args) {
       	//主动引用
           B b = new B();
       }
    

    结果:

    public static void main(String[] args) {
    		//反射也会产生主动引用
           Class.forName("com.dbright.Test.B");
        }
    

    2、类的被动引用(不会发生类的初始化)

    public static void main(String[] args) {
    		//调用父类静态变量
          System.out.println(B.b);
        }
    

    public static void main(String[] args) {
    		//定义自身数组
          B[] array = new B[5]; 
        }
    

    public static void main(String[] args) {
    		//调用自身静态变量
          System.out.println(B.M);
        }
    

    三、类加载器

    **类加载器的作用 :**将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中数据的访问入口。 类加载器主要分为三层:

    类缓存:标准的JavaSE类加载器可以按要求查找类jar找不到或无法加载主类,但一旦某个类被加载到类加载器中,他将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以回收这些Class对象。

    public class Test02 {
        public static void main(String[] args) throws ClassNotFoundException {
            //获取系统类的加载器
            ClassLoader loader = ClassLoader.getSystemClassLoader();
            System.out.println(loader);  //sun.misc.Launcher$AppClassLoader@18b4aac2
            //获取系统类加载的父类加载器-->扩展类加载器
            ClassLoader parent = loader.getParent();
            System.out.println(parent);  //sun.misc.Launcher$ExtClassLoader@74a14482
            //获取扩展类加载器的父类加载器-->根加载器(C/C++)
            ClassLoader parent1 = parent.getParent();
            System.out.println(parent1);  //null
            //测试当前类是哪个加载器加载的
            ClassLoader classLoader = Class.forName("com.dbright.Test.Test02").getClassLoader();
            System.out.println(classLoader);  //sun.misc.Launcher$AppClassLoader@18b4aac2
            //测试JDK内部类是谁加载的
            classLoader = Class.forName("java.lang.Object").getClassLoader();
            System.out.println(classLoader);  //null
            // 如何获取系统类加载器可以加载的路径
            System.out.println(System.getProperty("java.class.path"));
            /*
            D:\Software\Java\jdk1.8\jre\lib\charsets.jar;
            D:\Software\Java\jdk1.8\jre\lib\deploy.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\access-bridge-64.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\cldrdata.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\dnsns.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\jaccess.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\jfxrt.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\localedata.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\nashorn.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\sunec.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\sunjce_provider.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\sunmscapi.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\sunpkcs11.jar;
            D:\Software\Java\jdk1.8\jre\lib\ext\zipfs.jar;
            D:\Software\Java\jdk1.8\jre\lib\javaws.jar;
            D:\Software\Java\jdk1.8\jre\lib\jce.jar;
            D:\Software\Java\jdk1.8\jre\lib\jfr.jar;
            D:\Software\Java\jdk1.8\jre\lib\jfxswt.jar;
            D:\Software\Java\jdk1.8\jre\lib\jsse.jar;
            D:\Software\Java\jdk1.8\jre\lib\management-agent.jar;
            D:\Software\Java\jdk1.8\jre\lib\plugin.jar;
            D:\Software\Java\jdk1.8\jre\lib\resources.jar;
            D:\Software\Java\jdk1.8\jre\lib\rt.jar;
            D:\NEU\learn\java\project\out\production\project;
            D:\NEU\learn\java\project\src\com\lib\commons-io-2.8.0.jar;
            D:\Software\IntelliJ IDEA 2020.1.4\lib\idea_rt.jar
             */
            //双亲委派机制:如果上层加载器存在不会使用下层定义类
        }
    }
    

    双亲委派机制:如果上层加载器存在不会使用下层定义类

    2021最新完整面试题及答案(都整理成文档),有很多干货,包含mysql,netty,spring,线程,spring cloud、JVM、源码、算法等详细讲解,详细的学习规划图等学习资料,私信我:Java 获取!

    写作不易!请点赞、关注、评论给作者一个鼓励吧~

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    标签: jvm
    发表评论