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());
	}

六:总结

技术改进的道理如果明白,那么在使用时自然就更会印象深刻,接受更快。在理解他的设计思想和改进原因下,更会事半功倍。

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