java—当不可能进行泛化时,正确转换为作为参数传递的未知类型

rsaldnfx  于 2021-07-09  发布在  Java
关注(0)|答案(1)|浏览(266)

我有一个特殊类型的枚举,它定义了一个类,然后该类可以直接从一个枚举值示例化。为实现此目的,每个枚举实现以下接口:

public interface IEnumWithClass {
    public Class<?> getAssociatedClass();
}

一个枚举是这样的:

public enum Foo implements IEnumWithClass {

    eEnumValue(Goo.class);

    private final Class<?>    mAssociatedClass;

    Foo(Class<?> iAssociatedClass) {
        mAssociatedClass = iAssociatedClass;
    }

    @Override
    public Class<?> getAssociatedClass() {
        return mAssociatedClass;
    }
}

然后可以使用以下帮助程序示例化该类:

public class EnumWithClassHelper extends EnumWithValueHelper {
    private static Object getInstance(Class<?> type) throws Exception
    {    
        Constructor<?> constructor  = type.getConstructor();        
        return constructor.newInstance();
    }   
}

还有一个类似以下的电话:

Goo myGoo = (Goo) EnumWithClassHelper.getInstance( Foo.eEnumValue.getAssociatedClass() );

问题:我想避开这里的演员,直接得到一个黏液。
我使用以下助手制作:

@SuppressWarnings("unchecked")
private static <T> T getInstance(Class<?> type) throws Exception
{    
    Constructor<?> constructor  = type.getConstructor();        
    return (T) constructor.newInstance();
}

但在本例中,我有一个未经检查的cast异常警告,我也不想要它。
有什么安全的方法吗?还是我要坚持第一种方法?由于接口和枚举限制,我似乎无法将类作为参数传递(我没有成功地为枚举指定泛型参数)。
谢谢!:)

jogvjijk

jogvjijk1#

不幸的是,由于反射没有任何compiletime类型检查,所以您需要在某个时候进行未检查的强制转换。这又回到了打字的基本原理;jvm不知道它将在代码中示例化的对象的类型(通过设计),直到代码被执行为止,因此不能确定适当的类型是否可用,因为未检查的强制转换将保持未检查状态,这是由于您在接口中使用的泛型所造成的。同时,如果你想使用反射示例化的对象,没有理由不强制转换它,我怀疑你为什么不想要类型强制转换,因为这样做只是确保你拥有的变量实际上是它声称的类型,这只会让你的生活更容易出错。
这个答案可能不令人满意,所以我建议您使用另一个模型:

public interface IEnumWithClass<T> {
    public Class<T> getAssociatedClass();
}

public abstract class Foo<T> implements IEnumWithClass<T> {
    // Put any other code that shouldn't be instance-specific here
}

public final class ActualFoos{
    public static final Foo<Goo> goo = new Foo<Goo>() {
        @Override
        public Class<String> getAssociatedClass() {
            return Goo.class;
        }
    };
    public static final Foo<Integer> integer = new Foo<Integer>() {
        @Override
        public Class<Integer> getAssociatedClass() {
            return Integer.class;
        }
    };
}

同时,你的 getInstance 方法可以重新定义为:

public static <T> T getInstance(Class<T> type) throws Exception
{
    Constructor<T> c = type.getConstructor();
    c.setAccessible(true);
    return c.newInstance();
}

这允许你打电话 getInstance 使用(例如) ActualFoos.goo.getAssociatedClass() 作为参数直接得到 Goo 没有任何强制转换或未选中强制转换的对象。例如,如果我们假设 getInstance 是班上的一员 Bar ,代码可以如下所示:

Goo g = Bar.getInstance(ActualFoos.goo.getAssociatedClass());

或者,如果您只引用您知道可以访问的构造函数(可能是public),那么您可以完全放弃helper方法:

Goo g = ActualFoos.goo.getAssociatedClass().getConstructor().newInstance();

tldr公司;有一种方法可以用不同的系统来做你想做的事情,但不能完全用你的系统来做你想做的事情。

相关问题