JDK 令我們期待很久可是當他發布的時候卻更換版本號為這說明Java已經有大幅度的變化本文將講解JDK支持的新功能Java的泛型
Java泛型
其實Java的泛型就是創建一個用類型作為參數的類就象我們寫類的方法一樣方法是這樣的method(String strString str )方法中參數strstr的值是可變的而泛型也是一樣的這樣寫class Java_Generics<KV>這裡邊的K和V就象方法中的參數str和str也是可變下面看看例子
//code list
import JavautilHashtable;
class TestGen<KV>{
public Hashtable<KV> h=new Hashtable<KV>();
public void put(K k V v) {
hput(kv);
}
public V get(K k) {
return hget(k);
}
public static void main(String args[]){
TestGen<StringString> t=new TestGen<StringString>();
tput(key value);
String s=tget(key);
Systemoutprintln(s);
}
}
正確輸出:value
這只是個例子(Java中集合框架都泛型化了這裡費了遍事)不過看看是不是創建一個用類型作為參數的類參數是KV傳入的值是String類型這個類他沒有特定的待處理型別以前我們定義好了一個類在輸入輸入參數有所固定是什麼型別的有要求但是現在編寫程序完全可以不制定參數的類型具體用的時候來確定增加了程序的通用性像是一個模板
呵呵類似C++的模板(類似)
泛型通配符
下面我們先看看這些程序
//Code list
void TestGenMedthod(List l) {
for (Object o : l)
Systemoutprintln(o);
}
看看這個方法有沒有異議這個方法會通過編譯的假如你傳入String就是這樣List<String>
接著我們調用它問題就出現了我們將一個List<String>當作List傳給了方法JVM會給我們一個警告說這個破壞了類型安全因為從List中返回的都是Object類型的而讓我們再看看下面的方法
//Code list
void TestGenMedthod(List<String> l) {
for (Object o : l)
Systemoutprintln(o);
}
因為這裡的List<String>不是List<Object>的子類不是String與Object的關系就是說List<String>不隸屬於list<Object>他們不是繼承關系所以是不行的這裡的extends是表示限制的
類型通配符是很神奇的List<?>這個你能為他做什麼呢?怎麼都是?它似乎不確定他總不能返回一個?作為類型的數據吧是啊他是不會返回一個?來問程序員的?JVM會做簡單的思考的看看代碼吧更直觀些
//code list
List<String> l = new ArrayList<String>();
liadd(String);
List<?> l = l;
Systemoutprintln(lget());
這段代碼沒問題的lget()將返回一個Object
編寫泛型類要注意
) 在定義一個泛型類的時候在 <>之間定義形式類型參數例如class TestGen<KV>其中K V不代表值而是表示類型
) 實例化泛型對象的時候一定要在類名後面指定類型參數的值(類型)一共要有兩次書寫例如
TestGen<StringString> t=new TestGen<StringString>()
) 泛型中<K extends Object>extends並不代表繼承它是類型范圍限制
泛型與數據類型轉換
消除類型轉換
上面的例子大家看到什麼了數據類型轉換的代碼不見了在以前我們經常要書寫以下代碼如
//code list
import JavautilHashtable;
class Test {
public static void main(String[] args) {
Hashtable h = new Hashtable();
hput(key value);
String s = (String)hget(key);
Systemoutprintln(s);
}
}
這個我們做了類型轉換是不是感覺很煩的並且強制類型轉換會帶來潛在的危險系統可能會拋一個ClassCastException異常信息在JDK中我們完全可以這麼做如
//code list
import JavautilHashtable;
class Test {
public static void main(String[] args) {
Hashtable<StringInteger> h = new Hashtable<StringInteger> ();
hput(key new Integer());
int s = hget(key)intValue();
Systemoutprintln(s);
}
}
這裡我們使用泛化版本的HashMap這樣就不用我們來編寫類型轉換的代碼了類型轉換的過程交給編譯器來處理是不是很方便而且很安全上面是String映射到String也可以將Integer映射為String只要寫成HashTable<IntegerString> h=new HashTable<IntegerString>();hget(new Integer())返回value果然很方便
自動解包裝與自動包裝的功能
從上面有沒有看到有點別扭啊hget(new Integer())這裡的new Integer();好煩的在JDK之前我們只能忍著了現在這種問題已經解決了請看下面這個方法我們傳入一個int這一基本型別然後再將i的值直接添加到List中其實List是不能儲存基本型別的List中應該存儲對象這裡編譯器將int包裝成Integer然後添加到List中去接著我們用Listget();來檢索數據並返回對象再將對象解包裝成int恩JDK給我們帶來更多方便與安全
//Code list
public void autoBoxingUnboxing(int i) {
ArrayList<Integer> L= new ArrayList<Integer>();
Ladd(i);
int a = Lget();
Systemoutprintln(The value of i is + a);
}
限制泛型中類型參數的范圍
也許你已經發現在code list 中的TestGen<KV>這個泛型類其中KV可以是任意的型別也許你有時候呢想限定一下K和V當然范圍怎麼做呢?看看如下的代碼
//Code list
class TestGen<K extents StringV extends Number>
{
private V v=null;
private K k=null;
public void setV(V v){
thisv=v;
}
public V getV(){
return thisv;
}
public void setK(K k){
thisk=k;
}
public V getK(){
return thisk;
}
public static void main(String[] args)
{
TestGen<StringInteger> t=new TestGen<StringInteger>();
tsetK(new String(String));
tsetV(new Integer());
Systemoutprintln(tgetK());
Systemoutprintln(tgetV());
}
}
上邊K的范圍是<=String V的范圍是<=Number注意是<=對於K可以是String的V當然也可以是Number也可以是IntegerFloatDoubleByte等看看下圖也許能直觀些請看上圖A是上圖類中的基類AA分別是A的子類A有個子類分別是A_A_
然後我們定義一個受限的泛型類class MyGen<E extends A>這個泛型的范圍就是上圖中蘭色部分
這個是單一的限制你也可以對型別多重限制如下
class C<T extends Comparable<? super T> & Serializable>
我們來分析以下這句T extends Comparable這個是對上限的限制Comparable< super T>這個是下限的限制Serializable是第個上限一個指定的類型參數可以具有一個或多個上限具有多重限制的類型參數可以用於訪問它的每個限制的方法和域
多態方法
//Code list
class TestGen {
<T extends Object> public static List<T> make(T first) {
return new List<T>(first);
}
}
From:http://tw.wingwit.com/Article/program/Java/hx/201311/27017.html