面试刷题23:类加载过程和双亲委派机制?

面试刷题23:类加载过程和双亲委派机制?

jvm赋能java跨平台的能力,而类加载机制是深入理解java的必要条件。

我是李福春,我在准备面试,今天的问题是:

java的类加载机制是怎样的?什么是双亲委派原则?

答:java的类加载过程分为 加载,链接,初始化。

加载:即从数据源(jar,class,网络)加载class文件到jvm,映射为class对象,如果不是classFile结构,抛出ClassFormatError;

链接:把第一步得到的class对象转换到jvm环境,进行验证(字节信息是否符合jvm规范,否则抛出VerifyError),准备(为静态变量分配内存空间),解析(常量池中的符号引用替换为直接引用);

初始化:即为静态变量和静态代码块赋值。

java的类加载器部分的加载器分4类,见上图。

BootStrapClassLoader:加载jre/lib下的jdk的jar包,具有超级权限,是最顶级的类加载器;

ExtensionClassLoader:加载jre/lib/ext下的jar包,加载jdk的扩展程序包;

ApplicationClassLoader:加载当前应用classpath下的jar包或者class文件;

自定义ClassLoader:用户自定义的类加载器,一般是为了进行进程隔离,或者自己操纵字节码

双亲委派机制:即为了避免类信息被重复加载和程序的安全性,父加载器优先子加载器加载类型到jvm,子加载器无法加载父加载器已经加载到jvm中的类型信息。

下面做一下扩展:针对面试官可能会追问的细节。

类加载器体系

面试刷题23:类加载过程和双亲委派机制?

指定超级加载器的目录和时机:

# 指定新的bootclasspath,替换java.*包的内部实现
java -Xbootclasspath:<your_boot_classpath> your_App
 
# a意味着append,将指定目录添加到bootclasspath后面
java -Xbootclasspath/a:<your_dir> your_App
 
# p意味着prepend,将指定目录添加到bootclasspath前面
java -Xbootclasspath/p:<your_dir> your_App

指定扩展加载器的目录:

java -Djava.ext.dirs=your_ext_dir HelloWorld

指定系统加载器的实现类:

java -Djava.system.class.loader=com.yourcorp.YourClassLoader HelloWorld

打印出类加载器:

package org.example.mianshi.classloader;



import java.util.Collection;

/**
 * 作者:     carter
 * 创建日期:  2020/3/31 12:41
 * 描述:     类加载器的层级关系
 */

public class PrintClassLoaderApp {


    public static void main(String[] args) {

        System.out.println("PrintClassLoaderApp 的类加载器是:"+PrintClassLoaderApp.class.getClassLoader());
        System.out.println("parent 的类加载器是:"+ PrintClassLoaderApp.class.getClassLoader().getParent());
        System.out.println("parent.parent 的类加载器是:"+ PrintClassLoaderApp.class.getClassLoader().getParent().getParent());
        System.out.println("Collection 的类加载器是:"+ Collection.class.getClassLoader());

    }

}

输出结果:

我使用的java10,PlatformClassLoader替代了ExtensionClassLoader;

PrintClassLoaderApp 的类加载器是:jdk.internal.loader.ClassLoaders$AppClassLoader@4459eb14
parent 的类加载器是:jdk.internal.loader.ClassLoaders$PlatformClassLoader@2ac1fdc4
parent.parent 的类加载器是:null
Collection 的类加载器是:null

自定义类加载器

自定义类加载器一般用来进行进程内隔离,或者需要自己操纵字节码的场景。

过程如下:

1,通过名称找到二进制代码,即class文件;

2,使用class文件创建对应的class对象;

示例代码如下:

package org.example.mianshi.classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * 作者:     carter
 * 创建日期:  2020/3/31 14:24
 * 描述:     自定义类加载器
 */

public class CustomerClassLoaderApp extends ClassLoader {

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        byte[] bytes = loadClassFromFile(name);

        return defineClass(name, bytes, 0, bytes.length);
    }

    private byte[] loadClassFromFile(String name) {

        InputStream inputStream = getClass().getClassLoader()
                .getResourceAsStream(name.replace(".", File.separator) + ".class");

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        int nextValue = 0;
        try {
            while ((nextValue = inputStream.read()) != -1) {
                byteArrayOutputStream.write(nextValue);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] buffer = byteArrayOutputStream.toByteArray();


        return buffer;
    }
}

如何加速类加载

1,   AOT , 即提前把字节码编译成机器码,然后在启动的时候指定机器码的位置,

2,AppCDS ,即提前把类信息加载成为元数据,使用内存映射技术,免除类加载和解析的开销。

小结

本节回顾了jvm的类加载过程,类加载器的层次,双亲委派原则,

然后指明了自定义类加载器的使用场景和基本过程,以及给了一个简单的例子;

最后给出了两种加速类加载器速度的方法。

面试刷题23:类加载过程和双亲委派机制?

原创不易,转载请注明出处,让我们互通有无,共同进步,欢迎沟通交流。

原文 

https://segmentfault.com/a/1190000022214093

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 面试刷题23:类加载过程和双亲委派机制?

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址