泛型

一、泛型问题引出

例如,现在要求用户设计一个表示坐标点的类,但是此坐标保存数据有可能有如下几种:

· 整型数据:x = 10、y = 20;

· 小数数据:x = 10.2、y = 20.3;

· 字符串数据:x = 东经100度、y = 北纬20度。

那么现在很明显,Point类表示坐标,那么针对于坐标点有三类数据,而在Point类里面应该定义有两个属性:x、y,所以现在首先要解决的问题就是确定出x、y属性的数据类型。

既然现在要保存有int、double、String或者以后有可能的其它类型,则自然想到使用Object,因为存在如下转换关系:

· 保存整型:int è 自动装箱为Integer è 向上转型为Object;

· 保存小数:double è 自动装箱为Double è 向上转型为Object;

· 保存字符串:String è 向上转型为Object。

范例:实现代码

class Point {
	private Object x;
	private Object y;

	public void setX(Object x) {
		this.x = x;
	}

	public void setY(Object y) {
		this.y = y;
	}

	public Object getX() {
		return x;
	}

	public Object getY() {
		return y;
	}
}

范例:保存int型数据

public class TestDemo {
	public static void main(String[] args) {
		// 第一层次:设置坐标数据
		Point point = new Point();
		point.setX(10); // 向上转型为Object
		point.setY(20); // 向上转型为Object
		// 第二层次:取得坐标数据
		int x = (Integer) point.getX(); // 向下转型
		int y = (Integer) point.getY(); // 向下转型
		System.out.println("x = " + x + ",y = " + y);
	}
}

范例:保存double型数据

public class TestDemo {
	public static void main(String[] args) {
		// 第一层次:设置坐标数据
		Point point = new Point();
		point.setX(10.2); // 向上转型为Object
		point.setY(20.3); // 向上转型为Object
		// 第二层次:取得坐标数据
		double x = (Double) point.getX(); // 向下转型
		double y = (Double) point.getY(); // 向下转型
		System.out.println("x = " + x + ",y = " + y);
	}
}

范例:保存String型数据

public class TestDemo {
	public static void main(String[] args) {
		// 第一层次:设置坐标数据
		Point point = new Point();
		point.setX("东经100度"); // 向上转型为Object
		point.setY("北纬20度"); // 向上转型为Object
		// 第二层次:取得坐标数据
		String x = (String) point.getX(); // 向下转型
		String y = (String) point.getY(); // 向下转型
		System.out.println("x = " + x + ",y = " + y);
	}
}

此时的代码已经很好的完成了给出的系统要求,但是本程序依靠的是Object可以接收所有数据类型这一特征展开的,于是成是Object,败笔也在于次,因为Object保存的范围太大了。那么在程序运行之中就有可能出现隐患。

范例:观察问题

public class TestDemo {
	public static void main(String[] args) {
		// 第一层次:设置坐标数据
		Point point = new Point();
		point.setX(10); // 向上转型为Object
		point.setY("北纬20度"); // 向上转型为Object
		// 第二层次:取得坐标数据
		String x = (String) point.getX(); // 向下转型
		String y = (String) point.getY(); // 向下转型
		System.out.println("x = " + x + ",y = " + y);
	}
}

此时程序编译的时候没有任何的错误,但是执行的时候会出现“ClassCastException”,所以来讲此时的程序就存在有安全隐患,事实上,所有对象的向下转型都有可能存在这种安全隐患。最好的做法就是别转型。

以上的问题在JDK 1.5之前根本就无法解决,而在JDK 1.5之后由于引入了泛型的处理机制,所以此类问题很好的解决了。所谓的泛型指的是类之中定义的属性,在程序编译的时候不给出具体的类型,只给出一个类型的占位标记,而后在使用此类产生对象时,再设置具体类型。

范例:利用泛型修改

public class TestDemo {
	public static void main(String[] args) {
		// 第一层次:设置坐标数据
		Point point = new Point();
		point.setX("东经100度");
		point.setY("北纬20度");
		// 第二层次:取得坐标数据
		String x = point.getX(); // 向下转型
		String y = point.getY(); // 向下转型
		System.out.println("x = " + x + ",y = " + y);
	}
}

那么此时由于泛型技术的出现,取消了向下转型,而向下转型取消后就相当于消除了所有的ClassCastException这种安全隐患。但是需要注意的是,在设置泛型类型的时候只能够使用引用类型,即:如果要保存的是int或double,应该使用包装类操作。

范例:保存int

public class TestDemo {
	public static void main(String[] args) {
		// 第一层次:设置坐标数据
		Point point = new Point();
		point.setX(10);
		point.setY(20);
		// 第二层次:取得坐标数据
		int x = point.getX();
		int y = point.getY();
		System.out.println("x = " + x + ",y = " + y);
	}
}

请把以上的分析理解了,代码可以暂时不会。但是提示一下,为了照顾JDK 1.5之前所编写的代码。为了保证以前的代码没有任何的错误,所以如果在使用泛型标记类的时候没有设置泛型类型,那么会按照Object做默认处理。

public class TestDemo {
	public static void main(String[] args) {
		// 第一层次:设置坐标数据
		Point point = new Point();
		point.setX(10);
		point.setY(20);
		// 第二层次:取得坐标数据
		int x = (Integer) point.getX();
		int y = (Integer) point.getY();
		System.out.println("x = " + x + ",y = " + y);
	}
}

这类的情况一直到今天还会继续发生着,所以如果不设置泛型请一定要记住,类型就是Object。


二、通配符

下面为了方便讲解,重新定义一个使用泛型的类。

class Info {
	private T msg;

	public void setMsg(T msg) {
		this.msg = msg;
	}

	public T getMsg() {
		return msg;
	}
}

下面要针对于Info类的对象实现一次引用传递。

public class TestDemo {
	public static void main(String[] args) {
		Info info = new Info();
		info.setMsg("Hello World .");
		fun(info);
	}

	public static void fun(Info temp) {
		System.out.println(temp.getMsg());
	}
}

但是既然是设置泛型,肯定不可能只是String一种,有可能设置其它类型。此时,如果传递的是一个“Info”那么fun()方法是不可能使用的。如果用重载也不可能,因为重载的看重的是数据类型。于是现在发现,泛型一旦使用之后,在之前好不容易解决的参数统一问题,现在又重新回来了。于是这个时候有同学说了,那么既然参数上设置泛型会存在有问题,那么不如就别设置了。但是问题又回来了,如果不设置泛型,那么参数表示的类型就是Object。

范例:参数上不使用泛型

public class TestDemo {
	public static void main(String[] args) {
		Info info = new Info();
		info.setMsg("可乐");
		fun(info);
	}

	public static void fun(Info temp) {
		temp.setMsg(100); // 现在修改为Integer
		System.out.println(temp.getMsg());
	}
}

 所以这个时候发现,不设置泛型,操作的数据形式就可能出现混乱,于是现在就可以总结出来,我们需要的是一个可以接收任意的泛型类型,但是又不能修改里面数据,并且可以取得里面数据的操作。那么现在就只能够利用通配符“?”来完成此功能。

范例:使用“?”解决

public class TestDemo {
	public static void main(String[] args) {
        Info info = new Info() ;
        info.setMsg("可乐");
        fun(info) ;
    }

	public static void fun(Info temp) {
		temp.setMsg(100); // 现在修改为Integer
		System.out.println(temp.getMsg());
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值