程序员

类加载器

2020-07-16  本文已影响0人  尉昌达
类加载过程
  1. 自低向上检查该类是否已经加载
  2. 自顶向下进行实际查找和加载
类加载过程

自定义的类加载器

继承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 - 申请内存 - 默认值 - 初始值
上一篇下一篇

猜你喜欢

热点阅读