2014-10-09 63 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); 
} 
相關問題