Java泛型的應用
---恢復內容開始---
在開發中,我們有時候會用到泛型來寫工具類,為了使方法更通用,以前,沒有完全弄懂,今天,就這個機會把泛形寫一寫
泛型是Java SE 1.5的新特性,泛型的本質是引數化型別,也就是說所操作的資料型別被指定為一個引數。這種引數型別可以用在類、介面和方法的建立中,分別稱為泛型類、泛型介面、泛型方法。泛型的引入,讓JAVA更安全。之前沒有引入泛型,各種的型別轉換錯誤。
泛型的好處是在編譯的時候檢查型別安全,並且所有的強制轉換都是自動和隱式的,以提高程式碼的重用率。
我們見不各種泛型的字母萬用字元T,E,K,V等等,還有?,其實這些字母只約定,實際中使用什麼字母都可以,以下是約定:
- ? 表示不確定的java型別
- T (type) 表示具體的一個java型別
- K V (key value) 分別代表java鍵值中的Key Value
- E (element) 代表Element
import java.util.ArrayList;
public class Demo {
public static void main(String[] args) {
}
public <T> void aa(T t){
ArrayList<?> al=new ArrayList<T>();
}
}
這種方式 正確
ArrayList<?> al=new ArrayList<T>();
但是這樣就不行了,後面只能是具體型別,不能是萬用字元,前邊是可以的
ArrayList<?> al=new ArrayList<?>();
?和T都表示不確定的型別 ,但如果是T的話,函式裡面可以對T進行操作,比方 T car = getCar(),而不能用? car = getCar()。
Class<T>在例項化的時候,T要替換成具體類
Class<?>它是個通配泛型,?可以代表任何型別,主要用於宣告時的限制情況
public class Test {
public static <T> T createInstance(Class<T> clazz) throws IllegalAccessException, InstantiationException {
return clazz.newInstance();
}
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Fruit fruit= createInstance(Fruit .class);
People people= createInstance(People.class);
}
}
class Fruit{
}
class People{
}
上面的類使用Class<T>泛型後,newInstance不用強轉
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
//雖然Test<T1,T2>,但類名字仍為Test。T1,T2只是告訴我們new的時候要加入泛型,更方便通用
//T1,T2可以任意定義,比如改成K,V都可以
//他們不會關聯到其他類,只是在本類中通用
public class Test<T1, T2> {
public static void main(String[] args) {
System.out.println(new Test().getT1());
System.out.println(new Test().getT2());
new Test<String, String>().getClassName("");//T1,T2在new的時候用到,這裡都為String
new Test().getClassAndList(Integer.class);
//HashMap的括號裡面不能是T,E,T1,T2等不確定的東西,但可以是?
HashMap<?, ?> map = new HashMap<Object, String>();
List<?> list = new ArrayList<String>();
}
public T1 getT1() {
//這裡的“T1”替換成1或1.0都會報錯
return (T1) "T1";
}
T2 getT2() {
//將自動轉型為String
return (T2) "T2";
}
public <T> void getClassName(T x) {
//<T>必須放在void或者返回型別的前面
System.out.println(x.getClass().getName());
}
public <T> Class<?> getClassAndList(Class<?> a) {
//Class<T>前面缺少<T>必須定義,否則將出現編譯錯誤
//T改成其他字母都可以,但一定要宣告
// 返回型別和引數中的型別:Class<T>和Class<?>都可以。因為返回的a的型別為Class<T>,Class<?>可以通配
//當兩個都是Class<?>,引數中的?自動通配成T
System.out.println(a.getClass().getName());//傳入的a是一個類,Class型別
//引數裡面的Class<T>最大的好處是如果方法裡面定義了泛型,可以自動獲取型別值,比如如下的List<T>可以自動獲取到a的型別,不必強調死
List<?> aa = new ArrayList<T>();
//List<?> aa = new ArrayList<?>();會報錯,以為ArrayList必須是一種型別,List<>起到通配的作用
//List<T> aa = new ArrayList<T>();當然正確
System.out.println(aa);
return a;
}
}
這個例子說明泛型可以是任何字母
public class GenericTest {
public static void main(String[] args) {
Box<String> name = new Box<String>("corn");
Box<Integer> age = new Box<Integer>(712);
Box<Number> number = new Box<Number>(314);
getData(name);
getData(age);
getData(number);
//getUpperNumberData(name); // 1
getUpperNumberData(age); // 2
getUpperNumberData(number); // 3
}
public static void getData(Box<?> data) {
System.out.println("data :" + data.getData());
}
public static void getUpperNumberData(Box<? extends Number> data){
System.out.println("data :" + data.getData());
}
}
class Box<T> {
private T data;
public Box() {
}
public Box(T data) {
setData(data);
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
Box<? extends Number> 問號也可以通過這種方式代表,傳入的都是Nubmber的子類