Java中的泛型詳解。本站提示廣大學習愛好者:(Java中的泛型詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是Java中的泛型詳解正文
所謂泛型:就是許可在界說類、接口指定類型形參,這個類型形參在將在聲明變量、創立對象時肯定(即傳入現實的類型參數,也可稱為類型實參)
泛型類或接口
“菱形”語法
//界說
public interface List<E> extends Collection<E>
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
//應用
List<String> list = new ArrayList();
//Java7今後可以省略前面尖括號的類型參數
List<String> list = new ArrayList<>();
從泛型類派生子類
//方法1
public class App extends GenericType<String>
//方法2
public class App<T> extends GenericType<T>
//方法3
public class App extends GenericType
偽泛型
不存在真實的泛型類,泛型類對Java虛擬機來講是通明的.JVM其實不曉得泛型類的存在,換句話來講,JVM處置泛型類和通俗類沒甚麼差別的.是以在靜態辦法、靜態初始化塊、靜態變量外面不許可應用類型形參。
- 以下方法都是毛病的
private static T data;
static{
T f;
}
public static void func(){
T name = 1;
}
上面的例子可以從正面驗證不存在泛型類
public static void main(String[] args){
List<String> a1 = new ArrayList<>();
List<Integer> a2 = new ArrayList<>();
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass());
System.out.println(a2.getClass());
}
輸入
true
class java.util.ArrayList
class java.util.ArrayList
類型通配符
起首必需明白一點,假設Foo是Bar的父類,然則List<Foo>其實不是List<Bar>的父類.為了表現各類泛型的父類,Java應用"?"來表現泛型通配.即List<?>來表現各類泛型List的父類.帶這類通配符List泛型不克不及設置(set)元素,只能獲得(get)元素。由於法式沒法肯定List中的類型,所以不克不及添加對象。但獲得的對象確定是Object類型。
以下辦法會編譯失足:
List<?> list = new ArrayList<>();
list.add(new Object());
主張幾點:
1.List<String>對象不克不及被當做List<Object>對象應用,也就是說:List<String>類其實不是List<Object>類的子類。
2.數組和泛型有所分歧:假定Foo是Bar的一個子類型(子類或許子接口),那末Foo[]仍然是Bar[]的子類型;但G<Foo>不是G<Bar>的子類型。
3.為了表現各類泛型List的父類,我們須要應用類型通配符,類型通配符是一個問號(?),將一個問號作為類型實參傳給List聚集,寫作:List<?>(意思是未知類型元素的List)。這個問號(?)被稱為通配符,它的元素類型可以婚配任何類型。
通配符的下限
List<? extends SuperType>表現一切SuperType泛型List的父類或自己。帶有通配符下限的泛型不克不及有set辦法,只能有get辦法。
設置通配符下限能處理以下成績:Dog是Animal子類,有個getSize辦法要獲得傳入List的個數,代碼以下
abstract class Animal {
public abstract void run();
}
class Dog extends Animal {
public void run() {
System.out.println("Dog run");
}
}
public class App {
public static void getSize(List<Animal> list) {
System.out.println(list.size());
}
public static void main(String[] args) {
List<Dog> list = new ArrayList<>();
getSize(list); // 這裡編譯報錯
}
}
這裡編程失足的緣由是List<Animal>其實不是List<Dog>的父類。處理計劃一可以把getSize辦法中形參List<Animal>改成List<?>,不外如許的話在每次get對象的時刻都要強迫類型轉換,比擬費事。應用通配符下限很好的處理了這個成績,可以把List<Animal>改成List<? extends Animal>,編譯就不會錯了,也不消類型轉換。
通配符的上限
List<? super SubType>表現SubType泛型List的上限。帶有通配符下限的泛型不克不及有get辦法,只能有set辦法。
泛型辦法
假如界說類、接口是沒有應用類型形參,但界說辦法時想本身界說類型形參,這也是可以的,JDK1.5還供給了泛型辦法的支撐。泛型辦法的辦法簽名比通俗辦法的辦法簽名多了類型形參聲明,類型形參聲明以尖括號括起來,多個類型形參之間以逗號(,)離隔,一切類型形參聲明放在辦法潤飾符和辦法前往值類型之間.語法格局以下:
潤飾符 前往值類型 辦法名(類形列表){
//辦法體
}
泛型辦法許可類型形參被用來表現辦法的一個或多個參數之間的類型依附關系,或許辦法前往值與參數之間的類型依附關系。假如沒有如許的類型依附關系,就不該該應用泛型辦法。Collections的copy辦法就應用泛型辦法:
public static <T> void copy(List<? super T> dest, List<? extends T> src){ ...}
這個辦法請求src類型必需是dest類型的子類或自己。
擦除和轉換
在嚴厲的泛型代碼裡,帶泛型聲明的類總應當帶著類型參數。但為了與老的Java代碼堅持分歧,也許可在應用帶泛型聲明的類時不指定類型參數。假如沒無為這個泛型類指定類型參數,則該類型參數被稱作一個raw type(原始類型),默許是該聲明該參數時指定的第一個下限類型。
當把一個具有泛型信息的對象賦給另外一個沒有泛型信息的變量時,則一切在尖括號之間的類型信息都被扔失落了。好比說一個List<String>類型被轉換為List,則該List對聚集元素的類型檢討釀成了成類型變量的下限(即Object),這類情形被為擦除。
示例
class Apple<T extends Number>
{
T size;
public Apple()
{
}
public Apple(T size)
{
this.size = size;
}
public void setSize(T size)
{
this.size = size;
}
public T getSize()
{
return this.size;
}
}
public class ErasureTest
{
public static void main(String[] args)
{
Apple<Integer> a = new Apple<>(6); // ①
// a的getSize辦法前往Integer對象
Integer as = a.getSize();
// 把a對象賦給Apple變量,喪失尖括號裡的類型信息
Apple b = a; // ②
// b只曉得size的類型是Number
Number size1 = b.getSize();
// 上面代碼惹起編譯毛病
Integer size2 = b.getSize(); // ③
}
}