1. 程式人生 > >泛型與萬用字元

泛型與萬用字元

泛型

-----------先寫一個ObjectStack類實現棧的操作-----------

class ObjectStack{
    private Object[] elem;
    private int top;
    public ObjectStack(){
        this(10);
    }
    public ObjectStack(int size){
        this.elem = new Object[size];
        this.top = 0;
    }
    public void push(Object value){
        this
.elem[this.top++] = value; } public void pop(){ --this.top; } public Object getTop(){ return this.elem[this.top-1] ; } } public class ObjectStackDemo { public static void main(String[] args) { ObjectStack objectStack = new ObjectStack(); objectStack.
push(10); objectStack.push(66.6); objectStack.push("showLo"); //String str = (String) objectStack.getTop(); //這裡必須強轉,否則會報錯 //對多資料來說很麻煩 //System.out.println(str); } }

雖然ObjectStack對元素資料型別沒有限制, 放任何型別的資料進去都會編譯通過,但是都預設為Object型別,所以當我們得到棧頂元素時,返回的是Object類,獲取該元素時需要進行強制轉換。。。。就很麻煩la。。。。。
所以…我們有了泛型~~

emmmmmm…什麼是泛型呢???
就是----------適用於許多許多的型別。
所以上面的例子用泛型來寫就很nice了!!!

class GenericStack<T> {
    private T[] elem;
    private int top;

    public GenericStack() {
        this(10);
    }

    public GenericStack(int size) {
        //this.elem = new T[size];  error
        this.elem = (T[]) new Object[size];
        this.top = 0;
    }
    public void push(T value){
        this.elem[this.top++] = value;
    }
    public void pop(){
        this.elem[this.top-1] = null;
        --this.top;
    }
    public T getTop(){
        return this.elem[this.top-1];
    }
}

測試

public class GenericStackDemo {
    public static void main(String[] args) {
        //想用哪種型別就在建立的時候指定該型別
        GenericStack<Integer> genericStack = new GenericStack<Integer>();
        genericStack.push(10);
        //用指定型別以外的型別則會出現錯誤
        //genericStack.push("ss"); error
        //genericStack.push(10.3); error
        int data = genericStack.getTop();
        GenericStack<Double> genericStack1 = new GenericStack<Double>();
        genericStack1.push(40.3);
        //GenericStack<Integer>[] genericStack3  = new GenericStack<Integer>(); error 
        // 不能new泛型型別的物件陣列
    }
}

泛型概述

  • 通過泛型可以定義型別安全的資料結構,而無需使用實際的資料型別
  • 泛型類和泛型方法具有可重用性、型別安全性和高效性
  • 在泛型型別定義中,必須通過指定尖括號中的型別引數來宣告型別。引數型別不是特定的型別,而是型別佔位符
class GenericStack<T>
T只是一個型別的佔位符,表示GenericStack是一個泛型類
  • 在建立泛型型別的例項物件時,必須指定尖括號的型別,可以是編譯器識別的任何型別(!!!不能為簡單型別)
GenericStack<Integer> genericStack = new GenericStack<Integer>();
GenericStack<Animal> genericStack2 = new GenericStack<Animal>();

泛型的意義

  1. 可以對型別進行自動檢查(並不是替換)在編譯期間進行檢查
  2. 自動對型別進行轉換

泛型是怎麼編譯的呢???
是用了型別的擦除機制,通過向上擦除===》Object類
(在編譯器的編譯期間,把泛型全部擦除為Object型別)

    public static void main(String[] args) {
        GenericStack<Integer> genericStack = new GenericStack<Integer>();
        GenericStack<String> genericStack1 = new GenericStack<String>();
        System.out.println(genericStack);
        System.out.println(genericStack1);

        System.out.println(int.class);
        System.out.println(String.class);
        System.out.println(GenericStack.class);
    }

在這裡插入圖片描述

寫一個通用的演算法,找到陣列當中的最大值

class GenericAlg<T extends Comparable<T>>{
    public T findMaxVal(T[] array) {
        T max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i].compareTo(max) > 0) {
                max = array[i];
            }
        }
        return max;
    }
}

測試程式碼

public class Test2 {
    public static void main(String[] args) {
        Integer[] array ={1,2,3,4,5};
        GenericAlg<Integer> genericAlg = new GenericAlg<Integer>();
        System.out.println(genericAlg.findMaxVal(array));

        Double[] array1 = {3.6,4.8,5.9,6.6,0.9};
        GenericAlg<Double> genericAlg1 = new GenericAlg<Double>();
        System.out.println(genericAlg1.findMaxVal(array1));
    }
}

//5
//6.6

泛型方法

//泛型的上界-----》T extends Comparable<T>
//泛型沒有下界
class GenericAlg2{
    public static<T extends Comparable<T>> T findMaxValu(T[] array){
        T max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i].compareTo(max) > 0) {
                max = array[i];
            }
        }
        return max;
    }
}

public class Test2 {
    public static void main(String[] args) {
        Integer[] array ={1,2,3,4,5};
        Double[] array1 = {3.6,4.8,5.9,6.6,0.9};
        //T會通過實參的型別推演出泛型型別
        System.out.println(GenericAlg2.findMaxValu(array));
        System.out.println(GenericAlg2.findMaxValu(array1));
        System.out.println(GenericAlg2.<Integer>findMaxValu(array)); //也可在前面指明其型別
    }
//5
//6.6

記憶體洩漏

// An highlighted block
var foo = 'bar';

泛型的坑

  • 不能new泛型型別的陣列
    • eg: new T[];
  • 不能new泛型型別的物件
    • eg: T obj = new T();
  • 不能new 泛型型別的物件陣列
    • eg: Object[] obj = new GenericStack[10];
  • 不能用簡單型別作為泛型型別的引數
  • 一定記得加<泛型型別的引數>,否則就是Object
    • 不能 GenericStack genericStack3 = new GenericStack();
    • 應該 GenericStack genericStack = new GenericStack();
  • 在靜態方法中不能使用泛型型別的引數,因為靜態方法不依賴物件,如果不依賴物件,就不知道這個T是什麼型別,編譯時就不能進行型別檢查

萬用字元(?)

通過擦除機制 ------》 Object
寫一個通用的演算法:列印集合ArrayList內的所有元素

class GenericAlg1{
    public static <T> void printList(ArrayList<T> list){
        for (T obj : list){
            System.out.println(obj + " ");
        }
        System.out.println();
    }
}

public class GenericDemo {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        arrayList.add(10);
        arrayList.add(20);
        arrayList.add(30);
        GenericAlg1.printList(arrayList);
    }
}

在這裡插入圖片描述

Integer 繼承 Number , Number 繼承 Object
但是 ArrayList ArrayList ArrayList 三者間不能構成繼承關係

class GenericAlg1{
    
    public static void printList(ArrayList<?> list) {
        for (Object obj : list) {
            System.out.println(obj + " ");
        }
        System.out.println();
    }
}

public class GenericDemo {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        arrayList.add(10);
        arrayList.add(20);
        arrayList.add(30);
        GenericAlg1.printList(arrayList);
        
       // ArrayList<Object> arrayList1 = new ArrayList<Integer>();  error,不構成繼承關係
    }
}

萬用字元的應用

寫一個演算法找集合當中的最大值
在這裡插入圖片描述

比較時報錯,應該怎麼辦呢???
解決辦法如下

class GenericAlg2{
    public static <T extends Comparable<T>> T findMaxVal(ArrayList<T> list){
        T max = list.get(0);
        for (int i = 0; i < list.size(); i++) {
            if (max.compareTo(list.get(i)) < 0){
                max = list.get(i);
            }
        }
        return max;
    }
}

萬用字元的上下界

可以使用 extends 為萬用字元限定上界或使用 super 為萬用字元限定下界
<? extends 基類>      //? 限定為指定類或其派生類
<? super 派生類>      //? 限定為指定類或其基類
  • 萬用字元的上界主要用來寫入
  • 萬用字元的下界主要用來讀取
class GenericAlg2{
    //萬用字元的下界:找到是不是有T的基類實現了Comparable介面
    public static <T extends Comparable<? super T>> T findMaxVal1(ArrayList<T> list){
        T max = list.get(0);
        for (int i = 0; i < list.size(); i++) {
            if (max.compareTo(list.get(i)) < 0){
                max = list.get(i);
            }
        }
        return max;
    }
    //萬用字元的上界 ArrayList<? extends T>
    public static <T extends Comparable<T>> T findMaxVal(ArrayList<? extends T> list){
        T max = list.get(0);
        for (int i = 0; i < list.size(); i++) {
            if (max.compareTo(list.get(i)) < 0){
                max = list.get(i);
            }
        }
        return max;
    }
}
class Person implements Comparable<Person>{//不實現介面main函式呼叫方法時會報錯
    private String name;
    public Person(String name){
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }

    @Override
    public int compareTo(Person o) {
        return name.compareTo(o.name);
    }
}

class Student extends Person{
    private int age;
    public Student(String name,int age){
        super(name);
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
}

public class GenericDemo {
    public static void main(String[] args) {
        ArrayList<Person> arrayList = new ArrayList<Person>();
        arrayList.add(new Person("ss"));
        arrayList.add(new Person("qq"));
        System.out.println(GenericAlg2.findMaxVal(arrayList));

        ArrayList<Student> arrayList1 = new ArrayList<Student>();
        arrayList1.add(new Student("ss",8));
        arrayList1.add(new Student("qq",18));
        System.out.println(GenericAlg2.findMaxVal(arrayList1));
        System.out.println(GenericAlg2.findMaxVal1(arrayList1));
    }
}

在這裡插入圖片描述