JAVA使用泛型改進Object參數類型統一帶來的缺陷

泛型是在jdk1.5之後被引入的,技術革新一定是由於前面的技術的缺陷造成的,因此需要了解泛型出現的原因,才能更好的理解和使用泛型。

一:多態性複習

在之前已經寫了一篇關於java多態性的理解總結,鏈接如下:
JAVA多態性
爲節約篇幅,接下來就接上一篇繼續進行。

class Ball{
	public void play(){
		System.out.println("在玩Ball");
	}
}
class BasketBall extends Ball{
	public void rule(){
		System.out.println("籃球規則爲:....... ");		
	}
	public void play(){
		System.out.println("在玩籃球");
	}
}
class FootBall extends Ball{
	public void play(){
		System.out.println("在玩足球");
	}
}
public class DemoTest{
	public static void main(String args[]){
		Ball ball = new BasketBall();//向上類型轉換
		playRule(ball);
	}
	public static void playRule(Ball ball){
		BasketBall bb = (BasketBall)ball; //向下類型轉換(強制轉換)
		bb.rule();
	}
}

拿了一段代碼,上面定義static靜態方法時參數的類型爲Ball,是父類,實際上傳輸的是BasketBall這個子類對象,實現了參數統一,具體的作用優點已經在上面的鏈接文章中給出了。

二:Object的超然地位

在jdk1.9之後,java引入了自動裝箱和自動拆箱機制,這就給基本數據類型轉換成相應的引用數據類型提供了便利。而Object類是又是所有類的父類,他可以接收所有的引用類型。即可以實現將所有的引用類型實例對象轉換成Object的對象(向上類型轉換)。也就可以實現參數的統一,比上面的還要徹底 !

Object ball = new BasketBall();//向上類型轉換

三:由Object引發的問題

成也蕭何敗也蕭何,由於Object的描述範圍的廣泛,也會造成一些安全隱患

class Ball{
	//...
}
class BasketBall extends Ball{
	public void rule(){
		System.out.println("籃球規則爲:....... ");		
	}
}
class FootBall extends Ball{
	public void rule(){
		System.out.println("足球規則爲:....... ");		
	}
}

public class MulChangeUpTest{
	public static void main(String args[]){
		Ball ball = new BasketBall();
		playRule(ball);
	}
	public static void playRule(Object obj){
		FootBall b = (FootBall)obj;
		b.rule();
	}
}

運行結果:編譯成功,運行報錯
在這裏插入圖片描述
讓人頭疼的是:這個問題他是編譯不報錯的,而是運行時報錯的,這就會造成極大的安全隱患
有人說爲什麼不去使用instanceof 去判斷一下,-_- 可千萬不要擡槓,我們這是在提出問題,準備去解決問題。但是instanceof只是一個防治措施,是爲了防止出現崩潰,並不是解決問題的根本措施,治標不治本

四:泛型出場

我們在瞭解到了由於Object作爲參數帶來的缺點之後,必須要進行解決。我特別喜歡老師說的一句話,轉型會帶來問題那麼就不去轉型。使用別的途徑去解決問題。

class Ball<T>{
	// 球的類型可能使用String,或者Integer類型代表
	private T ballType;
	public void setBallType(T ballType){
		this.ballType = ballType;
	}
	public T getBallType(){
		return this.ballType;
	}
}

public class DemoTest{
	public static void main(String args[]){
		Ball<Integer> ball = new Ball<Integer>();
		ball.setBallType(10);
		int type = ball.getBallType();
		System.out.println(b.getBallType());
	}
}

當前類型被死死的限制爲了Integer,就不會造成這種安全隱患了。
此時編譯和運行都正確。使用泛型<T>來表示Type類型,這個Ball類內部的所有T代表的類型,是在運行時動態決定的。

如果不按照泛型定義的類型進行賦值:

public class DemoTest{
	public static void main(String args[]){
		Ball<Integer> ball = new Ball<Integer>();
		ball.setBallType("籃球");
	}
}

報錯信息:
在這裏插入圖片描述
如此,使用了泛型後在編譯期間就會報錯,就將這種安全隱患解決了。

五:參數統一下的泛型:泛型通配符

先看一段代碼

class Ball<T>{
	// 球的類型可能使用String,或者Integer類型代表
	private T ballType;
	public void setBallType(T ballType){
		this.ballType = ballType;
	}
	public T getBallType(){
		return this.ballType;
	}
}

public class DemoTest{
	public static void main(String args[]){
		Ball<Integer> ball = new Ball<Integer>();
		ball.setBallType(10);
		playRule(ball);
	}
	public static void playRule(Ball<String> b){
		System.out.println(b.getBallType());
	}
}

先想一想,我們使用Object的最大優點是什麼? 就是實現了參數類型的統一。但是使用了上面的泛型來定義playRule的參數類型時,將傳入的參數類型限制在了String類型。Integer類型的就會報錯,這與我們改善Object的初衷是相悖的。
此時就需要一個泛型用於描述一切的類型。即泛型通配符

<?>

	public static void playRule(Ball<?> b){
		System.out.println(b.getBallType());
	}

六:總結

技術改進的道理如果明白,那麼在使用時自然就更會印象深刻,接受更快。在理解他的設計思想和改進原因下,更會事半功倍。

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