java 泛型

-- Start

使用泛型

泛型是 Java SE 5 加入的新特性,使用泛型非常简单,下面是一个简单的例子。

import java.util.ArrayList;
import java.util.List;

public class Test {

	public static void main(String[] args) {
		// 未使用泛型
		List list1 = new ArrayList();
		list1.add("尚波");
		String name = (String)list1.get(0); // 需要强制类型转换
		
		
		// 使用泛型
		List<String> list2 = new ArrayList<String>();
		list2.add("尚波");
		name = list2.get(0);
		
		// 从 Java SE 7 开始,只要编译器从上下文中能够推断出类型参数,你就可以使用 <> 代替 <String>
		List<String> list3 = new ArrayList<>();
	}

}

大家可以看到使用泛型非常简单,使用泛型后,当我们从 list 中 get 数据时,无需进行强制类型转换,从而避免了在运行时可能发生的 ClassCastException,同时也使我们的程序可读性更好。

 

 

定义泛型类

下面我们通过一个简单的例子来看看如何定义一个泛型类。

class MyList<T> {

	private List<T> values = new ArrayList<T>();

	public MyList() {
	}

	public void add(T value) {
		values.add(value);
	}

	public T get(int index) {
		return values.get(index);
	}
}


在上面的例子中,我们定义 MyList 类, 它有一个类型参数 T (泛型类也可以有多个类型参数),在类中我们可以使用该类型参数定义域或指定方法参数的类型,返回值的类型等。通常类型参数使用大写形式,在 Java 库中,使用 E 表示集合类型,使用 K 和 V 表示 key 和 value,使用 T(需要时也可以用临近的字母U和S) 表示任意类型。


 

定义泛型方法

事实上,我们也可以给一个普通类定义一个泛型方法,下面是一个简单的例子。

public class Test {

	public static <T> T min(T[] a) {
		if (a == null || a.length == 0)
			return null;

		T min = a[0];
		for (T t : a) {
			if (t.compareTo(min) < 0) {
				min = t;
			}
		}

		return min;
	}
}

 

限定类型变量

事实上,上面的例子是有问题的,你看出来问题出在哪里了吗?问题就在类型变量 T 代表任何类,我们并不能保证每一个类中都有 compareTo 方法,除非这个类实现了 Comparable 接口。解决的办法也很简单,限定类型变量 T 为实现了Comparable 接口的类,下面的例子演示了如何限定类型变量。

public class Test {

	public static <T extends Comparable> T min(T[] a) {
		if (a == null || a.length == 0)
			return null;

		T min = a[0];
		for (T t : a) {
			if (t.compareTo(min) < 0) {
				min = t;
			}
		}

		return min;
	}
}


怎么样?很简单吧。我们也可以限定类型变量 T 是继承自某个类或实现了多个接口的类型,采用如下的形式。

<T extends MyClass & MyInterface1 & MyInterface2>

由于 Java 是单继承,所以上面的限定结构中只能有一个类且必须是第一个。

 

通配符类型

 我们先看一个例子。

import java.util.ArrayList;
import java.util.List;

public class Test {

	public static void main(String[] args) {
		List<Person> pl = new ArrayList<Person>();
		pl.add(new Person("123456789987654321", "尚波"));
		printInformation(pl);
		
		List<Student> sl = new ArrayList<Student>();
		sl.add(new Student("123456789987654321", "尚波", "五年二班"));
		printInformation(sl); // 此处编译错误
	}

	public static void printInformation(List<Person> pl) {
		if (pl == null) {
			return;
		}

		for (Person p : pl) {
			System.out.println(p.getID() + ":" + p.getName());
		}
	}

}

class Person {
	private String ID;
	private String name;

	public Person() {
	}

	public Person(String ID, String name) {
		this.ID = ID;
		this.name = name;
	}

	public String getID() {
		return ID;
	}

	public void setID(String iD) {
		ID = iD;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

class Student extends Person {
	private String className;
	
	public Student(String ID, String name, String className) {
		super(ID, name);
		this.className = className;
	}

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}
}


printInformation 方法的参数类型是 List<Person>, 虽然 Student 是 Person 的子类, 但是该方法却不能接受 List<Student> 类型的参数, 所以上面有一处编译错误,解决的办法是,将printInformation方法改成如下通配符的形式,表示 List 中可以是 Person 或它的子类

public static void printInformation(List<? extends Person> pl) {
	if (pl == null) {
		return;
	}

	for (Person p : pl) {
		System.out.println(p.getID() + ":" + p.getName());
	}
}


我们再看一个例子。

import java.util.ArrayList;
import java.util.List;

public class Test {

	public static void main(String[] args) {

		List<Student> sl = new ArrayList<Student>();
		sl.add(new Student("123456789987654321", "尚波", "五年二班"));

		List<Object> result1 = new ArrayList<Object>();
		selectStudent(sl, result1); // 此处编译错误

		List<Person> result2 = new ArrayList<Person>();
		selectStudent(sl, result2); // 此处编译错误

		List<Student> result3 = new ArrayList<Student>();
		selectStudent(sl, result3);
	}

	public static void selectStudent(List<Student> sl, List<Student> result) {
		for (Student s : sl) {
			if (s.getName().startsWith("尚")) {
				result.add(s);
			}
		}
	}

}

class Person {
	private String ID;
	private String name;

	public Person() {
	}

	public Person(String ID, String name) {
		this.ID = ID;
		this.name = name;
	}

	public String getID() {
		return ID;
	}

	public void setID(String iD) {
		ID = iD;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

class Student extends Person {
	private String className;

	public Student(String ID, String name, String className) {
		super(ID, name);
		this.className = className;
	}

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}
}


selectStudent 方法有一个 List<Student> 类型的参数,它用来存储姓尚的学生,理论上 List<Person> 和 List<Object> 都可以用来存储学生,因为 Person 和 Object 是 Student 的超类,但是现在该方法却不能接受 List<Person> 和 List<Object>,所以上面的程序有两处编译错误,解决的办法是,将 selectStudent 方法改成如下通配符的形式,表示 List 中可以是 Student 或它的超类

public static void selectStudent(List<Student> sl, List<? super Student> result) {
	for (Student s : sl) {
		if (s.getName().startsWith("尚")) {
			result.add(s);
		}
	}
}


我们再看一个例子。

import java.util.ArrayList;
import java.util.List;

public class Test {

	public static void main(String[] args) {

		List<Person> sl = new ArrayList<Person>();
		sl.add(new Person("123456789987654321", "尚波"));

		printInformation(sl);
	}

	public static void printInformation(List<?> sl) {
		for (Object p : sl) {
			System.out.println(p);
		}

		sl.add(new Person("123456789987654321", "尚波")); // 此处编译错误
	}

}

class Person {
	private String ID;
	private String name;

	public Person() {
	}

	public Person(String ID, String name) {
		this.ID = ID;
		this.name = name;
	}

	public String getID() {
		return ID;
	}

	public void setID(String iD) {
		ID = iD;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}


 看到了吗?我们甚至还可以只使用问号来限定 List,初看起来,使用问号限定和不使用限定没有任何区别,事实上它们之间有本质区别,使用问号限定后我们将不能往 List 中添加对象,所以上面有一处编译错误。

擦除类型

事实上,虚拟机并不认识泛型,所有的类型变量在编译的时候都会被擦除,从而将一个泛型类转换成为一个普通类。
 

--- 更多参见: Java SE 精萃
-- 声 明:转载请注明出处
-- Last Updated on 2015-10-29
-- Written by ShangBo on 2012-06-12
-- End
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值