您的位置:

LoadClass详解

一、LoadClass的概念

LoadClass是Java中的一个类加载器,它的主要功能是将二进制字节流加载到JVM中,并将其转换成Java类对象。它具有以下特点:

1. 面向对象:LoadClass是一个Java对象,它拥有类对象实例化所需的所有信息。

2. 分层次性质:LoadClass采用了分层次的架构模式,其顶层3个classloader分别为引导类(classpath路径下的jre/lib文件夹下面的jar包),扩展类(classpath路径下的jre/extend/lib文件夹下面的jar包)以及系统类(classpath路径下设置的自己的class路径),对于一个class,先从引导类加载器(classpath路径下的jre/lib文件夹下面的jar包)查找,如果找不到,在到扩展类加载器(classpath路径下的jre/extend/lib文件夹下面的jar包)查找,如果还找不到则到系统类加载器(classpath路径下设置的自己的class路径)查找。

3. 双亲委派机制:LoadClass在加载类的时候,会按照双亲委派模型的方式,将加载请求传递到其父级classloader中查找。如果父级classloader能够找到该类,并且类的权限验证通过,则直接返回该类的Class对象。否则,依次向上委派直到JVM的顶层classloader,如果还是没找到,则使用自己的findClass方法查找并返回Class对象。这种机制可以保证应用程序的安全性,避免类的重复加载。

二、LoadClass的使用

LoadClass的主要作用是在运行时加载指定的类,并返回该类的Class对象。它的使用方法如下:

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        ClassLoader c = Test.class.getClassLoader();
        Class clazz = c.loadClass("com.example.demo.ClassName");
        System.out.println(clazz.getName());
    }
}

在以上代码中,我们通过类的getClasLoader()方法获取了Test类的类加载器,然后调用其loadClass()方法加载指定的类,最后通过Class对象获取到该类的名称。需要注意的是,这里的参数是类的全路径名。

三、LoadClass的继承关系

LoadClass的继承关系比较复杂,如下图所示:

其中,ClassLoader类是所有Java类加载器的父类,定义了加载类的基本方法,最基础的loadClass()方法在其中定义。

BootstrapClassLoader是Java虚拟机的启动类加载器,它主要从jre目录下的lib/rt.jar文件中加载核心类(如java、javax等)。由于它是使用C++编写的,因此无法在Java代码中显示引用。

ExtensionClassLoader是Java虚拟机的扩展类加载器,它从jre目录下的lib/ext文件夹中加载扩展类。也可以通过-Djava.ext.dirs指定其他目录。

SystemClassLoader是Java虚拟机的系统类加载器,它从CLASSPATH中指定的路径中加载用户类,也可以指定通过-Djava.class.path指定路径。

自定义加载器包括AppClassLoader、PluginClassLoader等,使用时需要自己编写相应的代码,并继承ClassLoader类。

四、LoadClass的常见问题

1. 类加载器的双亲委派机制存在某些隐患,可能导致某些类加载失败。

2. 类加载器的继承关系过于复杂,且在Java 9之前存在一定的限制(JDK 9时引入了模块化系统,对类加载器进行重构)。

3. 对于一些特殊的类加载器,如OSGI BundleClassLoader,其获取到的ClassLoader对象并不是系统的ClassLoader,该Loader无法访问到系统的ClassLoader。

4. 在类加载的委派机制中,若父ClassLoader为空,则由BootstrapClassLoader加载,虽然这样不会影响程序运行,但扩展性相对较差。

以上问题,在具体使用时需要考虑清晰。

五、LoadClass的优化

由于LoadClass在类加载时需要查找和验证类,因此其性能较慢。常见的优化方式包括类的预加载和JIT编译。

1. 类的预加载:在应用程序启动时,将常用的类提前加载到内存中,避免了在程序运行过程中去查找类。这样每次在运行时加载,就会比较快了。

2. JIT编译:JIT即“Just-In-Time”编译器,它会将热点代码编译成本地代码,提高了程序的执行速度。我们可以通过添加JIT编译命令来进行优化。

java -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -XX:MaxInlineSize=3 Main

以上是在运行Java程序时,添加JIT编译命令的示例,其中-XX:+PrintCompilation表示打印程序中被JIT编译的方法,-XX:MaxInlineSize指定方法内联的最大尺寸。

六、小结

LoadClass是Java中的一个类加载器,其主要功能是将二进制字节流加载到JVM中,并将其转换成Java类对象。它具有面向对象、分层次和双亲委派的特性。其使用方法是调用ClassLoader的loadClass()方法加载指定的类,并返回该类的Class对象。在继承关系上,LoadClass的父类是ClassLoader,其子类包括BootstrapClassLoader、ExtensionClassLoader和SystemClassLoader等。由于LoadClass在类加载时需要查找和验证类,因此可以通过类的预加载和JIT编译进行优化。