使用通配符转换通用 class 的 Class 实例
Casting Class instance of an generic class using wildcards
我目前真的无法理解这里发生的事情。我有以下(最小)代码:
public class SillyCast {
interface B {}
interface D<T extends B> {}
class C<T extends D<?>> {}
class A<T extends B> extends C<D<T>> {}
List<Class<? extends C<?>>> list = new ArrayList<>();
void m() {
list.add((Class<? extends C<?>>) A.class);
}
}
在 Eclipse 中编译(和 运行)这段代码时,一切都按预期工作,但是当从命令行(Oracle JDK)执行时,我在 期间收到以下错误编译:
error: incompatible types: Class<A> cannot be converted to Class<? extends C<?>> list.add((Class<? extends C<?>>) A.class);
我知道 Oracle JDK 的行为并不总是与 Eclipse JDT 完全相同,但这看起来很奇怪。
如何将 A.class
的实例添加到我的 ArrayList 中? 直觉上这似乎是可行的。
为什么 Oracle JDK 和 Eclipse JDT 对此转换有不同的看法?为什么 Oracle JDK 在执行此转换时遇到问题。
起初我认为这可能是一个错误,但我在不同的 Java 版本(8 和 11)上测试了这个问题,所有版本都出现了这个问题。此外,这种演员表似乎太“简单”了,因为这可能会在多个版本中被忽视,所以希望通过设计做到这一点。
不确定您要实现的目标,但这很好用:
public class Main{
static interface B {}
static interface D<T extends B> {}
static class C<T extends D<?>> {}
static class A<T extends B> extends C<D<T>>{}
static List<Class<? extends C>> list = new ArrayList<>();
public static void main(String[] args) {
list.add(A.class);
list.add(C.class);
}
}
这真是令人困惑,你想达到什么目的?您正在通过扩展其他接口的接口进行参数化(然后通过 类 扩展由扩展接口的接口参数化的 类 )。这种复杂程度表明它可能需要一种不同的、更简单的方法 :D
编辑:这对你有用吗? (编译运行没有错误):
public static void main(String[] args) {
List<Class<? super A<?>>> list = new ArrayList<>();
list.add(A.class);
list.add(C.class);
}
我可能错了,这有点令人困惑,但据我了解 C<?>
是 C<D<T>>
的超类,因此 List<? extends C<?>>
接受类型为 [=12= 的对象] 及其所有子项(C
的变体由任何类型 T
参数化),这就是为什么在其中粘贴 A
的实例会出错。
A
作为 C
的子类对 List<A>
和 List<C>
没有影响,它们唯一的关系是它们 are children of List<?>.
这就是为什么我认为我们一直运行出错,而A
是一个C<D<T>>
,List<A>
与List<C>
没有关系。我同意,如果保留这种关系,感觉会很直观。
我认为正如@ferrouskid 所指出的,这不起作用的原因可能是,尽管人们普遍认为,C<?>
不是 C<D<?>>
的超类型。
尽管这与其说是真正的解决方案,不如说是一种混淆策略,但我目前的解决方法是通过在转换之前将 A.class
分配给变量来分散 Oracle 编译器的注意力(可能需要 @SuppressWarnings("unchecked")
)
Class<?> aa = A.class;
list.add((Class<? extends C<?>>) aa);
免责声明:这种操作非常危险,因为转换可能会在运行时失败。因此,仅当您对受影响的方法进行了完整的测试覆盖时才执行此操作。
我目前真的无法理解这里发生的事情。我有以下(最小)代码:
public class SillyCast {
interface B {}
interface D<T extends B> {}
class C<T extends D<?>> {}
class A<T extends B> extends C<D<T>> {}
List<Class<? extends C<?>>> list = new ArrayList<>();
void m() {
list.add((Class<? extends C<?>>) A.class);
}
}
在 Eclipse 中编译(和 运行)这段代码时,一切都按预期工作,但是当从命令行(Oracle JDK)执行时,我在 期间收到以下错误编译:
error: incompatible types: Class<A> cannot be converted to Class<? extends C<?>> list.add((Class<? extends C<?>>) A.class);
我知道 Oracle JDK 的行为并不总是与 Eclipse JDT 完全相同,但这看起来很奇怪。
如何将 A.class
的实例添加到我的 ArrayList 中? 直觉上这似乎是可行的。
为什么 Oracle JDK 和 Eclipse JDT 对此转换有不同的看法?为什么 Oracle JDK 在执行此转换时遇到问题。
起初我认为这可能是一个错误,但我在不同的 Java 版本(8 和 11)上测试了这个问题,所有版本都出现了这个问题。此外,这种演员表似乎太“简单”了,因为这可能会在多个版本中被忽视,所以希望通过设计做到这一点。
不确定您要实现的目标,但这很好用:
public class Main{
static interface B {}
static interface D<T extends B> {}
static class C<T extends D<?>> {}
static class A<T extends B> extends C<D<T>>{}
static List<Class<? extends C>> list = new ArrayList<>();
public static void main(String[] args) {
list.add(A.class);
list.add(C.class);
}
}
这真是令人困惑,你想达到什么目的?您正在通过扩展其他接口的接口进行参数化(然后通过 类 扩展由扩展接口的接口参数化的 类 )。这种复杂程度表明它可能需要一种不同的、更简单的方法 :D
编辑:这对你有用吗? (编译运行没有错误):
public static void main(String[] args) {
List<Class<? super A<?>>> list = new ArrayList<>();
list.add(A.class);
list.add(C.class);
}
我可能错了,这有点令人困惑,但据我了解 C<?>
是 C<D<T>>
的超类,因此 List<? extends C<?>>
接受类型为 [=12= 的对象] 及其所有子项(C
的变体由任何类型 T
参数化),这就是为什么在其中粘贴 A
的实例会出错。
A
作为 C
的子类对 List<A>
和 List<C>
没有影响,它们唯一的关系是它们 are children of List<?>.
这就是为什么我认为我们一直运行出错,而A
是一个C<D<T>>
,List<A>
与List<C>
没有关系。我同意,如果保留这种关系,感觉会很直观。
我认为正如@ferrouskid 所指出的,这不起作用的原因可能是,尽管人们普遍认为,C<?>
不是 C<D<?>>
的超类型。
尽管这与其说是真正的解决方案,不如说是一种混淆策略,但我目前的解决方法是通过在转换之前将 A.class
分配给变量来分散 Oracle 编译器的注意力(可能需要 @SuppressWarnings("unchecked")
)
Class<?> aa = A.class;
list.add((Class<? extends C<?>>) aa);
免责声明:这种操作非常危险,因为转换可能会在运行时失败。因此,仅当您对受影响的方法进行了完整的测试覆盖时才执行此操作。