Skip to main content
 首页 » 编程设计

Java检查类是否存在

2022年07月19日128小虾米

Java检查类是否存在

对于决定使用哪个接口的实现类,检查类的存在性非常有用。本文我们探索 Class.forName()方法检查类路径下是否存在特定类的一些细节差异。

1. 使用Class.forName()

使用java反射检查类的存在性,对于 Class.forName()方法,其文档中指出如果类不存在则抛出 *ClassNotFoundException*异常。

1.1 检测ClassNotFoundException异常

首先我们写个测试期望抛出ClassNotFoundException异常,这样可以知道测试满足期望:

@Test(expected = ClassNotFoundException.class) 
public void givenNonExistingClass_whenUsingForName_thenClassNotFound() throws ClassNotFoundException {
    
    Class.forName("class.that.does.not.exist"); 
} 

这样我们能够证明当类不存在是会抛 *ClassNotFoundException*异常。让我们写个类测试其确实存在:

@Test 
public void givenExistingClass_whenUsingForName_thenNoException() throws ClassNotFoundException {
    
    Class.forName("java.lang.String"); 
} 

这个测试证明 Class.forName() 方法在类确实存在时不在抛异常。然而这并不是完美的解决方案。

1.2 类初始化的副作用

需要特别指出的是,没有指定类加载器,Class.forName() 方法对执行类的静态初始化代码块,这回导致异常行为。

为了验证这种行为,下面创建一个类在静态块中国抛出 RuntimeException异常,这样可以知道初始化块是否被执行:

public static class InitializingClass {
    
    static {
    
        if (true) {
    //enable throwing of an exception in a static initialization block 
            throw new RuntimeException(); 
        } 
    } 
} 

通过查阅 forName文档,我们看到如果初始化失败会抛出 ExceptionInInitializerError异常。下面写个测试进行验证:

@Test(expected = ExceptionInInitializerError.class) 
public void givenInitializingClass_whenUsingForName_thenInitializationError() throws ClassNotFoundException {
    
    Class.forName("path.to.InitializingClass"); 
} 

执行初始化块有不可见的副作用。现在知道了如何引起性能问题或潜在错误。下面讨论如何跳过类初始化。

2. 跳过 Class.forName() 中初始化

幸运的是,forName()方法提供了重载方法,其接收一个类加载器,以及是否执行类初始化两个参数。根据文档,下面调用时等价的:

Class.forName("Foo") 
Class.forName("Foo", true, this.getClass().getClassLoader()) 

现在我们修改true为false,测试测试进行验证是否触发了静态块的调用:

@Test 
public void givenInitializingClass_whenUsingForNameWithoutInitialization_thenNoException() throws ClassNotFoundException {
    
    Class.forName("path.to.InitializingClass", false, getClass().getClassLoader()); 
} 

3. Java9 实现

对于Java9及以上版本,有第三个重载方法,其接收模块或类名字符串。该重载默认不运行类初始化,另外如果请求的类不存在不再抛异常而是返回null。

4. 总结

本文我们解释了调用Class.forName会引起类初始化的副作用和性能问题,因此尽量使用其重载方法避免这些问题。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/108809901
阅读延展