泛型,即「參數化型態」。
一提到參數,最熟悉的就是定義方法時形式參數(formal parameter, parameter, 參數),然後調用此方法時傳遞實際參數(actual parameter, arguments, 引數)。
那麼參數化型態怎麼理解呢?顧名思義,就是將型態由原來具體的型態參數化,類似於方法中的變數參數,此時型態也定義成形式參數(可以稱之為形式型態參數),然後在使用/調用時傳入具體的型態(實際型態參數)。

泛型的本質是為了參數化型態(在不創建新型態的情況下,通過泛型指定的不同型態來控制形式參數具體限制的型態)。
也就是說在泛型使用過程中,操作的數據型態被指定為一個參數,這種參數型態可以用在類別、介面和方法中,分別被稱為泛型類別(Generic Class)、泛型介面(Generic Interface)、泛型方法(Generic Method)

泛型類別(Generic Class)

在 JAVA 中的泛型相似於 C++ 中的樣板(Template),我們同樣使用尖括號(angle brackets)「<>」來指定參數型態

// 建立一個泛型物件的實例
BaseType obj = new BaseType();

注意:在參數型態中,我們不能使用基礎型態,如
  「int」`「char」、「double」等。

泛型使用實例

package test5;

public class Point<T> {
	T x;
	T y;
	
	public T getX() {
		return x;
	}

	public void setX(T x) {
		this.x = x;
	}

	public T getY() {
		return y;
	}

	public void setY(T y) {
		this.y = y;
	}
}

Java Bean

package test5;

public class Person {
	private String name;
	private Integer age;
	private String gender;
	private String hobe;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public String getHobe() {
		return hobe;
	}
	public void setHobe(String hobe) {
		this.hobe = hobe;
	}
}

主程序

用junit4 來做整個主程式

package test5;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class TestBean {
	Person person = null;
	Point<String> point = null;
	Point<Integer> pointInt=null;
	
	@Before
	public void setUp() throws Exception {
		person = new Person();
		person.setName("phillips");
		person.setAge(40);
		person.setGender("M");
		person.setHobe("music");
	}

	@Before
	public void setUp1() throws Exception {
		point = new Point<String>();
		point.setX("hellow");
	}
	
	@Before
	public void setUp2() throws Exception {
		pointInt = new Point<Integer>();
		pointInt.setX(100);
	}
	
	@Test
	public void test() {
		System.out.println(person.getName());
		System.out.println(person.getAge());
		System.out.println(person.getGender());
		System.out.println(person.getHobe());
	}

	@Test
	public void test1() {
		System.out.println("x:"+point.getX());
	}
	
	@Test
	public void test2() {
		System.out.println("x:"+pointInt.getX());
	}
	
	
	@After
	public void tearDown() throws Exception {
	}
}

輸出結果

phillips
40
M
music
x:hellow
x:100

定義泛型:Point<T>

首先,大家可以看到 Point<T>,即在類名後面加一個尖括號,括號裡是一個大寫字母。這裡寫的是 T,其實這個字母可以是任何大寫字母,大家這裡先記著,可以是任何大寫字母,意義是相同的。

泛型類別中使用泛型

這個 T 表示繼承自 Object 類的任何類別,比如 String、Integer、Double 等等。這裡要注意的是,T 一定是繼承於 Object 類別的。為方便起見,大家可以在這裡把 T 當成 String,即 String 在類別中怎麼用,那 T 在類別中就可以怎麼用!所以下方的:定義變數、作為返回值、作為參數傳入的定義就很容易理解了。

// 定義變數
private T x;

// 作為返回值
public T getX(){
  return x;
}


// 作為參數傳入
public void setX(T x){
  this.x = x;
}

外部類別使用泛型類別

下方為泛型類別的用法:

//IntegerPoint使用
Point p1 = new Point();
p1.setX(new Integer(100));
System.out.println(p1.getX());


//FloatPoint使用
Point p2 = new Point();
p2.setX(new Float(100.12f));
System.out.println(p2.getX());

首先,是建立一個實例。

這裡與普通建立物件實例的不同之點在於,普通建立物件實例是這樣的:Point p = new Point();

但,因為我們構造類別時,是這樣寫的 class Point,所以在使用的時候也要在 Point 後加上型態來定義 T 代表的意義。建立物件實例如下:

//IntegerPoint使用
Point p1 = new Point();

//FloatPoint使用
Point p2 = new Point();

尖括號中,你傳進去的是什麼,T 就代表什麼型態。
這就是泛型的最大作用,我們只需要考慮邏輯實現,就能拿給各種類別來使用。

總結

使用泛型的優勢有「不用強制轉型」和「使用型態不對時,在編譯時期會報錯」。

使用型態參數時,使用有意義的字母可提高可讀性。

可使用「限制泛型可用型態(T extends someClass)」規範可使用的物件實例型態,排除不需要的型態。

可在宣告物件變數時使用「型態通配字元(?)」,方便切換不同泛型物件實例;但會有一些副作用。

參考來源: https://ethan-imagination.blogspot.com/2018/11/javase-gettingstarted-017.html

Steven玄

謝謝您觀看本站內容!! 😅 西元93年台灣男,軟體前、後、資料庫工程師 和 多元收入實踐,程式設計、網站系統規劃、商業策略分析規劃、多元收入研究,目前在網站開發公司擔任工程師。

發佈留言