我想要一个通用方法,它接受某种类型 T 的对象,以及一个表示该类型的类。最终我打算用它来创建一个 Map<Class<?>, Object>
,我知道每个类都会映射到一个完全属于自己类型的对象;我知道我无法让编译器相信这一点,但我想尽可能多地保持代码的编译时通用安全性。这是一个演示我遇到的问题的最小示例:
public class Example {
public static <T extends Number> void foo(Class<T> c, T x) {
;
}
public static void bar(int x) {
foo(Integer.class, x);
}
public static void baz(Number x) {
foo(x.getClass(), x);
}
}
我可以写 foo
方法没有问题,它有我想要的签名,如果我在编译时确切知道我有什么类型,我可以使用它,如 bar
, 但我不能在任何类型的对象上使用它,正如我在 baz
中尝试的那样: baz
不编译,引用:
Example.java:11: error: method foo in class Example cannot be applied to given types;
foo(x.getClass(), x);
^
required: Class<T>,T
found: Class<CAP#1>,Number
reason: inferred type does not conform to lower bound(s)
inferred: CAP#1
lower bound(s): Number
where T is a type-variable:
T extends Number declared in method <T>foo(Class<T>,T)
where CAP#1 is a fresh type-variable:
CAP#1 extends Number from capture of ? extends Number
我想我理解这里的问题:x.getClass()
返回 Class<? extends Number>
, 它建立了 <? extends Number>
作为T
,但是 x
继续有类型 Number
, 需要 T
成为Number
,因此冲突。当我写这篇文章时,我希望编译器知道 x.getClass()
和 x
确实共享完全相同的T
,但它不知道这一点是有道理的。
那么,我在这里做什么?有没有办法我可以写类似 foo
的东西还有类似 baz
的东西?我应该放弃编译时安全并在运行时进行一些转换吗?有没有更好的方法来实现我的最终目标 Map<Class, Object>
?
最佳答案
根据 the documentation for Object.getClass()
:
The actual result type is
Class<? extends |X|>
where|X|
is the erasure of the static type of the expression on whichgetClass
is called.
注意关于“静态类型的删除”的部分。这意味着,如果你有一个类型变量 T
例如,声明为 <T extends Number>
, 和一个变量 T x
, 然后返回值 x.getClass()
不是 Class<? extends T>
,但是Class<? extends Number>
.如果没有任何不安全的强制转换,这确实让您很难做您想做的事情(诚然,这取决于您到底想做什么)。
但是,您可以将不安全性包含在它自己的函数中。例如,这有效:
public class test {
public static <T extends Number> void foo(Class<T> c, T x) {
;
}
@SuppressWarnings("unchecked")
public static <T> Class<? extends T> getClass2(T x) {
return((Class<? extends T>)x.getClass());
}
public static void bar(int x) {
foo(Integer.class, x);
}
public static void baz(Number x) {
foo(getClass2(x), x);
}
}
关于java - javac 能否推断出将 x.getClass() 和 x 一起使用的正确泛型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36163287/