java泛型
在JDK1.5增加了泛型機制
泛型程序設計使得編寫的代碼可以被很多不同類型的對象所重用。
類型參數:使得程序具有更好的可讀性和安全性
泛型類的定義
- public class Person<T> {
- private T name;
- public Person(T name) {
- super();
- this.name = name;
- }
- public Person() {
- super();
- }
- public T getName() {
- return name;
- }
- public void setName(T name) {
- this.name = name;
- }
- }
調用:
- public class GenericDome {
- public static void main(String[] args) {
- Person<String> name1=new Person<String>("singsong1");
- Person<String> name2=new Person<String>();
- name2.setName("singsong2");
- System.out.println("name1="+name1.getName());
- System.out.println("name2="+name2.getName());
- }
- }
運行結果:
name1=singsong1
name2=singsong2
T是類型變量,要用<>括起來,並放在類名的後面。當然了泛型類可以有多個類型變量。
如public interface Map<K,V>
類型變量使用大寫形式,且比較短。在java庫中,使用變量E表示集合的元素類型,K和V分別表示表的關鍵字與值的類型。T表示“任意類型”
泛型類可看作普通類的工廠。
泛型方法
- public class Max {
- public static <T extends Comparable<T>> T getMax(T[] a) {
- if (a == null) {
- return null;
- }
- T max = a[0];
- for (int i = 0; i < a.length; i++) {
- if (max.compareTo(a[i]) < 0) {
- max = a[i];
- }
- }
- return max;
- }
- }
此方法求最大值
注意,類型變量放在修飾符(這裏是public static)的後面,返回類的前面。
泛型方法可以定義在普通類中,也可以定義在泛型類中。
在此泛型方法中使用了類型變的限定機制:
<T extends Comparable<T>>
因爲要確保T所屬的類有compareTo方法。所以將T限定爲現實了Comparable接口的類。
如果傳入的類沒有實現Comparable接口的,調用getMax將會產生一個編譯錯誤。
當然,一個變量類型或通配符可以有多個限定,用“&”分隔(注意:類型變量是用“,”逗號分隔)
如:T extends Comparable<T>& Serializable<T>
在java的繼承中,可以根據需要擁有多個接口超類型,但限定中至多有一個類。如果用一個類作爲限定,它必須是限定列表的第一個。
當調用一個泛型方法是,在方法名前的尖括號中放入具體的類型
調用:
運行結果:12
- public class GenericMethodDome {
- public static void main(String[] args) {
- Integer[] a = { 1, 2, 12, 4, 5 };
- System.out.println(Max.<Integer> getMax(a));// System.out.println(Max.getMax(a));
- }
- }
虛擬機沒有泛型類型對象,即所有對象都屬於普通類。
無論何時定義一個泛型類型,都自動提供了一個相應的原始類型(raw type)。原始類型的名字就是刪去類型參數後的泛型類型名。擦除類型變量,並替換爲限定類型(無限定的變量用Object)
如:
- public class Person<T> {
- private T name;
- public Person(T name) {
- super();
- this.name = name;
- }
- public Person() {
- super();
- }
- public T getName() {
- return name;
- }
- public void setName(T name) {
- this.name = name;
- }
- }
Person<T>原始類型
- public class Person {
- private Object name;
- public Person(Object name) {
- super();
- this.name = name;
- }
- public Person() {
- super();
- }
- public Object getName() {
- return name;
- }
- public void setName(Object name) {
- this.name = name;
- }
- }
原始類型用第一個限定的類型變量來替換,如果沒有就給定限定用Object替換。
如:public class Person<T extends Comparable & Serializable> implements Serializable {
public Person(T name) {
super();
this.name = name;
}
.. .. .. ..
}
原始類型:
public class Person implements Serializable {
public Person(Comparable name) {
super();
this.name = name;
}
.. .. .. ..
}
編譯器翻譯泛型表達式和泛型方法
當程序調用泛型方法是,如果擦除返回類型,編譯器插入強制類型轉換。
如:Person<String> someone=. . .;
編譯器首先調用原始方法Person.getName();
然後將返回的Object類型強制轉換化爲String類型。
當存取一個泛型域時也要插入強制類型轉換。
對一泛型方法要了解當類型擦除時,可能與多態產生衝突。要解決這個問題,就需要編譯器在子類中生成一個相應的橋接方法(bridge method)
總結
ü 虛擬機中沒有泛型,只有普通的類和方法。
ü 所有的類型參數都用它們的限定類型替換。
ü 橋接方法被合成來保持多態。
ü 爲了保持類型安全。必要時插入強制類型轉換。
使用java泛型的一些約束與限制,大多數限制都是由類型擦除引起的。
不能使用基本類型實例化類型參數
因爲在類型擦除時,沒有限定的類型變量,是用Object類型來限定,而Object不能存儲基本類型。
運行時類型查詢只適用於原始類型
不能拋出也不能補貨泛型類實例
泛型類擴展Throwable都不合法。不能再catch語句中使用類型變量。但是在異常聲明中可以使用類型變量
參數化類型的數值不合法
如果需要收集參數化類型的對象,最好直接使用ArrayList.
不能實例化類型變量
泛型類的靜態上下文中類型變量無效
不能再靜態域或方法中引用類型變量
注意擦除後的衝突
泛型規範:要想支持擦除的轉換,就需要強行限制一個類或類型變量不能同時成爲兩個接口類型的子類。而這兩個接口是同一接口的不同參數化。
泛型類可以擴展或實現其他的泛型類