1. 程式人生 > >Java泛型 extends,super和萬用字元的理解

Java泛型 extends,super和萬用字元的理解

1.java泛型的特點

通常情況下,一個編譯器處理泛型有兩種方式:
     1.Code specialization。在例項化一個泛型類或泛型方法時都產生一份新的目的碼(位元組碼or二進位制程式碼)。例如,針對一個泛型list,可能需要 針對string,integer,float產生三份目的碼。
     2.Code sharing。對每個泛型類只生成唯一的一份目的碼;該泛型類的所有例項都對映到這份目的碼上,在需要的時候執行型別檢查和型別轉換。
     C++中的模板(template)是典型的Code specialization實現。C++編譯器會為每一個泛型類例項生成一份執行程式碼。執行程式碼中integer list和string list是兩種不同的型別。這樣會導致程式碼膨脹(code bloat),不過有經驗的C++程式設計師可以有技巧的避免程式碼膨脹。
     Code specialization另外一個弊端是在引用型別系統中,浪費空間,因為引用型別集合中元素本質上都是一個指標。沒必要為每個型別都產生一份執行程式碼。而這也是Java編譯器中採用Code sharing方式處理泛型的主要原因。
     Java編譯器通過Code sharing方式為每個泛型型別建立唯一的位元組碼錶示,並且將該泛型型別的例項都對映到這個唯一的位元組碼錶示上。將多種泛型類形例項對映到唯一的位元組碼錶示是通過型別擦除(type erasue)實現的。

2.什麼是型別擦除?

    型別擦除指的是通過型別引數合併,將泛型型別例項關聯到同一份位元組碼上。編譯器只為泛型型別生成一份位元組碼,並將其例項關聯到這份位元組碼上。型別擦除的關鍵在於從泛型型別中清除型別引數的相關資訊,並且再必要的時候新增型別檢查和型別轉換的方法。

     型別擦除可以簡單的理解為將泛型java程式碼轉換為普通java程式碼,只不過編譯器更直接點,將泛型java程式碼直接轉換成普通java位元組碼。
     型別擦除的主要過程如下:
     1.將所有的泛型引數用其最左邊界(最頂級的父型別)型別替換。
     2.移除所有的型別引數。

3.extends,super和萬用字元的介紹

 1.extends

        extends不僅可以用來表示繼承一個父類,可以用在泛型類的定義上。表示引數型別繼承自某個類或者實現了某個介面。exte nds和&結合使用可以表示引數型別必須要繼承和實現的型別和介面。注意,extends和&的型別引數中只能有一個類,其餘為介面。用法如下
package generics;


class O<T>{
	T item;
}

class HoldItem<T> {
  T item;
  HoldItem(T item) { this.item = item; }
  T getItem() { return item; }
}


class Colored2<T extends HasColor> extends HoldItem<T> {
  Colored2(T item) { super(item); }
  java.awt.Color color() { return item.getColor(); }
}

class ColoredDimension2<T extends Dimension & HasColor>
extends Colored2<T> {
  ColoredDimension2(T item) {  super(item); }
  int getX() { return item.x; }
  int getY() { return item.y; }
  int getZ() { return item.z; }
}

class Solid2<T extends Dimension & HasColor & Weight>
extends ColoredDimension2<T> {
  Solid2(T item) {  super(item); }
  int weight() { return item.weight(); }
}

public class InheritBounds {
  public static void main(String[] args) {
    Solid2<Bounded> solid2 =
      new Solid2<Bounded>(new Bounded());
    solid2.color();
    solid2.getY();
    solid2.weight();
  }
} ///:~
2.extends,super和?萬用字元一起使用
import java.util.*;

class Fruit {}
class Apple extends Fruit {}
class Jonathan extends Apple {}
class Orange extends Fruit {}
public class GenericsAndCovariance {
  public static void main(String[] args) {
    // Wildcards allow covariance:
    List<? extends Fruit> flist = new ArrayList<Apple>();
    flist=new ArrayList<Orange>();
    //編譯失敗,不能新增任何型別
    //flist.add(new Fruit());
    //flist.add(new Object());
    //flist.add(new Object());
    // We know that it returns at least Fruit:
    Fruit f = flist.get(0);
    List<? super Fruit> list = new ArrayList<Fruit>();   
    list.add(new Apple());//可以   
    list.add(new Fruit());//可以   
    list.add(new Jonathan());
  }
} ///:~</span>
      List<?extends Fruit> flist=new ArrayList<Apple>()表明flist引用的list是Fruit的子類,具體是Apple還是Orange並不知道,所以在使用list.add的型別實際是?extends Fruit,所以不能使用add新增任何物件,包括Object和Fruit物件,因為如果可以,則可通過flist.add((Fruit)new Orange())將Orange物件新增到Apple的List中。get實際上返回的是Object物件然後轉型為Fruit,所以可以使用。     super關鍵字表示所引用的List的是Fruit或者Fruit的父類。所以可以將Oragnge,Apple都新增到list中,因為它們都是Fruit的子型別。再次驗證如下
package generics;

public class Holder<T> {
  private T value;
  public Holder() {}
  public Holder(T val) { value = val; }
  public void set(T val) { value = val; }
  public T get() { return value; }
  public boolean equals(Object obj) {
    return value.equals(obj);
  }	
  public static void main(String[] args) {
    Holder<Apple> Apple = new Holder<Apple>(new Apple());
    Apple d = Apple.get();
    Apple.set(d);
    // Holder<Fruit> Fruit = Apple; // Cannot upcast
    Holder<? extends Fruit> fruit = Apple; // OK
    Fruit p = fruit.get();
    d = (Apple)fruit.get(); // Returns 'Object'
    try {
      Orange c = (Orange)fruit.get(); // No warning
    } catch(Exception e) { System.out.println(e); }
    // fruit.set(new Apple()); // Cannot call set()
    // fruit.set(new Fruit()); // Cannot call set()
    System.out.println(fruit.equals(d)); // OK
  }
} /* Output: (Sample)
java.lang.ClassCastException: Apple cannot be cast to Orange
true
*///:~