【APICloud系列|34】免費使用的ChromeDebug 模組
技術標籤:JavaSE
泛型
1、泛型的概念
泛型的出現,可以讓我們少些程式碼,它的主要作用是解決型別的安全問題,不會因為將物件置於某個容器中而失去其型別。在泛型出現之前,Java提供了對Object型別引用的任意操作,即向上轉型和向下轉型,上轉型沒問題,但是向下轉型這種強制型別轉換是存在隱患的,因此Java提供了泛型機制。
Java泛型(generics)是JDK5中引入的一個新特性, 泛型提供了編譯時型別安全檢測機制,該機制允許程式設計師在編譯時檢測到非法的型別。泛型的本質是引數化型別,也就是說所操作的資料型別被指定為一個引數。
泛型並不是一種資料型別,而是一種特殊語法,對接收的資料型別進行了規定。如Map<String,String> map = new HashMap()。只允許字串型別資料作為Map集合的value值,不接受其他資料型別。使用泛型的好處是在程式碼書寫過程中可提高效率和資料型別安全,規避因資料型別不符合要求而造成的編譯錯誤,最突出的是避免了資料物件強制轉換,支援動態下確定資料型別。通常在集合中使用泛型。
以一個例子說明。
定義一個實體類:
public class T1 {
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
測試:
public static void main(String[] args) {
T1 t = new T1();
// 上轉型
t.setObj(new Boolean(true));
System.out.println(t.getObj());
T1 t2 = new T1();
t2.setObj(new Float (25.5));
// 強制轉換
Integer res = (Integer) t2.getObj();
System.out.println(res);
}
執行,控制檯:
型別轉換錯誤,Float型別不能強制轉換成Integer型別,這是不允許的,但是編譯的時候並沒有報錯,這時候可以用泛型有效的解決這種向下轉型的型別安全問題。
2、定義泛型類
泛型類的定義很簡單,語法如下:
類名 <T>
使用泛型的好處就是不用再進行強制轉換了,也就不存在發生型別轉換錯誤。以下用例子說明。
定義一個泛型類T2:
/*
* 定義泛型類
* 型別用T表示
*/
public class T2<T> {
// 這個obj沒有定義成具體型別
private T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
測試:
public static void main(String[] args) {
// 傳入Boolean型別作為引數
T2<Boolean> t0 = new T2<>();
t0.setObj(true);
Boolean b = t0.getObj();
System.out.println(b);
// 傳入Float型別作為引數
T2<Float> t2 = new T2<>();
t2.setObj(25.5f);
Float f = t2.getObj();
System.out.println(f);
}
控制檯:
3、宣告多個型別
在定義泛型類的時候,可以同時宣告多個型別,語法如下:
類名 <型別1,型別2>
以下程式碼說明:
public class T3<Integer, Boolean> {
private Boolean single;
private Integer age;
public Boolean getSingle() {
return single;
}
public void setSingle(Boolean single) {
this.single = single;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
測試:
public static void main(String[] args) {
T3<Integer, Boolean> t = new T3<>();
t.setSingle(true);
t.setAge(25);
System.out.println("年齡:" + t.getAge());
System.out.println("是單身嗎?" + t.getSingle());
}
控制檯:
4、宣告陣列型別
在定義泛型的時候可以宣告為陣列型別,但是不能使用泛型機制來建立陣列例項。程式碼如下:
public class T4<T> {
//這個陣列的型別為T
private T[] arrays;
public T[] getArrays() {
return arrays;
}
public void setArrays(T[] arrays) {
this.arrays = arrays;
}
}
測試:
public static void main(String[] args) {
T4<Integer> t = new T4<>();
Integer[] num = new Integer[] {1, 4, 3, 123, 45 };
t.setArrays(num);
System.out.println("陣列中的元素如下:");
for (Integer i : t.getArrays()) {
System.out.print(i + "\t");
}
System.out.println();
System.out.println("--------------------------------");
T4<String> t2 = new T4<>();
String[] str = new String[] {"yan", "cheng", "zhi", "yun" };
t2.setArrays(str);
System.out.println("陣列中的元素如下:");
for (String s : t2.getArrays()) {
System.out.print(s + "\t");
}
}
控制檯:
5、宣告集合類的容器元素
可以使用K代表鍵,V代表值。如下:
public class T5<K, V> {
public Map<K, V> map = new HashMap<>();
// 設定put方法
public void put(K k, V v) {
map.put(k, v);
}
// 設定get方法
public V get(K k) {
return map.get(k);
}
public Map<K, V> getMap() {
return map;
}
public void setMap(Map<K, V> map) {
this.map = map;
}
}
測試:
public static void main(String[] args) {
T5<String, Integer> t = new T5<>();
for (int i = 1; i <= 5; i++) {
t.put("第" + i + "個元素", i);
}
Set<Entry<String, Integer>> set = t.getMap().entrySet();
for (Entry<String, Integer> entry : set) {
System.out.println(entry.getKey() + "\t" + entry.getValue() + "\n");
}
}
控制檯:
事實上,這種是多餘的,因為Java的集合框架已經泛型化了,直接使用就行了,不用這麼麻煩的定義。
6、限制泛型可用型別
預設的可以使用任何的型別來例項化一個泛型物件,但是也可以做出限制,規定可以使用哪些型別來例項化物件。語法如下:
類名 <T extends 型別>
使用泛型限制以後,只有繼承了規定的型別或實現了這個介面的類才能作為泛型的引數,以下程式碼說明:
/*
* 限制泛型引數型別
*/
public class T6<T extends List> {
public static void main(String[] args) {
// ArrayList實現了List介面,可以作為泛型引數
T6<ArrayList> t = new T6<>();
// LinkedList實現了List介面,可以作為泛型引數
T6<LinkedList> t2 = new T6<>();
// Vector實現了List介面,可以作為泛型引數
T6<Vector> t3 = new T6<>();
// 不接受Integer型別作為泛型引數
// T6<Integer> t4 = new T6<>();
// 不接受String型別作為泛型引數
// T6<String> t4 = new T6<>();
}
}
7、使用型別萬用字元
在泛型機制中,提供類的萬用字元?。萬用字元應用較少,有需求時才使用,不必要時可不用,採用泛型可滿足要求即可。
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("yan");
list.add("cheng");
list.add("zhi");
List<?> list2 = list;
System.out.println("list2集合大小為:" + list2.size());
for (Object o : list2) {
System.out.print(o.toString() + "\t");
}
System.out.println();
List<Integer> list3 = new ArrayList<>();
System.out.println("list3集合大小為:" + list3.size());
//list2集合會被覆蓋掉
list2 = list3;
System.out.println("list2集合大小為:" + list2.size());
}
8、泛型介面
也可以定義泛型的介面,像定義泛型類一樣。如下:
/*
* 定義泛型介面
*/
public interface TestDao<T> {
void save(T t);
}
介面的實現類:
public class TestDaoImpl<T> implements TestDao<T> {
@Override
public void save(T t) {
// TODO Auto-generated method stub
}
}