Javagenerics:不匹配
我有两个同构类型的层次结构。 第一个的基本类型是BaseA,第二个的基本类型是BaseB。 我知道如何将BaseB的任何子类的任何对象转换为其对应的BaseA子类型。 我想实现一个方法,它接受BaseB类型的对象确定其类并构造相应的BaseA子类型的对象。 示例代码:
public interface BaseA... public interface BaseB... public class DerA implements BaseA... public class DerB implements BaseB... ... public interface Transform { A toA (B b); } public class DerAtoDerB implements Transform { DerA toA (DerB b){...} } public class Transformations { private static Map<Class, Transform> _map = new HashMap(); static { _map.put(DerB.class, new DerAtoDerB()); } public static BaseA transform(B b){ Transform t = _map.get(b.getClass()); return t.toA(b); // Compile error: Transform cannot be applied to given types }
为什么与
不兼容
? 此外,如果我尝试实现这样的静态转换方法:
public static BaseA transform(BaseB b){ Transform t = _map.get(b.getClass()); return t.toA(b); // Compile error: Transform cannot be applied to given types }
我得到一个编译错误: Transform cannot be applied to given types
任何人都可以解释我对Generics的错误吗?
问题是在transform
方法中,编译器不能知道类型参数B extends BaseB
,而从映射中获取的Transform
类中的第二个类型参数( ? extends BaseB
)实际上代表了BaseB
的相同子类。 没有什么能阻止您在地图中存储不兼容的类型:
_map.put(DerB.class, new AnotherDerAtoAnotherDerB()); // the types don't match
您是保证映射中的类型匹配的人,因此您需要通过将其转换为正确的类型来告诉编译器:
@SuppressWarnings("unchecked") public static BaseA transform(B b) { Transform extends BaseA, B> t = (Transform extends BaseA, B>)_map.get(b.getClass()); return t.toA(b); }
当编译器在其类型中遇到带有通配符的变量时,它知道必须有一些T匹配发送的内容。它不知道T代表什么类型,但它可以为该类型创建一个占位符来引用必须是T的类型。 该占位符称为捕获该特定通配符。
我不知道为什么编译器无法弄清楚capture extends BaseB>
capture extends BaseB>
可以capture> extends BaseB
,也许是类型擦除的东西?
我会这样实现它:
interface BaseA {} interface BaseB {} class DerA implements BaseA {} class DerB implements BaseB {} interface Transform { BaseA toA(BaseB b); } class DerAtoDerB implements Transform { public BaseA toA(BaseB b) { return new DerA(); } } class Transformations { private static Map, Transform> _map = new HashMap<>(); static { _map.put(DerB.class, new DerAtoDerB()); } public static BaseA transform(B b) { Transform t = _map.get(b.getClass()); return t.toA(b); } }
? 意思是未知类型。
当变量是X类型时,您可以为其指定类型X的值或X的任何子类型,但“ ? extends X
”表示其他内容。
这意味着存在可能是X或X的任何子类型的未知类型。 这不是一回事。
例:
public static Transform extends BaseA, ? extends BaseB> getSomething(){ // My custom method return new Transform(); // <-- It does not accept BaseB, only MySubclassOfB } public static BaseA transform(BaseB b){ Transform extends BaseA, ? extends BaseB> t = getSomething(); return t.toA(b); // <--- THIS IS WRONG, it cannot accept any BaseB, only MySubclassOfB }
在这个例子中,编译器不知道是否允许任何BaseB或者什么,但是我展示了一个不存在的例子。
这个东西编译:
package com.test; import java.util.HashMap; import java.util.Map; interface BaseA{} interface BaseB{} class DerA implements BaseA{} class DerB implements BaseB{} interface Transform { A toA (B b); } class DerAtoDerB implements Transform { public DerA toA(DerB b){ return null; } @Override public BaseA toA(BaseB baseB) { return null; } } public class Transformations { private static Map, Transform extends BaseA, ? super BaseB>> _map = new HashMap, Transform extends BaseA, ? super BaseB>>(); static { _map.put(DerB.class, new DerAtoDerB()); } public static BaseA transform(B b){ Transform extends BaseA, ? super BaseB> t = _map.get(b.getClass()); return t.toA(b); } }
我对您的代码所做的更改如下:
-
DerAtoDerB
现在实现Transform
,而不是Transform
-
Map
的第二个通用参数的类型已更改为Transform extends BaseA, ? super BaseB>
Transform extends BaseA, ? super BaseB>
Transform extends BaseA, ? super BaseB>
– 注意使用super
而不是extends
– 它是相反的类型绑定。
Javagenerics的主要概念:如果ChildClass扩展ParentClass,它并不意味着YourApi
NumberTransform intTransform = new IntegerTransform(); // work with Integer numbers only NumberTransform longTransform = new LongTransform(); // work with Long numbers only longTransform.toA((Integer) 1); // you are trying to make this and got compilation error.
为了帮助编译器替换你的t初始化:
Transform extends BaseA, B> t = (Transform extends BaseA, B>) _map.get(b.getClass());