调用'Class.forName'时未经检查的强制转换警告

Joe*_*dev 7 java casting compiler-warnings

我的代码如下

package com.foo;

public class TestComposition {
    public static void main(String[] args) {
        try {
            Class<Foo> fooClass = 
                    (Class<Foo>) Class.forName("Foo");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

'try'块中的赋值会产生警告

Type safety: Unchecked cast from Class<capture#1-of ?> to 
     Class<Foo>
Run Code Online (Sandbox Code Playgroud)

为什么是这样?

Tom*_*ine 35

首先,如果你知道确切的类,那么你就不需要了Class.forName.Foo.class会做.(在J2SE 5.0之前,Foo.class实际编译为执行Class.forName("Foo"),然后在静态中缓存它.)

你可能想要的是:

Class<? extends Foo> fooClass =
    (Class<? extends Foo>) Class.forName("MyFoo");
Run Code Online (Sandbox Code Playgroud)

(当我说想要时,演员,特别是反思都是邪恶的.)

碰巧,你有一个合适的方法来"安全地"进行演员表(假设Foo它本身不是通用的).安全,因为不提供对不兼容对象的引用,而不是没有错误或没有意外的异常.

Class<? extends Foo> fooClass =
    Class.forName("MyFoo").asSubclass(Foo.class);
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 7

好吧,首先让我们清楚问题所在 - 它在演员阵容中.这是一个较短的例子:

public class Test {    
    public static void main(String[] args) throws Exception {
        Object x = (Class<Test>) Class.forName("Test");
    }
}
Run Code Online (Sandbox Code Playgroud)

这仍然有同样的问题.问题是演员阵容实际上并不会测试任何东西 - 因为演员阵容将被有效地转换为原始Class类型.因为Class<T>它更令人惊讶,因为实际上对象确实知道所涉及的类,但考虑类似的情况:

List<?> list = ... get list from somewhere;
List<String> stringList = (List<String>) list;
Run Code Online (Sandbox Code Playgroud)

该演员不会检查它是否真的List<String>因为类型擦除导致信息丢失.

现在在你的情况下,实际上有一个相当简单的解决方案 - 如果你在编译时知道类名,只需使用:

Class<Foo> fooClass = Foo.class;
Run Code Online (Sandbox Code Playgroud)

如果你能提供一个更现实的例子这是不是这种情况,我们可以帮助您确定最合适的选择.

  • 我认为真正的问题是;如果您知道类型,为什么要使用 Class.forName()? (3认同)