泛型

如何理解什麼是泛型呢?

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());
  }
}
狗狗狗

results matching ""

    No results matching ""