具有泛型和动态类类型的返回类型转换

时间:2018-07-26 19:43:57

标签: java class generics casting

我试图避免显式地从方法中强制返回。

如果我在编译时静态地指定类,那么我所拥有的效果很好,但是我更希望在运行时从枚举类型中获取该类。

public enum Type {

    SOME_TYPE(Clazz.class),
    ;

    private Type(Class<?> clazz) {
        this.clazz = clazz;
    }

    private final Class<?> clazz;

    public Class<?> getClazz() {
        return this.clazz;
    }
}

public class Foo {

    private Foo() {}

    public static <T> T doSomething(Class<T> clazz, String input) {
        // ...
        final Object obj = someProcess(input);

        return clazz.cast(obj);
    }
}

public class Bar {

    public void stuff() {

        // does not work without explicit casting to SomeClass
        // compiler error
        Clazz sc = Foo.doSomething(Type.SOME_TYPE.getClazz(), someInputData);

        // this does work, without an explicit cast
        Clazz sc2 = Foo.doSomething(Clazz.class, someInputData);
    }
}

我感觉这不可能动态地进行,因为编译器无法确定getClazz()方法将返回什么类。

我该如何做?

2 个答案:

答案 0 :(得分:2)

  

我试图避免显式地从方法中强制返回。

当前,编译器无法从中推断任何内容

Type.SOME_TYPE.getClazz()

因为此表达式引用了用通配符键入的Class

private final Class<?> clazz;

public Class<?> getClazz() {
    return this.clazz;
}

编译器如何猜测需要将其强制转换为SomeClass

枚举中定义的Class绝对是泛型。
我认为这种设计不适合您的需求。
如果要避免任何强制转换,请替换

Type.SOME_TYPE.getClazz()

通过将要显示的类显式地返回给方法的方法:

SomeClass.class

例如

SomeClass sc =  Foo.doSomething(SomeClass.class, someInputData); 

答案 1 :(得分:1)

泛型允许您省略强制转换如果,编译器可以证明该值将是该操作的兼容类型。

在您工作的sc2示例中,编译器可以看到您正在为Class类传递Class对象。 doSomething承诺将返回其类型与类型标记相匹配的对象(编译器也会对此进行验证),因此可以证明doSomething在这种情况下将返回一个Class实例;不需要演员。

但是,由于动态选择Class实例的性质,编译器无法证明类型将与此分配兼容。就编译器所知,您可能会加载代码,这些代码将更改将提供的Class作为类型标记,并更改返回的内容。由于可能存在不兼容的分配,这将引发异常,因此Java规则需要显式强制转换。

从逻辑上讲,实际上没有办法完全按照设计来完成您要问的事情。

在不了解您要完成的目标的情况下很难提出替代方案,因为任何替代方法都会有局限性,我不知道哪种替代方法可以接受。当然,最简单的情况是是否存在(或可能)有用的通用基类或接口来处理您可能返回的所有事物;但我想如果是这样的话,您就不会考虑这种设计。