1、类加载器负责加载 Java 类的字节代码到 Java 虚拟机中。最初是为了满足 Java Applet的需要而开发出来的,
Java Applet需要从远程下载Java类文件到浏览器中并执行。类加载器使得Java类可以被动态加载到Java虚拟机中并执行。
2、基本上所有的类加载器都是java.lang.ClassLoader类的一个实例,java.lang.ClassLoader类的基本职责
就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java类,
即java.lang.Class类的一个实例。除此之外,ClassLoader还负责加载Java应用所需的资源,
如图像文件和配置文件等。
ClassLoader中与加载类相关的方法如下:
(1)getParent() 返回该类加载器的父类加载器。
(2)loadClass(String name) 加载名称为 name的类。
(3)findClass(String name) 查找名称为 name的类。
(4)findLoadedClass(String name) 查找名称为 name的已经被加载过的类。
(5)defineClass(String name, byte[] b, int off, int len) 把字节数组 b中的内容转换成 Java类。
(6)resolveClass(Class<?> c) 链接指定的 Java 类。
3、java虚拟机中可以安装多个类加载,系统默认三个主要类加载器,每个类负责加载特定位置的类:
(1)引导类加载器(BootStrp):
它用来加载 Java的核心库,是用C++来实现的,并不继承自 java.lang.ClassLoader,
主要加载目录JRE/lib/rt.jar
(2)扩展类加载器(ExtClassLoader):
它用来加载 Java 的扩展库。主要加载目录JRE/lib/ext/*.jar。
(3)系统类加载器(AppClassLoader):
它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类,主要加载目录CLASSPATH指定的所有jar或目录。
Java 应用的类都是由它来完成加载的,可以通过 ClassLoader.getSystemClassLoader()来获取它。
4. 除了引导类加载器(BootStrp)之外,所有的类加载器都有一个父类加载器。可通过getParent()方法得到父类加载器。
JDK 的实现对于父类加载器是引导类加载器(BootStrp)的情况,getParent()方法返回 null。例:
public class ClassLoaderTree {
public static void main(String[] args) {
ClassLoader loader = ClassLoaderTree.class.getClassLoader();
while (loader != null) {
System.out.println(loader.toString());
loader = loader.getParent();
}
}
}
输出结果如下:
sun.misc.Launcher$AppClassLoader@187c6c7
sun.misc.Launcher$ExtClassLoader@10b62c9
5、类加载器的委托机制
当Java虚拟机要加载一个类时,首先当前线程的类加载器去加载线程中的第一个类,如果类A中引用了类B,
Java虚拟机将使用加载类A的加载器来加载类B.也可以直接使用loadClass()方法直接指定某个类加载器去加载某个类。
每个类加载器加载类时,会先委托给其上级类加载器,当所有上级类加载器没有加载到类时,回到发起者类加载器,
如果发起者类加载器还加载不了,则抛出ClassNotFoundException。
6、Java 虚拟机是如何判定两个 Java 类是相同的,Java 虚拟机不仅要看类的全名是否相同,
还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,
被不同的类加载器加载之后所得到的类,也是不同的。
为了保证Java核心库的类型安全。所有 Java 应用都至少需要引用 java.lang.Object类,
也就是说在运行的时候,java.lang.Object这个类需要被加载到 Java 虚拟机中。如果这个加载过程由Java应用
自己的类加载器来完成的话,很可能就存在多个版本的 java.lang.Object类,而且这些类之间是不兼容的。
通过代理模式,对于Java核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的
都是同一个版本的 Java 核心库的类,是互相兼容的。
7、Class.forName
Class.forName是一个静态方法,同样可以用来加载类。该方法有两种形式:
Class.forName(String name, boolean initialize, ClassLoader loader)
第一种形式的参数 name表示的是类的全名;initialize表示是否初始化类;loader表示加载时使用的类加载器。
Class.forName(String className)
第二种形式则相当于设置了参数 initialize的值为 true,loader的值为当前类的类加载器。
Class.forName的一个很常见的用法是在加载数据库驱动的时候。如
Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance()
用来加载 Apache Derby 数据库的驱动。
8、编写自己的类加载器
一般来说,自己开发的类加载器只需要覆写 findClass(String name)方法即可。
java.lang.ClassLoader类的方法 loadClass()封装了前面提到的代理模式的实现,
该方法会首先调用 findLoadedClass()方法来检查该类是否已经被加载过;如果没有加载过的话,
会调用父类加载器的 loadClass()方法来尝试加载该类;如果父类加载器无法加载该类的话,
就调用 findClass()方法来查找该类。因此,为了保证类加载器都正确实现代理模式,在开发自己的类加载器时,
最好不要覆写 loadClass()方法,而是覆写 findClass()方法。例:
public class FileSystemClassLoader extends ClassLoader {
private String rootDir;
public FileSystemClassLoader(String rootDir) {
this.rootDir = rootDir;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = getClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
}
else {
return defineClass(name, classData, 0, classData.length);
}
}
private byte[] getClassData(String className) {
String path = classNameToPath(className);
try {
InputStream ins = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while ((bytesNumRead = ins.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String classNameToPath(String className) {
return rootDir + File.separatorChar
+ className.replace('.', File.separatorChar) + ".class";
}
}
8.Tomcat6的类加载器(从上至下)
(1)BootStrapClassLoader,Java的核心库,实际没有这个类
(2)ExtensionClassLoader,对于Sun JVM,是sun.misc.Launcher$ExtClassLoader,加载 Java 的扩展库。
(3) SystemClassLoader,对于Sun JVM,是sun.misc.Launcher$AppClassLoader,加载java的应用库。
(4) CommonClassLoader,对于Tomcat 6,是org.apache.catalina.loader.StandardClassLoader,
加载的类目录通过{tomcat}/conf/catalina.properties中的common.loader指定,
以SystemClassLoader为parent(目前默认定义是common.loader=${catalina.base}/lib,
${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar)
(5) CatalinaClassLoader,加载的类目录通过{tomcat}/conf/catalina.properties中server.loader指定,
以CommonClassLoader为parent,如果server.loader配置为空,
则ServerClassLoader 与CommonClassLoader是同一个(默认server.loader配置为空)
(6) SharedClassLoader:加载的类目录通过{tomcat}/conf/catalina.properties中share.loader指定,
以CommonClassLoader为parent,如果server.loader配置为空,
则CatalinaClassLoader 与CommonClassLoader是同一个(默认share.loader配置为空)
(7) WebappClassLoader:每个Context一个WebappClassLoader实例,
负责加载context的/WEB-INF/lib和/WEB-INF/classes目录,
context间的隔离就是通过不同的WebappClassLoader来做到的。
由于类定义一旦加载就不可改变,因此要实现tomcat的context的reload功能,
实际上是通过新建一个新的WebappClassLoader来做的,
因此reload的做法实际上代价是很高昂的,需要注意的是,JVM内存的Perm区是只吃不拉的,
抛弃掉的WebappClassLoader加载的类并不会被JVM释放,
因此tomcat的reload功能如果应用定义的类比较多的话,reload几次就OutOfPermSpace异常了。
(8)JasperLoader:每个JSP一个JasperLoader实例,与WebappClassLoader做法类似,
JSP支持修改生效是通过丢弃旧的JasperLoader,建一个新的JasperLoader来做到的,
同样的,存在轻微的PermSpace的内存泄露的情况。
分享到:
相关推荐
- 代码安全性:Java提供了多层安全机制,包括字节码验证器、类加载器和安全沙箱,来确保Java代码的安全执行。 - 开发环境配置:Java开发需要配置JDK(Java Development Kit),包括JRE和编译工具等。 - 简单Java...
通过学习《JAVA虚拟机解读入门》,你将能够了解JVM如何加载和解析类,以及类加载的双亲委托模型。你还将掌握栈帧的工作方式,理解方法调用和返回的过程。此外,书中还会详细介绍垃圾收集的工作原理,包括如何判断...
总的来说,"JAVA反射机制的入门代码"是初学者理解Java反射机制的好教材,通过它,你可以学习如何动态地操作Java类,提高代码的灵活性,并掌握处理`properties`文件的基础方法。在深入学习和实践中,你将进一步理解...
3. **加载与链接**:类加载器负责将字节码加载至内存,并进行链接和初始化。 4. **执行**:JVM解释执行字节码,调用操作系统API完成具体操作。 5. **垃圾收集**:JVM自动管理内存,定期回收不再使用的对象,释放...
Java的类加载器分为三个层次:Bootstrap ClassLoader(引导类加载器)、Extension ClassLoader(扩展类加载器)和App ClassLoader(应用程序类加载器)。当JVM启动时,会按照一定的顺序加载类,通常是从BootStrap...
这个"Java Web从入门到精通光盘源码1-15"提供了学习者深入理解和实践Java Web应用开发的资源。以下是一些核心知识点的详细说明: 1. **Servlet与JSP**:Servlet是Java Web的基础,用于处理HTTP请求并生成动态响应。...
JDK包含了编译器javac、解释器java以及各种开发工具,如javadoc用于生成API文档,jconsole用于监控Java应用程序等。安装完成后,还需要配置环境变量,包括JAVA_HOME、PATH和CLASSPATH,确保系统能够正确识别和执行...
为了学习和使用Java2,开发者需要安装Java开发工具包(JDK),其中包含了Java编译器、解释器和其他工具。此外,集成开发环境(IDE)如Eclipse、IntelliJ IDEA等也是Java开发的常用工具,它们提供了代码编辑、调试、...
文档中介绍了类加载器、反射的使用、注解等高级概念,这些都是在编写动态、灵活的Java应用程序时不可或缺的知识点。 ### Java新特性 随着Java版本的不断更新,引入了许多新的特性。文档中提到了JDK新特性,例如泛型...
【JAVA初级入门教程】 JAVA,由SUN公司(现已被甲骨文公司收购)开发,是一种广泛应用的跨平台、面向对象的编程语言。JAVA在设计时摒弃了C/C++中一些复杂且较少使用的特性,使得它更适合初学者学习。JAVA以面向对象...
- **类加载器**:Java使用类加载器来加载和管理不同来源的类,这种机制有助于保护系统不受外部代码的影响。 - **1.2.7 Java的数据类型** - Java的数据类型是固定的,无论在哪种平台上运行都保持一致,例如byte...
【JAVA入门级小程序】 在计算机编程领域,Java是一种广泛使用的高级编程语言,以其“一次编写,到处运行”的特性而著名。对于初学者来说,Java提供了一个友好的学习平台,能够帮助他们快速掌握编程基础。本资源包...
12. **Java虚拟机(JVM)**:理解JVM的工作原理,如类加载机制、内存模型(堆、栈、方法区)和垃圾回收,对于优化性能和解决内存问题有很大帮助。 13. **Junit测试**:单元测试是软件开发的重要部分,JUnit是Java中...
Java 手机程序设计是移动开发领域中的一个重要分支,它主要关注如何利用Java语言来创建在智能手机和平板电脑上运行的应用程序。Java由于其“一次编写,到处运行”的特性,成为跨平台移动开发的理想选择。本教程将带...
【Java Web从入门到精通光盘18-21】是一个涵盖了Java Web开发基础到进阶的教程资源,旨在帮助初学者系统学习并掌握这一领域。在这个光盘中,你可能会遇到一系列关于Web应用程序开发的知识点,包括但不限于以下内容:...
Java程序在运行时可以动态加载类库,这使得Java应用能够适应不断变化的环境,同时也方便了软件的更新和扩展。 #### 7. 可移植性 Java字节码的跨平台特性使得Java程序可以轻松地在不同的操作系统上运行,无需修改或...
同时,JVM提供了强大的类加载器系统,包括引导类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和应用类加载器(Application ClassLoader),它们负责从不同来源加载类,如JRE的lib目录、...
- **动态性**:Java允许程序在运行时加载新的类和资源。 - **丰富的类库**:Java拥有大量的标准库,涵盖各种功能。 2. Java的应用场景: - **Web Applet**:Java小程序,嵌入在网页中,提供互动体验。 - **...