类<result>无法转换为Class <result <integer>&gt;

时间:2016-09-10 15:03:35

标签: java generics

假设我已将API方法声明为以下

public class Dummy {
    public static class Result<ValueT extends Comparable> {
        public ValueT value;
    }

    public static <ValueT extends Comparable> Result<ValueT> 
            getResult(Class<? extends Result<ValueT>> ofType) throws Exception {
        return ofType.newInstance();
    }
}

现在我想依靠Java编译时类型验证来调用它,并且无法找到正确的语法来执行此操作:

尝试:

getResult(Result<Integer>.class) <-- expected syntax

public static void invokeGetResult() {
    Result<Integer> intResult = getResult(Result<Integer>.class);
}

结果

error: <identifier> expected
  Result<Integer> intResult = getResult(Result<Integer>.class);
                                                        ^

getResult(Result.class) <-- just to try

public static void invokeGetResult() {
    Result<Integer> intResult = getResult(Result.class);
}

结果

error: method getResult in class Dummy cannot be applied to given types;
    Result<Integer> intResult = getResult(Result.class);
                                ^
  required: Class<? extends Result<ValueT>>
  found: Class<Result>
  reason: cannot infer type-variable(s) ValueT
    (argument mismatch; Class<Result> cannot be converted to Class<? extends Result<ValueT>>)
  where ValueT is a type-variable:
    ValueT extends Comparable declared in method <ValueT>getResult(Class<? extends Result<ValueT>>)

getResult((Class<Result<Integer>>)Result.class) <-- just to try

public static void invokeGetResult() {
    Result<Integer> intResult = getResult((Class<Result<Integer>>)Result.class);
}

结果

error: incompatible types: Class<Result> cannot be converted to Class<Result<Integer>>
    Result<Integer> intResult = getResult((Class<Result<Integer>>)Result.class);
                                                                        ^

3 个答案:

答案 0 :(得分:0)

如果传递Class<...>的唯一目的是实例化它,请考虑使用Supplier<...>。它没有这个问题,也没有任何例外。

以下是一个例子:

class SomeClass extends Result<Integer> {...}

public static <T extends Result<?>> T getResult(Supplier<T> constructor) {
   return constructor.get();
}

使用类似:

getResult(SomeClass::new); // Passes the constructor.

答案 1 :(得分:0)

真的不是Class<Result<Integer>>Class个对象在运行时表示可重新构造的类,并且在运行时只有一个Class个对象用于类Result,您可以通过表达式Result.class获取该对象。输入Class<Result>。没有Class个对象代表Result<Integer>Result<String>等。

您可以使用Class<Result>类型的表达式(您从Result.class获得)并在其上执行一系列不安全的转换,将其转换为Class<Result<Integer>>或类似的内容,例如:

`(Class<Result<Integer>>)(Class<?>)Result.class`

但不是不安全。它是不安全的,因为Class的接口具有某些方法,这些方法基于类的运行时类型操作返回T(类Class的类型参数)。例如,Class有一个方法.cast(),它检查传递的对象是否是该类的实例,如果不是,则抛出异常,如果是,则返回对象,类型为{ {1}}。如果您调用T,它将返回Result.class.cast(),并且该方法确实在运行时检查该对象是Result。但是如果在Result类型的表达式上调用.cast(),它将返回类型Class<Result<Integer>>,但是该类在运行时无法检查该事物是Result<Integer>,因为1)这是同一个Result<Integer>类对象,2)通用信息在运行时不存在。因此,您可能会获得可能不是Result的{​​{1}}。

所以基本上,你需要考虑使用这个类对象做什么,以及当你在运行时可以拥有它是一个表示原始对象的类对象时,如何将它作为Result<Integer>是有意义的。输入Result<Integer>

这里有一个方法Class<Result<Integer>>。我想知道你为什么在这里有通配符。您是否尝试让它接受Result的子类?因为如果没有,那么唯一可以传入的是唯一的Class<? extends Result<ValueT>>类对象本身,这意味着参数基本上没有意义,因为它总是可以传入的相同的东西;在这种情况下,你可以摆脱参数,只是做:

Result

如果您要接受Result的子类,那么您假设所有子类都必须具有无参数构造函数,因为您在其上调用public static <ValueT extends Comparable<? super ValueT>> Result<ValueT> getResult() throws Exception { return new Result<ValueT>(); } ,这很糟糕设计。你应该像Jorn Vernee的回答所暗示的那样使用像Result这样的东西。

答案 2 :(得分:-1)

编辑:我不明白原来的意图。这个例子应该适用于你的电话,但它有点hacky并且不那么推荐。

public class Dummy {
    public static class Result<ValueT extends Comparable> {
        public ValueT value;
    }

    public static <ValueT extends Comparable> Result<ValueT>
        getResult(Class<? extends Result<ValueT>> ofType) {
        return null;
    }
}

您可以这样称呼它:

Dummy.Result<Integer> result = Dummy.getResult(new Result<Integer>(){}.getClass());

编译时验证应该适用于此示例,因为您正在创建一个匿名空类,并且可以成功检索它的​​类型信息。

您也可以在评论中建议@Jorn建议进行类型转换,尽管您的编译器会警告您它是“未经检查的强制转换”。