第二十三條:不要在新代碼中使用原生類型

一、泛型的術語

類型參數:public class Request<E>{} 其中的E就是類型參數。
參數化類型:List<String> 這叫做參數化類型。
原生類型:List  沒有泛型的類,叫做原生。

補:在JAVA中是不推薦使用原生類型的,但是爲什麼不將原生類型去掉?
因爲泛型引入是在JAVA產生的20年後,爲了向上兼容以前的代碼,所以就保持了原生類型。

二、泛型的優點

①、能夠在編譯期間報錯
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<String> stringList = new ArrayList<>();
		stringList.add("asd");
		stringList.add(1);//報錯:無法存儲Integer類型
	}
而以前的代碼只能夠調用的時候,發現ClassCastException的錯誤

②、能夠隱式轉換(就是我輸入的是String,那麼我獲取到的數據也是String)
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<String> stringList = new ArrayList<>();
		stringList.add("asd");
		
		for(String str : stringList){
			System.out.println(str);
		}
	}
以前的代碼,存儲的都是Object類型,所以獲取之後需要自己強制轉換。

三、泛型的一些特徵

①、子類化規則
List<String> != List<Object> 雖然它們同爲List.class類。
這很好理解,因爲裏面存儲的內容不一樣,那麼這個容器的類型也就不一樣。(比如說茶壺和酒壺)
但是這個機制同時會引發一個問題:
Integer是Number的子類,但是List<Number> list != new List<Integer>()。
按道理來說List<Number> 應該是List<Integer>的父類,應該可以向上轉型纔是呀,可是根本無法使用。
這種方式是對的,因爲當向上轉型之後,就表示可以裝入Number的子類,比如double,但是double並不是Integer的子類,不能放在List<Integer>的容器中。
例:
	public static void main(String[]args){
		List<Number> list = new ArrayList<Integer>();
		double a = 1.34;
		list.add(a);
	}
這樣其實爲List<Integer>的容器就裝入了Double類的成員變量,這樣就違反了類型約束的規則。

②、原生類型可支持所有泛型
List<String> stringList = new ArrayList<>();
List<Object> objList = new ArrayList<>();

//"大哥"我能支持所有類型賦值
List list = objList;
list = stringList<span style="font-family: Arial, Helvetica, sans-serif;">;</span>
//並且還能裝填各種數據
list.add(1);
list.add("string");
list.add(new Object());
//List<Object> 我也能裝填各種類型,而且我還有類型檢驗
objList.add(1);
objList.add("string");
objList.add(new Object());
但是如果使用原生類型,就代表放棄了類型安全檢驗。
使用的時候就會產生錯誤:
String str = stringList.get(0);
就會報錯(ClassCastException):
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at Main.main(Main.java:12)

③、無限通配符(?)
JAVA爲了解決原生類型不安全的問題,所以產生了無限通配符 來解決這個問題。
使用:只需要List 變成List<?>就可以了。
那麼無限通配符真的起到作用了嗎?
從意義上講,是的。
因爲List<?>被認爲是安全的,而List被認爲是不安全的。
至少List<?>沒有警告 - -。
但是,事實上還是破壞了類型約束條件。
所以,爲保證類型安全,Collection<?>是無法存儲null以爲的數據的。

④、必須使用原生類型的情形。
原因:因爲泛型具有擦除的問題。
什麼叫做擦除:指的是,在運行期間,使泛型可以使沒使用泛型的代碼之間互相的轉換。


情形1、使用類文字的時候必須使用原生類型
例:可以使用List.class、String[].class、int.class
但是卻不可以使用List<String>.class,List<?>.class
因爲,JAVA的擦除會導致List<String>.class其實還是List.class,那麼List<String>、List<Object>本不相同的東西,就變成一樣了。

情形2、使用instanceof是違法的
例:
List<String> list = new ArrayList<>();
if (list instanceof List<String>) {}//由於擦除問題,這樣同樣是非法的。
所以一般方式是這樣處理的:
if (list instanceof List){
  List<?> myList = (List<?>) list;//保證類型安全
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章