Java泛型:<b extends =“”baseb =“”>与<! - 不匹配?扩展BaseB - > </b>

时间:2014-10-09 10:06:24

标签: java generics

我有两个同构类型的层次结构。第一个的基本类型是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>不兼容?此外,如果我尝试实现这样的静态转换方法:

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的错误吗?

5 个答案:

答案 0 :(得分:2)

问题是在transform方法中,编译器无法知道类型参数B extends BaseBTransform类中的第二个类型参数(? 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);
}

答案 1 :(得分:0)

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

我不知道为什么编译器无法确定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);
    }
}

答案 2 :(得分:0)

表示未知类型。

当变量的类型为 X 时,您可以为其指定类型为 X 的值或 X 的任何子类型,但是&#34; ? extends X&#34;意味着别的东西。

这意味着有一种未知类型可能 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或者是什么,但是我展示了它没有的例子。

答案 3 :(得分:0)

这件事编译:

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);
    }
}

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

  1. DerAtoDerB现在实施Transform<BaseA,BaseB>,而不是Transform<DerA,DerB>
  2. Map的第二个通用参数的类型已更改为Transform<? extends BaseA, ? super BaseB> - 请注意使用super代替extends - 它是相反的类型范围

答案 4 :(得分:-2)

Java泛型的主要概念:如果ChildClass扩展ParentClass,它并不意味着YourApi&lt; ChildClass&gt;扩展YourApi&lt; ParentClass&gt;。 E.g:

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());