1. 概述
在Java中,动态加载类是指在运行时而不是编译时将类加载到Java虚拟机(JVM)。这种方法在我们不知道编译时类名,或者类加载基于用户输入或系统属性的情况下特别有用。
Java中有多种方式动态加载类,包括Class.forName()
方法、ClassLoader API
以及依赖注入框架。本文将关注Class.forName()
和Class.forName().newInstance()
方法,它们在Java应用中常见且对开发者理解至关重要。
2. Class.forName()
方法
Class.forName()
方法接受一个完整的类名作为参数,并返回与已加载类关联的Class
对象。在执行过程中,它尝试查找、加载并链接类或接口。当我们想要获取关于类的信息,如字段和方法时,通常会使用它。然而,需要注意的是,类并未初始化,调用其方法是不可能的。
让我们编写一个快速测试,使用Class.forName()
方法:
@Test
public void whenUseClassForNameCreatedInstanceOfClassClass() throws... {
Class instance = Class.forName("com.baeldung.loadclass.MyClassForLoad");
assertInstanceOf(Class.class, instance, "instance should be of Class.class");
}
还要记住,动态加载方法并不检查请求类对其调用者的可访问性,可能导致与加载、链接或初始化相关的潜在异常。妥善处理这些异常至关重要,以避免意外行为和可能的崩溃:
-
LinkageError
- 如果链接失败 -
ExceptionInInitializerError
- 如果初始化失败 -
ClassNotFoundException
- 如果找不到类
3. Class.forName().newInstance()
方法
当需要创建一个类的实例时,Class.forName().newInstance()
方法更为合适。此方法同样接受一个完整的类名作为参数,并返回代表此Class
对象的类的新实例。这就像为MyClassForLoad
调用带有空参数列表的new
操作符。
让我们看一个使用Class.forName().newInstance()
方法的单元测试示例:
@Test
public void whenUseClassForNameWithNewInstanceCreatedInstanceOfTargetClass throws... () {
Object instance = Class.forName("com.baeldung.loadclass.MyClassForLoad").newInstance();
assertInstanceOf(MyClassForLoad.class, instance, "instance should be of MyClassForLoad.class");
}
请记住,Class.forName().newInstance()
可能会抛出几个异常:
-
IllegalAccessException
- 如果类或其无参构造函数不可访问 -
InstantiationException
- 如果这个类表示抽象类、接口、数组类、基本类型或void
-
ExceptionInInitializerError
- 如果由此方法引发的初始化失败 -
SecurityException
- 当调用代码没有足够的权限访问指定的类
然而,重要的是要注意,自Java 9起,newInstance()
方法已被弃用,因为它会传播由无参构造函数抛出的任何异常,包括检查异常。这实际上绕过了编译器进行的编译时异常检查。因此,可能导致意外错误或bug,使得代码库更难维护和扩展。
**推荐使用getDeclaredConstructor().newInstance()
**方法来避免这个问题:
Object instance = Class.forName("com.baeldung.loadclass.MyClassForLoad").getDeclaredConstructor().newInstance();
4. 总结
开发者必须深入了解Java中动态类加载的工作原理。它提供了许多优势,有助于提高Java应用程序的性能、可维护性和可扩展性。
本文介绍了Class.forName()
和Class.forName().newInstance()
是Java中的关键方法,它们允许我们在运行时加载类。这两种方法的区别在于它们的作用和返回值。
Class.forName()
动态加载类并返回一个Class
对象,而Class.forName().newInstance()
加载类并创建加载类的实例。
理解和区别这些方法对于实际场景中的应用至关重要,例如:
- 插件开发
- 如Spring或Guice这样的依赖注入框架
- 根据使用的数据库加载JDBC驱动
- 根据输入参数加载类
最后,通过了解Class.forName()
和Class.forName().newInstance()
之间的差异,开发者可以为其Java项目做出明智的动态加载类决策,从而实现更高效和有效的代码。完整的源代码可在GitHub上找到。