一 为什么要引入泛型这个概念?

       这里我用一个实例来简单说明。比如说:我们要设计一个表示二维坐标的类,但是因为关于坐标的表示有多种形式,比如:

       (1)整数表示:x=10    y=20

       (2)浮点型表示:x=10.5    y=20.8

       (3)字符串表示:x=””东经 50度””    y=”北纬 79度”

       因此,在我们设计的类中就不能单一的设置成int,float或String,而想要使用一个类型来接收这三种不同的数据类型,就只能使用Object。测试代码如下:

package javase.paradigm;/** * 二维坐标表示 * */public class Point {	private Object X;	private Object Y;		public Object getX() {		return X;	}	public void setX(Object x) {		X = x;	}	public Object getY() {		return Y;	}	public void setY(Object y) {		Y = y;	}	public static void main(String[] args) {		Point point = new Point();		//1 整数表示坐标		point.setX(10);  //int --> Integer --> Object		point.setY(20);				int x = (int) point.getX();		int y = (int) point.getY();		System.out.println("整数表示,X坐标是:" + x + ",Y坐标是:" + y);				System.out.println("******************我是华丽的分割线**********************");				//2 小数表示坐标		point.setX(10.5f);  //float --> Float --> Object		point.setY(20.8f);				float x2 = (float) point.getX();		float y2 = (float) point.getY();		System.out.println("小数表示,X坐标是:" + x2 + ",Y坐标是:" + y2);				System.out.println("******************我是华丽的分割线**********************");				//3 字符串表示坐标		point.setX("东经 50度");  //String --> Object		point.setY("北纬 79度");				String x3 = (String) point.getX();		String y3 = (String) point.getY();		System.out.println("字符串表示,X坐标是:" + x3 + ",Y坐标是:" + y3);			}}

输出:

整数表示,X坐标是:10,Y坐标是:20******************我是华丽的分割线**********************小数表示,X坐标是:10.5,Y坐标是:20.8******************我是华丽的分割线**********************字符串表示,X坐标是:东经 50度,Y坐标是:北纬 79度

       通过上面设计的这个类貌似已经解决我们的需求了?但是真的是这样吗?这个类中将变量设置成Object类型,就意味着可以使用任意的Object子类来初始化,如果对变量初始化的类型和取出类型不一致,则程序在运行时会报错,出现类型转化异常。比如说这样:

                point.setX(0);		point.setY("北纬179度");				int x4 = (int) point.getX();		int y4 = (int) point.getY();  //错误代码		System.out.println("错误案例,X坐标是:" + x4 + ",Y坐标是:" + y4);

这段代码编译没有问题,但是运行时报错,报错信息如下:

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer	at javase.paradigm.Point.main(Point.java:60)

错误信息已经很明显了,String类型不能转化成Integer类型。因此为了避免出现这种类型安全问题,我们就需要使用泛型

二 泛型的初步使用

(1)格式:

       类名称<具体类> 对象名称 = new 类名称<具体类>()

如:Point2<Integer> point2_1 = new Point2<Integer>();

(2)完整测试案例代码如下:

package javase.paradigm;public class Point2
 { private T var; public T getVar() { return var; } public void setVar(T var) { this.var = var; } public static void main(String[] args) { //1 整数 Point2
 point2_1 = new Point2
(); point2_1.setVar(20); System.out.println("整数测试:" + point2_1.getVar()); System.out.println("******************我是华丽的分割线**********************"); //字符串 Point2
 point2_2 = new Point2
(); point2_2.setVar("zifangsky的个人博客"); System.out.println("字符串测试:" + point2_2.getVar()); }}

输出:

整数测试:20******************我是华丽的分割线**********************字符串测试:zifangsky的个人博客

将第一个例子修改成泛型:

package javase.paradigm;public class Point3
 { private T x; private T y; public T getX() { return x; } public void setX(T x) { this.x = x; } public T getY() { return y; } public void setY(T y) { this.y = y; } public static void main(String[] args) { //1 整数表示 Point3
 point3_1 = new Point3
(); point3_1.setX(10); point3_1.setY(20); int x1 = point3_1.getX(); int y1 = point3_1.getY(); System.out.println("整数表示,X坐标是:" + x1 + ",Y坐标是:" + y1); System.out.println("******************我是华丽的分割线**********************"); //2 字符串表示 Point3
 point3_2 = new Point3
(); point3_2.setX("东经 50度"); point3_2.setY("北纬 79度"); String x2 = point3_2.getX(); String y2 = point3_2.getY(); System.out.println("字符串表示,X坐标是:" + x2 + ",Y坐标是:" + y2); }}

三 一个类中定义多个泛型类型

package javase.paradigm;public class Nodepad
 { private K key; private V value; public void setKey(K key) { this.key = key; } public void setValue(V value) { this.value = value; } public void print(){ System.out.println("键:" + key + ",值:" + value); } public static void main(String[] args) { Nodepad
 nodepad = new Nodepad
(); nodepad.setKey("zifangsky"); nodepad.setValue(100); //测试 nodepad.print(); }}

输出:

键:zifangsky,值:100

四 泛型方法的使用

(1)格式:

       [访问权限]<泛型标志> 泛型标志 方法名称([泛型标志 参数名称])

(2)测试代码:

package javase.paradigm;public class MethodDemo {	public 
 T getData(T t){ return t; } public void print(){ System.out.println("zifangsky"); } public static void main(String[] args) { MethodDemo methodDemo = new MethodDemo(); methodDemo.print(); int i = methodDemo.getData(10); System.out.println("int: " + i); String str = methodDemo.getData("hello world"); System.out.println("String: " + str); }}

输出:

zifangskyint: 10String: hello world

五 泛型接口的定义和两种实现方式

(1)泛型接口的定义:

package javase.paradigm;public interface Info
 { public T getVar();}

(2)接口的实现方式一:

在子类的定义上申明泛型类型:

package javase.paradigm;public class InfoImpl_1
 implements Info
 { private T var; public InfoImpl_1(T var) { this.var = var; } public T getVar() { return this.var; } public void setVar(T var) { this.var = var; }}

(3)接口的实现方式二:

直接在接口中指定具体类型:

package javase.paradigm;public class InfoImpl_2 implements Info
 { private String var; public InfoImpl_2(String var) { this.var = var; } public String getVar() { return this.var; } public void setVar(String var) { this.var = var; } }

六 一个综合实例

(1)简单分析:

       这里设计了Person这个类,但是一个人可能有多种信息展示形式,比如说:个人基本信息(姓名,性别,年龄。。。),联系方式(电话,地址,邮编。。。)。因此在Person中的信息类型就可以考虑申明为泛型。接着设计了一个空接口:Message和它的两个子类:Contact和Introduction,分别表示:联系方式和基本信息。

       在对Person进行定义的时候用了:class Person<T extends Message> ,这里的意思是这个泛型T只能是Message这个接口的子类,也就是说只能是我们先前定义的Contact和Introduction,避免了传递进来我们所不需要的其他信息

(2)实例代码:

package javase.paradigm;/** * 定义标识接口 * */interface Message{	}/** * 第一个子类,联系方式 * */class Contact implements Message{	private String address;	private String telphone;	private String zipcode;	public Contact(String address, String telphone, String zipcode) {		this.address = address;		this.telphone = telphone;		this.zipcode = zipcode;	}	/**	 * 重写toString方法	 * */	public String toString(){		return "联系方式:\n" + 				"\t|- 电话: " + telphone + "\n" + 				"\t|- 地址: " + address + "\n" +				"\t|- 邮编: " + zipcode + "\n";	}}/** * 第二个子类,个人信息 * */class Introduction implements Message{	private String name;	private String sex;	private int age;	private String job;	public Introduction(String name, String sex, int age, String job) {		this.name = name;		this.sex = sex;		this.age = age;		this.job = job;	}	/**	 * 重写toString方法	 * */	public String toString(){		return "基本信息:\n" + 				"\t|- 姓名: " + name + "\n" + 				"\t|- 性别: " + sex + "\n" +				"\t|- 年龄: " + age + "\n" +				"\t|- 工作: " + job + "\n";	}}/** * 定义泛型,并且T必须是Message这个接口的子类 * 避免了传递进来其他不需要的类型 * */public class Person
 { private T message; public Person(T message) { this.message = message; } public String toString(){ return message.toString(); } public static void main(String[] args) { //1 将泛型实例化成Contact类型 Person
 person_1 = new Person
(new Contact("http://www.zifangsky.cn", "10086", "1024")); System.out.println(person_1); System.out.println("******************我是华丽的分割线**********************"); //2 将泛型实例化成Introduction类型 Person
 person_2 = new Person
(new Introduction("zifangsky", "男", 256, "程序猿")); System.out.println(person_2); }}

输出:

联系方式:	|- 电话: 10086	|- 地址: http://www.zifangsky.cn	|- 邮编: 1024******************我是华丽的分割线**********************基本信息:	|- 姓名: zifangsky	|- 性别: 男	|- 年龄: 256	|- 工作: 程序猿