泛型和Class.forName

dog*_*ane 22 java generics instantiation

我想使用其名称创建指定类的实例.我的代码如下所示.

我收到编译器警告.我这样做是对的吗?甚至可以使用类的名称并获取该类型的实例,因为我认为编译器不知道该类型应该是什么方式?

public static <T> T create(final String className) {
    try {
        final Class<?> clazz = Class.forName(className);

        //WARNING: Type safety: Unchecked cast from capture#2-of ? to T
        return (T) create(clazz); 
    }
    catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

public static <T> T create(final Class<T> classToCreate) {
    final Constructor<T> constructor;
    try {
        constructor = classToCreate.getDeclaredConstructor();
        final T result = constructor.newInstance();
        return result;
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢

Ste*_*n C 32

我认为第一种方法应该是这样的:

public static <T> T create(final String className, Class<T> ifaceClass) 
throws ClassNotFoundException {
    final Class<T> clazz = Class.forName(className).asSubclass(ifaceClass);
    return create(clazz); 
}
Run Code Online (Sandbox Code Playgroud)

你不能使用类型参数进行上传类型转换...没有那些讨厌的类型安全警告.

顺便说一句,如果忽略这些警告,create方法可能会创建某个类的实例,该实例与调用者使用的实际类型不兼容.这可能会在以后导致意外的ClassCastException; 例如,在分配实例时.


编辑:@Pascal指出我们需要添加一个类型转换来进行编译; 即

Class<T> clazz = (Class<T>) Class.forName(className).asSubclass(ifaceClass);
Run Code Online (Sandbox Code Playgroud)

不幸的是,我们需要添加@SuppressWarnings注释.

  • 或者,如果你想使用asSubclass而不是cast,你应该声明clazz属于`Class <?扩展T>`,不再需要未经检查的强制转换. (9认同)