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 t = (Transform)_map.get(b.getClass()); return t.toA(b); } 

当编译器在其类型中遇到带有通配符的变量时,它知道必须有一些T匹配发送的内容。它不知道T代表什么类型,但它可以为该类型创建一个占位符来引用必须是T的类型。 该占位符称为捕获该特定通配符。

我不知道为什么编译器无法弄清楚capture capture可以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 ”表示其他内容。

这意味着存在可能是XX的任何子类型的未知类型。 这不是一回事。

例:

 public static Transform getSomething(){ // My custom method return new Transform(); // <-- It does not accept BaseB, only MySubclassOfB } public static BaseA transform(BaseB b){ Transform 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> _map = new HashMap, Transform>(); static { _map.put(DerB.class, new DerAtoDerB()); } public static  BaseA transform(B b){ Transform t = _map.get(b.getClass()); return t.toA(b); } } 

我对您的代码所做的更改如下:

  1. DerAtoDerB现在实现Transform ,而不是Transform
  2. Map的第二个通用参数的类型已更改为Transform Transform Transform – 注意使用super而不是extends – 它是相反的类型绑定。

Javagenerics的主要概念:如果ChildClass扩展ParentClass,它并不意味着YourApi 扩展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 t = (Transform) _map.get(b.getClass());