类加载器

作者: 尉昌达 | 来源:发表于2020-07-16 22:49 被阅读0次
    类加载过程
    1. 自低向上检查该类是否已经加载
    2. 自顶向下进行实际查找和加载
    类加载过程
    • 这里用双亲委派,主要出于安全来考虑,不会让随意的class加载进去

    自定义的类加载器

    继承ClassLoader,重写findclass()

    public class MyClassLoader extends ClassLoader {
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            File f = new File("c:/test/", name.replace(".", "/").concat(".class"));
            try {
                FileInputStream fis = new FileInputStream(f);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int b = 0;
    
                while ((b=fis.read()) !=0) {
                    baos.write(b);
                }
    
                byte[] bytes = baos.toByteArray();
                baos.close();
                fis.close();//可以写的更加严谨
    
                return defineClass(name, bytes, 0, bytes.length);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return super.findClass(name); //throws ClassNotFoundException
        }
    }
    

    这边自己实现findClass方法用的是钩子函数,模板方法的设计模式。

    类的LazyLoading

    LazyLoading 五种情况

    1. –new getstatic putstatic invokestatic指令,访问final变量除外

    2. –java.lang.reflect对类进行反射调用时

    3. –初始化子类的时候,父类首先初始化

    4. –虚拟机启动时,被执行的主类必须初始化

    5. –动态语言支持java.lang.invoke.MethodHandle解析的结果为REF_getstatic REF_putstatic REF_invokestatic的方法句柄时,该类必须初始化

    public class LazyLoading { //严格讲应该叫lazy initialzing,因为java虚拟机规范并没有严格规定什么时候必须loading,但严格规定了什么时候initialzing
        public static void main(String[] args) throws Exception {
            //P p;
            //X x = new X();
            //System.out.println(P.i);
            //System.out.println(P.j);
            //Class.forName("com.mashibing.jvm.c2_classloader.T008_LazyLoading$P");
    
        }
    
        public static class P {
            final static int i = 8;
            static int j = 9;
            static {
                System.out.println("P");
            }
        }
    
        public static class X extends P {
            static {
                System.out.println("X");
            }
        }
    }
    
    当执行X x = new X();
    输出:
    P
    X
    

    当访问final static 变量,类不用加载。

    当执行XSystem.out.println(P.i);
    输出:
    8
    
    当执行System.out.println(P.j);
    输出:
    P
    9
    
    当执行Class.forName("com.mashibing.jvm.c2_classloader.T008_LazyLoading$P");
    输出:
    P
    

    整个加载过程:

    1. Loading

    2. Linking
      2.1. Verification
      - 验证文件是否符合JVM规定
      2.2. Preparation
      - 静态成员变量赋默认值
      2.3. Resolution
      - 将类、方法、属性等符号引用解析为直接引用
      常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用

    3. Initializing

      • 调用类初始化代码 <clinit>,给静态成员变量赋初始值

    小总结:

    1. load - 默认值 - 初始值
    2. new - 申请内存 - 默认值 - 初始值

    相关文章

      网友评论

        本文标题:类加载器

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