![](/img/trans.png)
[英]Generics with Wildcards (Map<? extends A, List<? extends B>>)
[英]Java generics: <B extends BaseB> does not match <? extends BaseB>
我有两个同构类型的层次结构。 第一个的基本类型是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,B> {
A toA (B b);
}
public class DerAtoDerB implements Transform<DerA,DerB> {
DerA toA (DerB b){...}
}
public class Transformations {
private static Map<Class<?>, Transform<? extends BaseA, ? extends BaseB>> _map =
new HashMap<>();
static {
_map.put(DerB.class, new DerAtoDerB());
}
public static <B extends BaseB> BaseA transform(B b){
Transform<? extends BaseA, ? extends BaseB> t = _map.get(b.getClass());
return t.toA(b); // Compile error: Transform<A,B#2> cannot be applied to given types
}
为什么<B extends BaseB>
与<? extends BaseB>
不兼容<? extends BaseB>
<? extends BaseB>
? 此外,如果我尝试实现这样的静态转换方法:
public static BaseA transform(BaseB b){
Transform<? extends BaseA, ? extends BaseB> t = _map.get(b.getClass());
return t.toA(b); // Compile error: Transform<A,B> cannot be applied to given types
}
我得到一个编译错误: Transform<A,B> cannot be applied to given types
任何人都可以解释我对Generics的错误吗?
问题是在transform
方法中,编译器不能知道类型参数B extends BaseB
并且从map获得的Transform
类中的第二个类型参数( ? extends BaseB
)实际上代表了BaseB
的相同子类。 没有什么能阻止您在地图中存储不兼容的类型:
_map.put(DerB.class, new AnotherDerAtoAnotherDerB()); // the types don't match
您是保证映射中的类型匹配的人,因此您需要通过将编译器转换为正确的类型来告诉编译器:
@SuppressWarnings("unchecked")
public static <B extends BaseB> 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<Class<?>, Transform> _map =
new HashMap<>();
static {
_map.put(DerB.class, new DerAtoDerB());
}
public static<B extends BaseB> 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<MySubclassOfA, MySubclassOfB>(); // <-- 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,B> {
A toA (B b);
}
class DerAtoDerB implements Transform<BaseA,BaseB> {
public DerA toA(DerB b){ return null; }
@Override
public BaseA toA(BaseB baseB) {
return null;
}
}
public class Transformations {
private static Map<Class<?>, Transform<? extends BaseA, ? super BaseB>> _map = new HashMap<Class<?>, Transform<? extends BaseA, ? super BaseB>>();
static {
_map.put(DerB.class, new DerAtoDerB());
}
public static <B extends BaseB> BaseA transform(B b){
Transform<? extends BaseA, ? super BaseB> t = _map.get(b.getClass());
return t.toA(b);
}
}
我对您的代码所做的更改如下:
DerAtoDerB
现在实现Transform<BaseA,BaseB>
,而不是Transform<DerA,DerB>
Map
的第二个通用参数的类型已更改为Transform<? extends BaseA, ? super BaseB>
Transform<? extends BaseA, ? super BaseB>
Transform<? extends BaseA, ? super BaseB>
- 注意使用super
而不是extends
- 它是相反的类型绑定。 Java泛型的主要概念:如果ChildClass扩展ParentClass,它并不意味着YourApi <ChildClass>扩展YourApi <ParentClass>。 例如:
NumberTransform<String, ? extends Number> intTransform = new IntegerTransform<String, Integer>(); // work with Integer numbers only
NumberTransform<String, ? extends Number> longTransform = new LongTransform<String, Long>(); // 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());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.