泛型
如何理解什麼是泛型呢?
1
2
3
4
5
int i;
i = 100;
i = 55;
i = 22;
i是變數。
以上等號右邊的值,可以為100、55、22。
1
2
3
4
T = Integer;
T = Double;
T = ArrayList;
T = Object;
T為Type類型的英文字母。
T是變數。
以上等號右邊的值,可以為Integer, Double, ArrayList, Object。
所以下面文章內容所有的T, R, K, V …,任何英文字母,請把它看作變數,而變數中的值,就是類型。
自訂類型
在類別名後面,用尖括號包住<自訂類型>。
自訂類型T, R, M 可用英文字母任意一個大寫字母。
1
2
class Cat<T, R, M> {
}
屬性
泛型可以用在屬性類型。
1
2
3
4
5
class Cat<T, R, M> {
private T t;
private R r;
private M m;
}
建構子
泛型可以用在建構子參數類型。
1
2
3
4
5
6
7
8
9
10
11
class Cat<T, R, M> {
private T t;
private R r;
private M m;
public Cat(T t, R r, M m) {
this.t = t;
this.r = r;
this.m = m;
}
}
get,set方法
泛型可以用在方法參數類型與傳回值類型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Cat<T, R, M> {
private T t;
private R r;
private M m;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public R getR() {
return r;
}
public void setR(R r) {
this.r = r;
}
public M getM() {
return m;
}
public void setM(M m) {
this.m = m;
}
宣告與建立物件編譯器才會知道類型
1
Cat<String, Integer, Dog> cat = new Cat<String, Integer, Dog>();
jdk8以後可以省略後面的尖括號中的類型,因為前面已經宣告泛型(T,R,M)的類型是什麼,後面的可由前面的尖括號內容進行自動推導。
1
Cat<String, Integer, Dog> cat = new Cat<>();
沒泛型類型,預設Object
沒設定泛型類型。
1
Cat cat = new Cat();
編譯器自動認為泛型類型是Object。
1
Cat<Object, Object, Object> cat = new Cat<>();
泛型類型可以使用子類別
類別B繼承類別A
1
2
class A {}
class B extends A {}
Student,有泛型類型T屬性,與建構子。
1
2
3
4
5
6
7
class Student<T> {
private T t;
public Student(T t) {
this.t = t;
}
}
由以下的範例可以知道,泛型類型是可以用子類別。
1
2
3
Student<A> s3 = new Student<>(new A());
// 泛型類型是父類別A,但建構子放的是子類別B
Student<A> s4 = new Student<>(new B());
以下的程式碼也都是正確的,ArrayList是List的子類別,也是Object的子類別。
1
2
Student<List> s1 = new Student<>(new ArrayList<>());
Student<Object> s2 = new Student<>(new ArrayList<>());
基本型別自動轉成包裝類別
貓咪類別
1
2
3
4
5
6
7
8
9
10
11
class Cat<T, R, M> {
private T t;
private R r;
private M m;
public Cat(T t, R r, M m) {
this.t = t;
this.r = r;
this.m = m;
}
}
指定泛型類型,並建立物件,注意!建構子的參數都是基本型態,但內部會自動把12.5轉成Double類別,1轉成Integer類別。
1
Cat<Double, Boolean, Integer> cat = new Cat<>(12.5, true, 1);
使用getClass()知道泛型類型
1
2
3
4
5
6
7
8
9
10
11
12
13
class Cat<T, R, M> {
public void showType() {
System.out.println(t.getClass());
System.out.println(r.getClass());
System.out.println(m.getClass());
}
}
public class Test {
public static void main(String[] args) {
Cat<Double, Boolean, Integer> cat = new Cat<>(12.5, true, 1);
cat.showType();
}
}
class java.lang.Double
class java.lang.Boolean
class java.lang.Integer
不能使用泛型的情況
泛型不可以new
以下二種new是不被允許,因為編譯器根本不知道T是什麼類型,又怎麼會知道要在記憶體建立多大空間來裝這個物件。
1
2
3
4
class Cat<T, R, M> {
private T t = new T();
private T[] arr = new T[10];
}
泛型不可以用在靜態變數與靜態方法
靜態變數是在Class物件中,Class物件比物件更早建立,泛型要在物件建立的時候才指定類型,但靜態物件早就建立好了,根本不可能指定靜態變數的類型。
以下三種都不能使用。
1
2
3
4
5
6
7
8
9
10
11
12
class Cat<T, R, M> {
// static屬性
public static T t;
// static方法
public static T getStaticT() {
}
// static方法
public static void setStaticT(T t) {
}
}
不能用基本型態
基本型態有short, int, long, double, float, boolean, char
以下內容編譯不過。
1
Cat<int, double, char> cat = new Cat<>();
以下是另一種筆記。
語法
在類別名後面,自訂類型。
自訂類型的名稱可用T, R, K, V 任意一個大寫字母。
1
2
3
class 類別名<T, R, U> {
}
T代表Type,也就是類型。
T可以是成員變數的類型,也可以是成員方法參數類型。
成員變數類型
1
2
3
class 名稱<T> {
T 變數名;
}
1
2
3
class Obj1<T> {
T id;
}
參數類型
1
2
3
4
5
class Obj2<T> {
public void showMsg(T msg) {
msg.toString();
}
}
類型為T,只能用toString()的方法,toString()是由Object類別(所有類別的父類別)所提供的。
傳回值類型
1
2
3
4
5
6
class Obj3<T> {
private T[] elements;
public T getElements(int index) {
return elements[index];
}
}
使用泛型
宣告
在類別名後面有尖括號,尖括號中寫上實際的類型。
1
2
類別名<類型> 變數;
Obj1<String> test;
建立物件
new 類別名後面有尖括號,尖括號中寫上實際的類型。
語法
1
new 類別名<類型>();
JDK7以前一定要寫類型
1
Obj1<String> test = new Obj1<String>();
JDK7就可以不用在尖括號中寫類型,因為編譯器可以從宣告的時候就推斷類型。
1
Obj1<String> test = new Obj1<>();
範例
Cat類別,重寫toString()的方法
1
2
3
4
5
6
class Cat {
@Override
public String toString() {
return "貓貓貓";
}
}
Dog類別,重寫toString()的方法
1
2
3
4
5
6
class Dog {
@Override
public String toString() {
return "狗狗狗";
}
}
ShowObj,使用泛型,參數是泛型,什麼類型都可以。
1
2
3
4
5
class ShowObj<T> {
public void showObj(T obj) {
System.out.println(obj.toString());
}
}
宣告ShowObj是Cat類型,showObj()方法參數只能是Cat類型,不能放Dog類型,不然編譯時會出錯。
1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
ShowObj<Cat> show1 = new ShowObj<>();
show1.showObj(new Cat());
}
}
貓貓貓
宣告ShowObj是Dog類型,showObj()方法參數只能是Dog類型,不能放Cat類型,不然編譯時會出錯。
1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
ShowObj<Dog> show2 = new ShowObj<>();
show2.showObj(new Dog());
}
}
狗狗狗