计算机系统应用教程网站

网站首页 > 技术文章 正文

Java类的加载机制

btikc 2024-09-08 12:00:50 技术文章 19 ℃ 0 评论

什么是类的加载?

类的加载指的是将类的.class文件中的二进制数据读入内存中,将其放在运行时数据区域的方法去内,然后在堆中创建java.lang.Class对象,用来封装类在方法区的数据结构.只有java虚拟机才会创建class对象,并且是一一对应关系.这样才能通过反射找到相应的类信息.

我们上面提到过Class这个类,这个类我们并没有new过,这个类是由java虚拟机创建的。通过它可以找到类的信息,我们来看下源码:

/*
 * Private constructor. Only the Java Virtual Machine creates Class objects.
 * This constructor is not used and prevents the default constructor being
 * generated.
 */
 private Class(ClassLoader loader) {
 // Initialize final field for classLoader. The initialization value of non-null
 // prevents future JIT optimizations from assuming this final field is null.
 classLoader = loader;
 }

从上面贴出的Class类的构造方法源码中,我们知道这个构造器是私有的,并且只有虚拟机才能创建这个类的对象。

类加载器

什么是类加载器?

类加载器负责对类的加载。

Java自带有3种类加载器

 1)根类加载器,使用c++编写(BootStrap),负责加载rt.jar
 2)扩展类加载器,java实现(ExtClassLoader) JRE/lib/ext/*.jar
 3)应用加载器,java实现(AppClassLoader) classpath 

根类加载器,是用c++实现的,我们没有办法在java层面看到;而ExtClassLoader和AppClassLoader的代码,它是在sun.misc.Launcher类中,

static class ExtClassLoader extends URLClassLoader 
static class AppClassLoader extends URLClassLoader

双亲委派机制

关于类加载器,我们不得不说一下双亲委派机制。听着很高大上,其实很简单。比如A类的加载器是AppClassLoader(其实我们自己写的类的加载器都是AppClassLoader),AppClassLoader不会自己去加载类,而会委ExtClassLoader进行加载,那么到了ExtClassLoader类加载器的时候,它也不会自己去加载,而是委托BootStrap类加载器进行加载,就这样一层一层往上委托,如果Bootstrap类加载器无法进行加载的话,再一层层往下走。

java.lang.ClassLoader的loadClass方法很清楚地告诉了我们这一点:

private final ClassLoader parent;
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;
 }
 }

从上面代码我们知道首先会检查class是否已经加载了,如果已经加载那就直接拿出,否则再进行加载。其中有一个parent属性,就是表示父加载器。这点正好说明了加载器之间的关系并不是继承关系。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表