日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Java泛型深入理解小总结

發(fā)布時間:2025/3/20 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java泛型深入理解小总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉載自博客園:http://www.cnblogs.com/fantasy01/p/3963593.html


1、何為泛型

首先泛型的本質便是類型參數(shù)化,通俗的說就是用一個變量來表示類型,這個類型可以是String,Integer等等不確定,表明可接受的類型,原理類似如下代碼

int pattern; //聲明一個變量未賦值,pattern可以看作是泛型 pattern = 4; pattern = 5;//4和5就可以看作是String和Integer

泛型的具體形式見泛型類、泛型方法

  *泛型類形式如下

class Test<T> {private T t;Test(T t){this.t = t;}public T getT(){return t;}public void setT(T t){this.t = t;} }

  *泛型方法舉例代碼如下

public <T> void show() {operation about T... }

泛型參數(shù)類型聲明必須在返回類型之前

2、為何要引入泛型,即泛型與Object的優(yōu)勢

由于泛型可以接受多個參數(shù),而Object經(jīng)過強制類型轉換可以轉換為任何類型,既然二者都具有相同的作用,為何還要引進泛型呢?

解答:泛型可以把使用Object的錯誤提前到編譯后,而不是運行后,提升安全性。以下用帶泛型的ArrayList和不帶泛型的Arraylist舉例說明

代碼1:

ArrayList al = new ArrayList(); al.add("hello"); al.add(4);//自動裝箱 String s1 = (String)al.get(0); String s2 = (String)al.get(1);//在編譯時沒問題,但在運行時出現(xiàn)問題

首先聲明無泛型的ArrayList時,其默認的原始類型是Object數(shù)組,既然為Object類型,就可以接受任意數(shù)據(jù)的賦值,因此編譯時沒有問題,但是在運行時,Integer強轉成String,肯定會出現(xiàn)ClassCastException.因此泛型的引入增強了安全性,把類轉換異常提前到了編譯時期。

3、類型擦除和原始類型

  *類型擦除的由來

在JAVA的虛擬機中并不存在泛型,泛型只是為了完善java體系,增加程序員編程的便捷性以及安全性而創(chuàng)建的一種機制,在JAVA虛擬機中對應泛型的都是確定的類型,在編寫泛型代碼后,java虛擬中會把這些泛型參數(shù)類型都擦除,用相應的確定類型來代替,代替的這一動作叫做類型擦除,而用于替代的類型稱為原始類型,在類型擦除過程中,一般使用第一個限定的類型來替換,若無限定則使用Object.

  *對泛型類的翻譯

泛型類(不帶泛型限定)代碼:

class Test<T> {private T t;public void show(T t){} }

虛擬機進行翻譯后的原始類型:

class Test {private Object t;public void show(Object t){} }

泛型類(帶泛型限定)代碼: 

class Test<? extends Comparable> {private T t;public void show(T t){} }

虛擬機進行翻譯后的原始類型:

class Test {private Comparable t;public void show(Comparable t){} }

 *泛型方法的翻譯

class Test<T> {private T t;public void show(T t){} }class TestDemo extends Test<String> {private String t;public void show(String t){} }

由于TestDemo繼承Test<String>,但是Test在類型擦除后還有一個public void Show(Object t),這和那個show(String t)出現(xiàn)重載,但是本意卻是沒有show(Object t)的,

因此在虛擬機翻譯泛型方法中,引入了橋方法,及在類型擦除后的show(Object t)中調用另一個方法,代碼如下:

public void show(Object t) {show((String) t); }

4、泛型限定

  *泛型限定是通過?(通配符)來實現(xiàn)的,表示可以接受任意類型,那一定有人有疑問,那?和T(二者單獨使用時)有啥區(qū)別了,其實區(qū)別也不是很大,僅僅在對參數(shù)類型的使用上。

例如:

public void print(ArrayList<?> al) {Iterator<?> it = al.iterator();while(it.hasNext()){System.out.println(in.next());} }

public
<T> void print(ArrayList<T> al) {Iterator<T> it = al.iterator();while(it.hasNext()){T t = it.next(); //區(qū)別就在此處,T可以作為類型來使用,而?僅能作為接收任意類型 System.out.println(t);} }

  *??extends SomeClass ?這種限定,說明的是只能接收SomeClass及其子類類型,所謂的“上限”

  *? super SomeClass 這種限定,說明只能接收SomeClass及其父類類型,所謂的“下限”

一下舉例??extends SomeClass說明一下這類限定的一種應用方式

由于泛型參數(shù)類型可以表示任意類型的類類型,若T要引用compareTo方法,如何保證在T類中定義了compareTo方法呢?利用如下代碼:

public <T extends Comparable> shwo(T a, T b) {int num = a.compareTo(b); }

此處用于限定T類型繼承自Comparable,因為T類型可以調用compareTo方法。

  *可以有多個類型限定,例如:

<T extends Comparable & Serializable>

這種書寫方式為何把comparable寫在前邊?因為由于類型擦除的問題,原始類型是由Comparable替換的,因此寫在前邊的是類中存在此類型的泛型方法放在前邊,避免調用方法時類型的強制轉換,提高效率。

class Test<T extends Comparable & Serializable> {private T lower;private T upper;public Test(T first, T second) //此處是利用Comparable的方法,因此把Comparable寫在前邊,類型擦除后為Comparable,若為Serializable,還得用強制類型轉換,否則不能使用compareTo方法。 {int a = first.compareTo(second);...} }

  *關于泛型類型限定的“繼承”誤區(qū)

總有些人誤把類型的限定當作繼承,比如:

//類型是這樣的 <Student extends Person> //然后出現(xiàn)此類錯誤 ArrayList<Person> al = new ArrayList<Student>();

此處的<Person>, <Student>作為泛型的意思是ArrayList容器的接收類型,用一個簡單的例子來說明

ArrayList是一個大型養(yǎng)殖場,<Person>表明的是他能夠接收動物,而上邊的new語句生成的是一個只能夠接收豬的養(yǎng)殖場(ArrayList<Student>),即把一個大型養(yǎng)殖場建造成了一個養(yǎng)豬場,若是繼承的大型養(yǎng)殖場肯定是還能接受狗、羊....的,但是現(xiàn)在建造成了養(yǎng)豬場,那還能接受別的動物么?所以這肯定是錯誤的用法!簡而言之,泛型new時兩邊的類型參數(shù)必須一致。

5、泛型的一些基本規(guī)則約束

  *泛型的類型參數(shù)必須為類的引用,不能用基本類型(int, short, long, byte, float, double, char, boolean)

  *泛型是類型的參數(shù)化,在使用時可以用作不同類型(此處在說泛型類時會詳細說明)

  *泛型的類型參數(shù)可以有多個,代碼舉例如下:

public <T, E> void show() { coding operation..... }

  *泛型可以使用extends, super, ?(通配符)來對類型參數(shù)進行限定

  *由于類型擦除,運行時類型查詢只適用于原始類型,比如instanceof、getClass()、強制類型轉換,a instanceof (Pair<Employe>),在類型擦除后便是 a instanceof Pair,因此以上運行的一些操作在虛擬機中操作都是對原始類型進行操作,無論寫的多么虛幻,都逃不出類型擦除,因為在虛擬機種并不存在泛型。

  *不能創(chuàng)建參數(shù)化類型的數(shù)組

例如寫如下代碼:

Pair<String>[] table = new Pair<String>[10]; //ERROR //讓Object[] t指向table Object[] t = table; //向t中添加對象 t[0] = new Pair<Employe>(); //關鍵錯誤之處 String s = table[0];

由于Object可以接收任何類型,在里邊存入 new Pari<Employe>時,沒有任何問題,但是當取出的時候會出現(xiàn)ClassCastException,因此不能創(chuàng)建參數(shù)化類型數(shù)組。

  *不能實例化類型變量,及不能出現(xiàn)以下的類似代碼

T t = new T(); // T.Class

因為在類型擦除后,便是Object t = new Object();與用意不符合,即本意肯定不是要調用Object.

  *不能再靜態(tài)域或方法中出現(xiàn)參數(shù)類型

例如如下錯誤代碼

class Test<T> {private static T example; //errorpublic static void showExample() //error {action about T...}public static T showExample() //error {action about T.... } }

首先方法是一個返回類型為T的普通方法,而非泛型方法,這和在靜態(tài)方法中使用非靜態(tài)參數(shù)是一樣的,靜態(tài)方法是先于對象而存在內存中的,因此在編譯的時候,T的類型無法確定,一定會出現(xiàn)“Cannot?make?a?static?reference?to?a?non_static?reference”這樣類似的錯誤。

但是這樣的代碼就是正確的

class Test<T> {public static <T> T show(){action} }

因為此處的靜態(tài)方法是泛型方法,可以使用.

  *不能拋出或捕獲泛型類的實例

    +不能拋出不能捕獲泛型類對象

    +泛型類不能擴展Throwable,注意是類不能繼承Throwable,類型參數(shù)的限定還是可以的。

    +catch子句不能使用類型變量,如下代碼

try {.... } catch(T e) //error {... }

  *類型擦除后的沖突注意

例如:

class Pair<T> {public boolean equals(T value) //error {....} }

此處的錯誤的原因不能存在同一個方法,在類型擦除后,Pair的方法為,public boolean equals(Object value),這與從Object.class中繼承下來的equals(Object obj)沖突。

  *一個類不能成為兩個接口類型的子類,而這兩個接口是同一接口的不同參數(shù)化。

例如:

class Calendar implements coparable<Calendar>{}class GregorianCalendar extends Calendar implements Comparable<GregorianCalendar>{} //error

當類型擦除后,Calendar實現(xiàn)的是Comparable,而GregorianCalendar繼承了Calendar,又去實現(xiàn)Comparable,必然出錯!

———————————————————————————————————————————————————————————————————————————————

?先總結到此處。




總結

以上是生活随笔為你收集整理的Java泛型深入理解小总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。