java实现懒加载_java类加载过程和双亲委派

java类加载过程包括,加载->验证->准备->解析->初始化->使用->卸载,七个过程,主要说明前面5个过程。

1、加载:此加载千万不要和类加载混淆,此处加载只是类加载的第一个阶段。读取硬盘上编译后的字节码文件到jvm中,并且存储在运行时内存区,会在java堆中生成java.lang.Class对象,后面会作为方法区中该类的各种数据的访问入口。

2、验证:例如文件格式的校验(魔数头0xCAFEBABE开头)、元数据校验、字节码校验、符号引用校验等。

3、准备:给类的静态变量分配内存,赋值默认值。

public static int a = 1;//赋默认值 =0
public static final int a = 1;//存在ConstantValue属性的直接赋值=1

4、解析:将符号引用转化为直接引用,例如把静态方法 main()方法(本身其实就是一个符号,符号引用)替换为指向数据所存内存的指针或句柄等(直接引用),也叫做静态链接过程。动态链接是在程序运行期间完成的将符号引用替换为直接引用。

5、初始化:类中静态变量初始化为实际的值。

public static int a = 12;

接下来重点聊一聊类加载器

类加载到方法区后,主要包括运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应class实例的引用等信息。

其实java类加载是懒加载,在使用的时候才会加载。

public class MyClass {

    static {
        System.out.println("---load MyClass---");
    }

    public int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        MyClass mc = new MyClass();
        mc.add(1, 2);
        ClassLoader my = mc.getClass().getClassLoader();
        ClassLoader parent1 = my.getParent();
        ClassLoader parent2 = parent1.getParent();
        System.out.println("myclass loader:" + my);
        System.out.println("parent1 loader:" + parent1);
        System.out.println("parent2 loader:" + parent2);

        System.out.println("--- test load ---");
        A a = new A();
        B b = null;//当 B b=new B() 才会加载
    }

}

public class A {
    static {
        System.out.println("---load A---");
    }

    public A() {
        System.out.println("---init A---");
    }
}

public class B {
    static {
        System.out.println("---load B---");
    }

    public B() {
        System.out.println("---init B---");
    }
}

输出:
---load MyClass---
myclass loader:sun.misc.Launcher$AppClassLoader@18b4aac2
parent1 loader:sun.misc.Launcher$ExtClassLoader@4554617c
parent2 loader:null
--- test load ---
---load A---
---init A---

类加载器有三种

691032a32089b5ab58b8d11f0ba43e1f.png
1-1

启动类加载器(Bootstrap ClassLoader),由c++实现,负责将jre/lib目录中的类库加载到内存中。

扩展类加载器(Extension ClassLoader),由sun.misc.Launcher$ExtClassLoader实现,负责将jre/lib/ext目录中的类库加载到内存中。

应用程序加载器(Application ClassLoader),由sun.misc.Launcher$ApplicationClassLoader实现,也成为系统加载器。

其实还存在用户自定义的加载器,比如tomcat就是自己实现类加载器。

如图1-1所示,就是类的加载顺序。找了两个上级类加载器去加载,如果没有加载再往下加载,也就是委派上级两个父级加载(双亲委派)。

主要流程实现源码如下:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            //当前类加载器是否已经加载了该类
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    //如果当前类加载器的父类不为空,委托父类加载器加载该类
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                    //如果为空,委托引导类加载器加载该类
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    //调用URLCLassLoader的findClass方法找到类(classpath)路径下,查找该类并且加载
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

双亲委派优点:避免重复加载、避免核心类篡改。比如:网络植入一个java.lang.Integer类,如果通过双亲委派,先是由父类加载器加载,父类肯定会加载,子类不会再加载。

双亲委派缺点:例如像tomcat,如果tomcat发布两个war包程序,里面都引用了***.jar包,但是版本不一样,不可能用两个jvm。如果按照双亲委派势必造成冲突,所以tomcat是自己实现的类加载器,也叫打破双亲委派加载机制。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值