搜尋

首頁  >  問答  >  主體

java - A是B的子类,为什么List<A>就不是List<B>的子类?

如题。为什么会是这样呢?

ringa_leeringa_lee2834 天前976

全部回覆(7)我來回復

  • 迷茫

    迷茫2017-04-17 13:08:55

    注意對比的對象
    A是B的子類別 是A與B在比較
    List<A>List<B>的子類別 是List與List比較
    你可以透過List<? extend b>這樣的定義 來進行限定操作

    回覆
    0
  • ringa_lee

    ringa_lee2017-04-17 13:08:55

    因為都是List類,又沒有繼承關係

    回覆
    0
  • 怪我咯

    怪我咯2017-04-17 13:08:55

    物件的繼承代表了一種‘is-a’的關係,如果兩個物件A和B,可以表達為‘B是A’,則表示B可以繼承A。繼承者也可以理解為是對被繼承者的特殊化,因為它除了具備被繼承者的特性外,還具備自己獨有的個性。

    父類和子類,或稱為基類和衍生類,其中子類繼承父類的所有特性,同時也定義新的特性。

    回覆
    0
  • 巴扎黑

    巴扎黑2017-04-17 13:08:55

    List<A>的子類別是
    class XXX extends List<A>

    回覆
    0
  • ringa_lee

    ringa_lee2017-04-17 13:08:55

    Java裡的泛型是透過 型別擦除 來實現的

    Java中的泛型基本上都是在編譯器這個層次來實現的。在產生的Java字節碼中是不包含泛型中的類型資訊的。使用泛型的時候加上的型別參數,會在編譯器在編譯的時候去掉。這個過程就稱為類型擦除。

    List <A> 和 List <B> 在编译完成以后,实际上指向的是同一份字节码
    并不存在 List <A> 或者 List <B> 这2种类型 ,当然就更谈不上什么子类的问题了.
    

    以下僅供參考 我C++不熟
    你不是跟C++模板搞混了?
    C++的泛型實作方式不同

    在C++中 确实会为 List <A> 和 List <B> 生成2个class
    

    回覆
    0
  • 巴扎黑

    巴扎黑2017-04-17 13:08:55

    因為List<A>.class不成立。
    泛型

    回覆
    0
  • 大家讲道理

    大家讲道理2017-04-17 13:08:55

    一大堆回答都沒講到重點啊。 。我來加點內容。這裡涉及到兩個概念:協變與逆變。 (Covariance vs. Contravariance)

    簡言之,如果List<S>複合型別是協變的,那麼如果ST的子類,則List<S>也是List<T>的子類。如果List<S>是逆變的,結果顛倒,List<T>會變成List<S>的子類別。

    但是Java裡的泛型不實作以上兩種行為的任一種。 。 Java的泛型是不變的(Invariance)。

    為什麼這麼設計呢?先看一個陣列的例子。在Java中,陣列是協變的,於是Integer[]就是Number[]的子類別了。於是我們能寫出這樣的程式碼:

    Integer[] a = new Integer[3];
    Number[] b = a;    // a的类型是Integer[],是Number[]的子类
    b[0] = 3.14;    // 运行时错误
    

    Java的型別安全(Type Safety)的保證已經被破壞了。 Java會把數組的元素應有型別保存起來(Reification),保證能在執行時偵測到這種非法操作。

    假設List是協變的,那麼如下把Float放進Integer的程式碼:

    List<Integer> li = new ArrayList<Integer>(); 
    List<Number> ln = li;    // li的类型是List<Integer>,属于List<Number>的子类
    ln.add(new Float(3.1415));    // 不会有错误
    

    就能運作。而 @dkmeteor 也提到,Java的泛型採用了型別擦除,這樣就沒辦法保證List裡會不會被塞進一個Float,因為在運行時List看到的全都是Object。因此為了防止這類事情發生,Java的泛型是不變的。

    那有沒有辦法在Java裡用上協變或逆變的泛型呢?答案是肯定的,需要在聲明裡加wildcard:

    // 1.协变范例
    List<? extends Number> num = new List<Double>();
    // 2.逆变范例
    List<? super Number> num = new List<Object>();
    

    但是在第一種情況就不能呼叫參數裡帶有?的函數了,例如:

    class Container<E> {
        E data;
        public set(E data) {
            this.data = data;
        }
        public E get(E data) {
            return data;
        }
    }
    
    // 某方法中
    Container<? extends Number> num = new Container<Double>();
    num.set(new Float(3));    // 编译时错误
    

    這裡同樣是為了保證Type Safety。不能把Float傳給Container<Double>

    同理,在逆變的時候就不能呼叫回傳值帶?的函數,除非接受回傳值的變數型別是Object。

    Container<? super Number> num2;
    Number res = num2.get();    // 编译时错误
    

    部分來源:http://www.ibm.com/developerworks/cn/java/j-jtp01255.html

    回覆
    0
  • 取消回覆