簡體   English   中英

Java泛型: <B extends BaseB>不匹配 <? extends BaseB>

[英]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 ”是指別的東西。

這意味着有一個未知的類型,其可以是XX的任何亞型。 這不是一回事。

例:

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

我對您的代碼所做的更改如下:

  1. DerAtoDerB現在實現Transform<BaseA,BaseB> ,而不是Transform<DerA,DerB>
  2. 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM