2014-10-09 130 views
5

我有两个同构类型层次结构。第一个基本类型是BaseA,第二个基本类型是BaseB。我知道如何将BaseB的任何子类的任何对象转换为其相应的BaseA子类型。我想实现一个方法,它使用BaseB类型的对象来确定它的类并构造相应的BaseA子类型的对象。示例代码:Java泛型:<B extends BaseB>不匹配<?扩展BaseB>

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

任何人都可以解释我什么,我做错了泛型?

+0

第一个答案可能是你http://stackoverflow.com/questions/16449799/how-do-generics-of-generics-work – aalku 2014-10-09 11:31:18

回答

-2

Java泛型的主要概念:如果ChildClass继承父类,那么这并不意味着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()); 
+0

这怎么回答这个问题有用吗?这应该是一个评论。 – 2014-10-09 10:58:03

+0

实际上我并没有试图这样做,因为Transform的具体实现是由参数类决定的,我不会将Integer传递给期望Long的东西。 – egelev 2014-10-09 11:00:56

+0

你写了“Transform <?extends BaseA,?extends BaseB> t = ...”。部分“扩展BaseB”意味着它可以是BaseB的任何子类型。它可以是DerB,FooB,LambdaB等......然后你将具体的“B b”传递给变压器,从编译器的角度来看,变压器可以是变压器<..., DerB>,变压器<..., FooB>等 – ursa 2014-10-09 11:16:32

0

当编译器遇到一个变量,其类型通配符它知道一定有一些牛逼匹配什么被送往它不知道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); 
    } 
} 
+1

请勿将原始类型与仿制药混用。必须有一个更清洁的解决方案。 :) – 2014-10-09 11:02:53

0

表示未知类型。

当一个变量是X类型的,你可以将其指定类型XX但是任何亚型的值“? 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或什么,但我示出一个例子,其中它没有。

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 - 这是相反的类型绑定。
2

的问题是,在transform方法编译器不能知道类型参数B extends BaseB并在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); 
} 
相关问题