Java進階之泛型

泛型的優點

  1. 泛型類型可以提高可靠性和可讀性
  2. 泛型可以參數化類型
  3. 泛型可以讓我們在編譯時而不是在運行時檢測出錯誤

泛型類或方法允許用戶指定可以和這些類或方法一起工作的對象類型(相容的對象)
泛型類ArrayList、泛型接口Comparable
從JDK1.5開始,Java允許定義泛型類、泛型接口、泛型方法

泛型實例化

Java進階之泛型
泛型就是限制對象的數據類型

泛型的正確使用

舉個栗子吧

創建一個存儲字符串的線性表(ArrayList)

ArrayList<String> list = new ArrayList<>();

現在就只能向該線性表中添加字符串

list.add("a");

如果試圖向其中添加非字符串類型,就會產生編譯錯誤

list.add(new Person("張三",23));

當沒有使用泛型時,編譯通過,運行也通過,即可以添加任何元素,但這樣做在遍歷元素進行相關操作時會產生隱藏的bug。

 
泛型類型必須是引用數據類型,不能使用基本數據類型。

錯誤示範

ArrayList<int> list = new ArrayList<>();

正確示範

ArrayList<Integer> list = new ArrayList<>();
list.add(5);      //自動裝箱

 
使用泛型對數據類型進行限制後,無須類型轉換就可以從一個線性表中獲取一個值,因爲編譯器已經知道了這個元素的類型。

使用泛型前

ArrayList list = new ArrayList();
list.add("Jone");              //自動提升爲Object類型
list.add("Smith");
String s = (String)(list.get(0));//將Object類型轉爲String類型

使用泛型後

ArrayList<Double> list = new ArrayList<>();
list.add(5.5);          //5.5 is automatically converted to new Double(5.5)
list.add(3.0);          //3.0 is automatically converted to new Double(3.0)
Double doubleObject = list.get(0);  //No casting is needing
double d = list.get(1);             //Automatically converted to double

定義泛型類和接口

可以爲類或者接口定義泛型。當使用容器類來創建對象,或者使用容器類或接口來聲明引用變量時,必須指定具體的類型。

利用ArrayList模擬堆棧結構,使用泛型對元素類型進行限制

public class Stack<E>{
        //構造方法
        public Stack(){}

        //創建數組列表,存儲元素的數據類型爲E,需導包alt+shift+O
        private ArrayList<E> list = new ArrayList<>();

        //返回棧中的元素數目
        public int getSize(){
                return list.size();
        }

        //返回棧頂元素
        public E peek(){
                return list.get(getSize() - 1);
        }

        //返回並移除棧頂元素
        public E pop(){
                E o = list.get(getSize() - 1);
                list.remove(getSize() - 1);
                return o;
        }

        //添加一個新元素到棧頂
        public void push(E o){
                list.add(o);
        }

        //如果棧爲空,就返回true
        public boolean isEmpty(){
                return list.isEmpty();
        }

        @Override
              public String toString(){
                return "stack : " + list.toString();
        }
}

若使用LinkedList模擬堆棧結構,可以用getLast()、removeLast()、addLast()方法
上面自定義類的構造方法不是public Stack<E>(){},而是public Stack(){}

泛型可能會有多個參數,應將所有參數一起放在尖括號中,並用逗號分隔開,比如<E1,E2,E3>
可以定義一個類或接口作爲泛型類或者泛型接口的子類型
例如

public final class String
extends Object
implements Serializable, Comparable<String>, CharSequence

泛型方法

可以爲靜態方法定義泛型類型

public clas GenericMethodDemo{
        public static void main(String[] args){
                Integer[] integers = {1,2,3,4,5};
                String[] strings = {"London","Paris","New York","Austin"};

                GenericMethodDemo.<Integer>print(integers);
                GenericMethodDemo.<String>print(strings);
         }
         public static <E> void print(E[] list){
         for(int i = 0;i<list.length;i++){
                 System.out.print(list[i]+" ");
                 System.out.println();
        }
}

爲了聲明泛型方法,將泛型類型<E>置於方法聲明中關鍵字static之後

public static <E> void print(E[] list)

爲了調用泛型方法,需要將實際類型放在尖括號內作爲方法名的前綴。例如,

GenericMethodDemo.<Integer>print(integers);
GenericMethodDemo.<String>print(strings);

簡單調用

print(integers);
print(strings);

 

可以將泛型指定爲另外一種類型的子類型,這樣的泛型類型稱爲受限的。例如下面所示的代碼用以測試兩個幾何對象是否具有相同的面積。受限的泛型類型將E指定爲GeometricObject的泛型子類型。此時必須傳遞兩個GeomericObject的實例來調用equalArea

public class BoundedTypeDemo{
    public static void main(String[] args){
        Rectangle rectangle = new Rectangle(2,2);
        Circle circle = new Circle(2);
        System.out.println("Same area?" + equalArea(rectangle,circle));
    }
    public static <E extends GeometricObject> boolean equalArea(
            E object1,E object2){
        return object1.getArea()==object2.getArea();
    }
}

非受限泛型類型<E>等同於<E extends Object>
爲了定義一個類爲泛型類型,需要將泛型類型放在類名之後,例如,GenericStack
爲了定義一個方法爲泛型類型,要將泛型類型放在方法返回類型之前,例如,void max(E o1,E o2)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章