Java泛型

一.爲什麼會使用泛型

從Java程序設計語音1.0以來,變化最大部分就是泛型.泛型正是我們需要的程序設計手段.使用泛型機制編寫的程序代碼要比哪些雜亂的使用Object變量,然後再進行強制類型轉換的代碼具有更好的安全性和可讀性.

在Java中增加泛型類之前,泛型程序設計就是用繼承實現的.ArrayList類只維護一個Object引用的數組.類似於下面的代碼:

public class Arraylist{
		private Object [] elementData;
		...
		public Object get(int i){...}
		public void add(Object o){...}
	}

這樣實現會有兩個問題:①單獲取一個值時必須進行強制類型轉換.②可以向數組列表中添加任何類的對象,編譯和運行都不會出錯,然而在其他地方,將get的結果強制轉換成其它類型,程序就會報錯.

泛型提供了一個更好的解決方案,參數類型(Type Pararmeters).ArrayList類有一個類型參數用來指示元素的類型:

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

這使得代碼有更好的可讀性,人們一看就知道這個數組列表中包含的是String對象.
 

二.泛型類

首先定義一個簡單的sutdent類

public class Student {
	
	private String major;
	
	public Student(String major) {
		this.major = major;
	}

	public String getMajor() {
		return major;
	}

	public void setMajor(String major) {
		this.major = major;
	}

}

這樣做的一個壞處是Student裏面現在只能裝入String類型的元素,今後如果我們需要裝入Integer等其他類型的元素,還必須要另外重寫一個Student,代碼得不到複用,使用泛型可以很好的解決這個問題。

public class Student<T> {
	
	private T major;

	public T getMajor() {
		return major;
	}

	public void setMajor(T major) {
		this.major = major;
	}
}

這樣我們的Student就可以複用,使用時只要將T換成想要的類型.

三.泛型方法

聲明一個泛型方法只要在返回類型前面加上一個類型變量<T>就可以了:

public class Test {
    public static <T> boolean compare(T a,T b) {
        return a > b;
    }
}
public class Pair<T> {
    private T value;
    public Pair(T value) {
        this.value = value;
    }
    public void setValue(T value) { this.value = value; }
    public T getValue() { return value; }
}

對泛型方法的調用如下:

Pair<Integer> a = new Pair<>(1);
Pair<Integer> b = new Pair<>(2);
boolean same = Test.compare(p1, p2);

在泛型接口、泛型類和泛型方法的定義過程中,我們常見的如T、E、K、V等形式的參數常用於表示泛型形參,由於接收來自外部使用時候傳入的類型實參。那麼對於不同傳入的類型實參,生成的相應對象實例的類型是不是一樣的呢?

public class GenericTest {

    public static void main(String[] args) {

        Pair<Number> a = new Pair<>(1);
        Pair<Integer> b = new Pair<>(2);

        System.out.println("a class:" + a.getClass());      // com.test.Pair
        System.out.println("b class:" +b.getClass());        // com.test.Pair
        System.out.println(a.getClass() == b.getClass());    // true

    }

}

由此,我們發現,在使用泛型類時,雖然傳入了不同的泛型實參,但並沒有真正意義上生成不同的類型,傳入不同泛型實參的泛型類在內存上只有一個,即還是原來的最基本的類型(本實例中爲Pair),當然,在邏輯上我們可以理解成多個不同的泛型類型。

究其原因,在於Java中的泛型這一概念提出的目的,導致其只是作用於代碼編譯階段,在編譯過程中,對於正確檢驗泛型結果後,會將泛型的相關信息擦出,也就是說,成功編譯過後的class文件中是不包含任何泛型信息的。泛型信息不會進入到運行時階段。

對此總結成一句話:泛型類型在邏輯上看以看成是多個不同的類型,實際上都是相同的基本類型。

四.通配符

對於上面第三點代碼中的泛型方法,現在做如下調用:

Pair<Number> a = new Pair<>(1);
Pair<Integer> b = new Pair<>(2);
getData(a);
getDate(b);

public static void getData(Pair<Number> data) {
         System.out.println("data :" + data.getData());
}

上面的代碼在運行getData方法的時候會報錯,原因是因爲在泛型中Pair<Number> a 和Pair<Integer>,是不能等同,也不能視爲子父類關係的.對此我們可以這樣思考,如果把它們視爲子父類,那麼通過getData()方法取出的數據是什麼類型呢?

那麼這種情況應該怎麼解決呢?通配符 <?> 就應運而生了,注意了,此處是類型實參,而不是類型形參!且Box<?>在邏輯上是Pair<Integer>、Pair<Number>...等所有Box<具體類型實參>的父類。

Pair<Number> a = new Pair<>(1);
Pair<Integer> b = new Pair<>(2);
getData(a);
getDate(b);

public static void getData(Pair<?> data) {
         System.out.println("data :" + data.getData());
}

上面使用通配符這段代碼就不會有問題了.

五.類型變量的限定

在通配符的代碼上我們做如下修改:

Pair<Number> a = new Pair<>(1);
Pair<Integer> b = new Pair<>(2);
Pair<String> c = new Pair<>(2);
getData(a);
getDate(b);
getDate(c); //1

public static void getData(Pair<?> extends Number data) {
         System.out.println("data :" + data.getData());
}

上面的代碼在 1 處會報錯,原因是getData方法限定了泛型類型只能爲Number類的子類,這就是類型通配符上限.用Pair<?> extends Number表示.

本文參考地址:https://www.cnblogs.com/lwbqqyumidi/p/3837629.html

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