开发者

Typesafe forName class loading

How do I call Class.forName() when the result is a generic type? Usually I can use asSubclass(), but here the only way I see to do it is a cast, which kindof sticks out & bugs me when everything else is nicely typed with generics.

The scenario goes something like this:

There is a .jar with one entry point main class that has a main(). It takes an option of a classname (and some others, irrelevant here). The class given implements Callable<Integer>. This class is loaded, inited & launched.

Here is an example of what I need:

Class<? extends Callable<Integer>> clazz = (Class<? e开发者_开发知识库xtends Callable<Integer>>) Class.forName(options.valueOf(className)).asSubclass(Callable.class);

Is there any way to get rid of that cast?

Using SE6.


First you probably want a full generic Class

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

Then the java type system has no problem with

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

How can we get classCI? We can cheat by unchecked cast

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

This is inherently unsafe. There must be external forces to make sure the className really is a Callable<Integer>. For example if it's a Callable<String>, the program runs through all the casts without any problem, and it only blows up much later when Integer call() is invoked, and the error message will be very misleading.

It's ok if a cast cannot be analyzed statically to succeed:

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

as long as an exception is immediately thrown when the cast fails at runtime.

To be type safe, we must proactively check the generic type of the 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; 
}

We are justified to suppress "unchecked" here, because the implementation checks to make sure that if the className doesn't really denote a class implementing Callable<Integer>, it immediately throws an exception right there. Our cast is "checked", and the program is type safe.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜