Java不可不知的泛型使用

前面的文章:java

本文介紹了Java的泛型的基本使用。數組

1. 爲何使用泛型

看下面一個例子:ide

爲了說明問題,本類寫的儘可能簡陋,請把目光主要放在類型上。函數

/**
 * @author Xing Xiaoguan (xingrenguanxue)
 */

public class MyArrayList {
    private int[] elementData;
    private int size = 0;

    public MyArrayList(int capacity) {
        elementData = new int[capacity];
    }
    
	//向數組中添加元素
    public void add(int i) { 
        if (size == elementData.length) {
            throw new IndexOutOfBoundsException("數組已滿");
        }
        elementData[size++] = i;
    }
    
	//從數組中根據下標獲取元素
    public int get(int index) { 
        if (index < 0 || index > size - 1) {
            throw new IndexOutOfBoundsException("超出範圍");
        }
        return elementData[index];
    }

    @Override
    public String toString() {
        return "MyArrayList{" +
                "elementData=" + Arrays.toString(elementData) +
                '}';
    }
}

該類很簡單:有兩個成員變量,elementData是一個數組,size是數組中元素的數量。addget方法能添加和獲取元素。測試

下面測試一下:code

public class Test {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList(4);
        myArrayList.add(111); //向數組中添加3個int元素
        myArrayList.add(222);
        myArrayList.add(333);
        int i = myArrayList.get(0); //獲取
        System.out.println(i);
		//以上正常運行
        myArrayList.add("行小觀"); //添加一個String元素,類型不匹配,報錯
    }
}

向數組中添加3個int類型的元素並能獲取,這沒問題。對象

可是若是咱們的場景再也不須要int類型的元素,而是須要String類型的,那怎麼辦?繼承

很顯然,繼續使用該類會報錯,報錯的緣由很簡單:咱們向數組中添加的元素是String類型的,而數組和方法參數類型是int類型。接口

此時,就得須要再寫一份代碼,該份代碼較以前的並沒有大修改,只是把int改成String。若是場景繼續變怎麼辦?那就再寫一份新代碼!ci

這樣太麻煩了!有沒有解決辦法?有!

咱們知道,Object類是全部類的父類,Object類型的變量可以引用任何類型的對象。因此能夠將類型改成Object

/**
 * @author Xing Xiaoguan (xingrenguanxue)
 */

public class MyArrayList {
    private Object[] elementData; 
    private int size = 0;

    public MyArrayList(int capacity) {
        elementData = new Object[capacity];
    }

    public void add(Object o) { //向數組中添加元素
        if (size == elementData.length) {
            throw new IndexOutOfBoundsException("數組已滿");
        }
        elementData[size++] = o;
    }

    public Object get(int index) { //從數組中獲取元素
        if (index < 0 || index > size - 1) {
            throw new IndexOutOfBoundsException("超出範圍");
        }
        return elementData[index];
    }

    @Override
    public String toString() {
        return "MyArrayList{" +
                "elementData=" + Arrays.toString(elementData) +
                '}';
    }
}

再測試一下:

public class Test {
    public static void main(String[] args) {
        //myArrayList 給int元素使用
        MyArrayList myArrayList = new MyArrayList(4);
        myArrayList.add(111); //向數組中添加3個int元素
        myArrayList.add(222);
        myArrayList.add(333);

        int i = (int) myArrayList.get(0); //獲取
        System.out.println(i);

        //myArrayList 給String元素使用
        MyArrayList myArrayList1 = new MyArrayList(4);
        myArrayList1.add("aaa");
        myArrayList1.add("bbb");
        myArrayList1.add("ccc");

        String str = (String) myArrayList1.get(1);
        System.out.println(str);
    }
}

發現能夠向數組中添加和獲取intString類型的元素,這證實該類的數組和方法同時對各類類型的數據都有用,沒必要再添加額外代碼。

可是這樣又出現了兩個問題:

第一:從數組中獲取元素時,須要強制轉換類型才行。

int i = (int) myArrayList.get(0);

第二:同一個數組能夠添加各類類型的元素。

myArrayList.add(111); //int類型
myArrayList.add("222"); //String類型
myArrayList.add(true); //布爾類型

這就致使了當咱們從數組中獲取某個元素時,很難知道它的確切類型,每每會強轉類型失敗。

int i = (int)myArrayList.get(1); //原本是String類型的值,但我提早不知道,拿int變量接收,報錯

那這個問題有沒有解決辦法呢?

有!用泛型!

2. 泛型類

使用泛型改造MyArrayList

/**
 * @author Xing Xiaoguan (xingrenguanxue)
 */

public class MyArrayList <T> {
    private T[] elementData;
    private int size = 0;

    public MyArrayList(int capacity) {
        elementData = (T[]) new Object[capacity];
    }

    public void add(T o) { //向數組中添加元素
        if (size == elementData.length) {
            throw new IndexOutOfBoundsException("數組已滿");
        }
        elementData[size++] = o;
    }

    public T get(int index) { //從數組中獲取元素
        if (index < 0 || index > size - 1) {
            throw new IndexOutOfBoundsException("超出範圍");
        }
        return elementData[index];
    }

    @Override
    public String toString() {
        return "MyArrayList{" +
                "elementData=" + Arrays.toString(elementData) +
                '}';
    }
}

測試:

public class Test {
    public static void main(String[] args) {
        //myArrayList 給int元素使用
        MyArrayList<Integer> myArrayList = new MyArrayList<>(4);
        myArrayList.add(111); //向數組中添加3個int元素
//        myArrayList.add("222"); //添加非Integer元素報錯

        int i = myArrayList.get(1); //無需強制轉型
        System.out.println(i);  
    }
}

通過改造,咱們把MyArrayList類改成了一個泛型類,它是一個具備多個類型變量的類。

泛型類的聲明方式:引入一個類型變量,如T,而後使用<>將其括起來,放在類名後。

public class MyArrayList <T> {
    //......
}

如何理解類型變量?它就相似於數學中函數中的變量x,用來代替具體的值:

f(x) = 3x + 1

類型變量的名稱能夠隨便取,通常使用大寫字母表示,好比E、K、V、T等。

泛型類中的成員變量、方法參數和返回值的類型都使用類型變量代替:

private T[] elementData;

public void add(T o) {
    //.......
}

public T get(int index) {
	//......
}

固然,一個泛型類能夠有多個類型變量:

public class MyClass <K, V> {
    //......
}

當咱們須要實例化泛型類時,就使用具體的類型來替換類型變量(T):

MyArrayList<Integer> myArrayList = new MyArrayList<>(4);

該過程就至關於向數學函數中代入數值:

f(3) = 3*3+1 = 10

3. 泛型方法

當咱們聲明瞭一個泛型類後,能夠很天然地在類內部使用泛型方法。

其實,當類是普通類時,咱們仍然可以使用泛型方法。下面是一個例子:

/**
 * @author Xing Xiaoguan (xingrenguanxue)
 */

public class PrinterVar {

    //該方法接收一個T類型的變量,打印並返回該變量
    public <T> T print(T var) {
        System.out.println(var);
        return var;
    }

    public static void main(String[] args) {
        PrinterVar printerVar = new PrinterVar();
        String var = printerVar.print("aa");//String類型
        Integer var1 = printerVar.print(12);//int類型
        System.out.println(var + " " + var1);
    }
}

4. 關於我

點擊這裏認識我 。 (^o^)/

相關文章
相關標籤/搜索