首页 > 编程知识 正文

java类加载器说法正确的是,java类加载器有什么用

时间:2023-05-03 10:28:19 阅读:134215 作者:3846

进大学的话,接触Java已经4年了,虽然已经习惯了基本的API,但是我觉得对Java的特性还是了解了一半。 要成为优秀的Java开发人员,必须深刻理解类加载机制和具有JVM字节码等核心特性的Java平台的工作原理。 今天我将记录我在新的学习过程中对Java类加载机制的了解。

1 .类加载机制

类加载是将类合并到正在运行的JVM进程中的过程。 要首先加载类,必须先加载类文件并连接,然后进行大量的验证。 然后,将生成一个表示该类的class对象,从中可以创建新的实例。 这就是我理解的Java类加载的结构。

通过加载和连接出现的class对象表示该类已经加载到JVM中,以后将不再加载。

2 .类加载器和父母委托模型

Java平台有几种经典的类加载器,它们在平台启动和正常操作中承担着不同的任务。

根类加载器(Bootstrap ClassLoader ) ——通常在虚拟机启动后立即实例化。 它可以被视为JVM的一部分,通常负责加载系统的基本jar包(主要是rt.jar ),而不进行验证工作。 开发人员不能直接使用此加载程序

扩展类加载器(Extension ClassLoader ) ——用于加载安装过程中附带的标准扩展。 一般包括安全扩展。 我们的开发者可以直接使用。

应用(或系统)类加载器(System ClassLoader ) ——这是最广泛使用的类加载器。 负责加载APP应用程序类。

在比自定义类加载器(Custom ClassLoader ) ——更复杂的环境中,开发人员可以通过继承java.lang.ClassLoader类来实现自己的类加载器以满足特定的需要。 例如,Spring框架封装了自己的类加载器。 在之后的Spring源代码学习中遇到了吧。

线程上下文类加载器(Context ClassLoader ) ——缺省为系统类加载器,可以在Thread.currentThread ).setcontextclassloader中进行设置可以为每个线程加载线程上下文类。这主要用于打破父级委托模型,允许父级类加载器通过子类加载所需的类库。

父母委托模型后,我们从这张图中可以看到以下内容。

如果类加载器收到类加载请求,但他说不会立即去找,那么只有先委托他的父加载器完成该请求,并反馈说找不到其父加载器,他才会自己去找。 (注意:父加载器的默认目录路径不同,一个类在虚拟机中通过完全限定类名的类加载器建立唯一性。 )采用父母委托的好处可以保证系统中的类不会混乱。 例如,如果您自己编写了java.lang.object类,并将路径也放在lib下,则编译后将有两个object类。 如果采用来自父母的委托,则不会加载你自己写的object,而只加载rt.jar中的object。

3 .加载类

有两种方法可以手动加载类: Class.forName (和ClassLoader.loadClass )。

从源代码中看看他们的区别吧

Class.forName (

有两种重载方法

publicstaticclassforname (string class name ) throws ClassNotFoundException {

返回格式0 (class name,true,class loader.getcallerclassloader () );

}

publicstaticclassforname (string name,boolean initialize,

ClassLoader loader )

throws ClassNotFoundException

{

if (loader==空值) {

securitymanagersm=system.getsecuritymanager (;

if(sm!=null ) {

class loader ccl=class loader.getcallerclassloader (;

if(ccl!=null ) {

sm.checkPermission (

security constants.get _ class loader _ permission;

}

}

}

returnforname0(name,initialize,loader );

}

/* * calledaftersecuritycheckshavebeenmade.* /

privatestaticnativeclassforname0(字符串名称,布尔初始化,

oader loader)

throws ClassNotFoundException;

第一个方法默认初始化类。

第二个方法可以选择是否初始化类和可以选择类加载器。

它们俩最终都是返回forName0,而forName0有native关键字,原生态的方法,是其他语言实现的,我就不深究下去了。

ClassLoader.loadClass()

它同样也有两个重载方法

public Class> loadClass(String name) throws ClassNotFoundException {

return loadClass(name, false);

}

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();

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;

}

}

第一个方法的具体实现是第二个方法。resolve参数为false。

第二个方法先检查这个类是否被加载过,如果没有被加载过,那就通过双亲委派的模式去找,如果父类加载器不是根类加载器,那就递归调用,如果是,那就试着返回根类加载器所加载的类或者返回null,当虚拟机想要装入的不仅包括指定的类似,resolve参数为true,装入该类英语的所有其他类。这个方法还用了其他的类,它们基本都是用native修饰的,在这也不深究,知道是用来干嘛的就好了。

以上就是我所学习的关于Java类加载器的内容。

https://blog.csdn.net/donggua3694857/article/details/51932630

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。