Generics and Class.forName

2022-09-01 17:12:29

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

我收到编译器警告。我这样做的方式是否正确?是否有可能使用类的名称并取回该类型的实例,因为我认为编译器无法知道该类型应该是什么?

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();
    }
}

谢谢


答案 1

我认为第一种方法应该看起来像这样:

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); 
}

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

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


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

Class<T> clazz = (Class<T>) Class.forName(className).asSubclass(ifaceClass);

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


答案 2

我认为这是因为没有针对 T 进行参数化。当您触发 eclipse 自动完成时,它假定 clazz.newInstance() 返回 Object。因此,保留演员阵容并添加@SuppressWarnings。如果您没有正确使用该方法(即),则会发生a,但这是正常的。Class.forName(..)String str = Utils.create("java.util.ArrayList");ClassCastException


推荐