Typesafe forName类加载

时间:2011-06-01 07:42:08

标签: java generics

当结果是通用类型时,如何调用Class.forName()?通常我可以使用asSubclass(),但在这里,我认为这样做的唯一方法就是演员阵容,这种方式很有用。当其他所有内容都使用泛型输入时,我会感到烦恼。

场景如下:

有一个.jar,其中一个入口点主类具有main()。它需要一个类名的选项(以及其他一些,在这里无关紧要)。给出的类实现Callable<Integer>。这个类是加载的,inited&amp;启动。

这是我需要的一个例子:

Class<? extends Callable<Integer>> clazz = (Class<? extends Callable<Integer>>) Class.forName(options.valueOf(className)).asSubclass(Callable.class);

有没有办法摆脱那个演员?

使用SE6。

1 个答案:

答案 0 :(得分:10)

首先,您可能需要完整的通用Class

Class<Callable<Integer>> classCI = ...;

然后java类型系统没有问题

Class<? extends Callable<Integer>> clazz =     
    Class.forName(options.valueOf(className))
    .asSubclass(classCI);

我们如何获得classCI?我们可以通过未经检查的演员来欺骗

Class<Callable<Integer>> classCI = (Class<Callable<Integer>>)Callable.class;

这本质上是不安全的。必须有外力才能确保className真的是Callable<Integer>。例如,如果它是Callable<String>,则程序会毫无问题地运行所有强制转换,并且只有在调用Integer call()时才会爆炸,并且错误消息将会产生误导。

如果无法静态分析演员表以取得成功,那就没关系了:

Object o = ...;
String s1 = (String)o; // may fail, no javac warning
String s2 = String.class.cast(o); // may fail, no javac warning

只要在运行时转换失败时立即抛出异常。

为了安全起见,我们必须主动检查className

的泛型类型
@SuppressWarning( "unchecked" )
Class<? Callable<Integer>> getClass(String className)
{
    Class clazz = Class.forName(className);
    via reflection, check generic super interfaces of clazz
    if there's no Callable<Integer> super interface
        throw "className is not a Callable<Integer>"

    // we have *checked*, the following cast is safe
    return (Class<? Callable<Integer>>)clazz; 
}

我们有理由在此处禁止“取消选中”,因为实现检查以确保如果className没有真正表示实现Callable<Integer>的类,那么立即在那里抛出异常。我们的演员阵容被“检查”,程序是安全的。