前言:
目前各位老铁们对“java的类加载器”都比较讲究,大家都需要知道一些“java的类加载器”的相关内容。那么小编在网摘上网罗了一些对于“java的类加载器””的相关内容,希望看官们能喜欢,同学们快快来学习一下吧!类加载器负责运行时(Runtime)把class文件动态的加载到虚拟机(JVM)中。同时,类加载器也是JRE的一部分,所以JRE可以不关心底层文件系统,就可以运行Java程序。此外,这些 Java 类不是一次性加载到内存中的,而是在应用程序需要时加载到内存中。
类加载器简介
首先我们通过一段代码来看一下Java中的类加载器:
public class ClassLoaderTest {
@Test
public void testClassLoaders() {
System.out.println("Classloader of this class:"
+ ClassLoaderTest.class.getClassLoader());
System.out.println("Classloader of Logging:"
+ Logging.class.getClassLoader());
System.out.println("Classloader of ArrayList:"
+ ArrayList.class.getClassLoader());
// 打印结果
// Classloader of this class:sun.misc.Launcher$AppClassLoader@18b4aac2
// Classloader of Logging:sun.misc.Launcher$ExtClassLoader@6325a3ee
// Classloader of ArrayList:null
}
}
从打印结果来看,包含3种类加载器:应用类加载器(Application ClassLoader), 扩展类加载器(Extension ClassLoader)和 一个启动类加载器(展示位null)。
应用类加载器在类路径中加载我们自己的文件,它是扩展类加载器的子类。扩展类加载器加载的类是核心 Java 类的扩展,默认放在/lib/ext目录中,或者被java.ext.dirs系统变量所指定的路径中的所有类库。它是启动类加载器的子类。启动类加载器是所有其他类的父类,默认放在/lib目录中,或者-Xbootclasspath参数所指定的路径中。是虚拟机识别的类库,用户无法直接使用。对于ArrayList为什么打印出来的是null,那是因为启动类加载器都是用本地方法(native)写的,而不是Java,所以不会显示类。类加载器是如何工作的
上面我们已经知道,类加载器是JRE的一部分。当 JVM 尝试加载一个类时,类加载器尝试定位该类并使用完全限定的类名将类信息加载进入runtime。 java.lang.ClassLoader.loadClass()负责将类加入runtime,如果runtime中没有该类,会首先从父类加载,如果父类没有加载,然后尝试从子类加载,这就是双亲委派模型。如果最后都没有加载到该类,则会抛出ClassNotFoundException异常。
双亲委派模型: 当一个类加载器收到类加载请求时,它首先不会自己去加载这个类的信息,而是把该请求转发给父类加载器,依次向上。所以所有的类加载请求都会被传递到父类加载器中,只有当父类加载器中无法加载到所需的类,子类加载器才会自己尝试去加载该类。
在大部分情况下,内置的几种类加载器已经够用了,但是在需要从本地硬盘或网络加载类的场景中,我们可能需要使用自定义类加载器。
public class CustomClassLoader extends ClassLoader {
@Override
public Class findClass(String name) {
byte[] b = loadClassFromFile(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassFromFile(String fileName) {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(
fileName.replace('.', File.separatorChar) + ".class");
byte[] buffer;
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int nextValue = 0;
try {
while ( (nextValue = inputStream.read()) != -1 ) {
byteStream.write(nextValue);
}
} catch (IOException e) {
e.printStackTrace();
}
buffer = byteStream.toByteArray();
return buffer;
}
}
loadClass方法
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {}
这里需要注意的是loadClass的第二个参数,当需要解析类的时候需要将该值设置为true,然而,我们并不总是需要解析一个类。 如果我们只需要确定类是否存在,那么 resolve 参数设置为 false。
如class.forName加载类时resolve就为true;而classLoader.loadClass时默认resolve为false。
#科技青年#
标签: #java的类加载器