本文共 5919 字,大约阅读时间需要 19 分钟。
-- 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大家可以看到使用泛型非常简单,使用泛型后,当我们从 list 中 get 数据时,无需进行强制类型转换,从而避免了在运行时可能发生的 ClassCastException,同时也使我们的程序可读性更好。list2 = new ArrayList (); list2.add("尚波"); name = list2.get(0); // 从 Java SE 7 开始,只要编译器从上下文中能够推断出类型参数,你就可以使用 <> 代替 List list3 = new ArrayList<>(); }}
下面我们通过一个简单的例子来看看如何定义一个泛型类。
class MyList在上面的例子中,我们定义 MyList 类, 它有一个类型参数 T (泛型类也可以有多个类型参数),在类中我们可以使用该类型参数定义域或指定方法参数的类型,返回值的类型等。通常类型参数使用大写形式,在 Java 库中,使用 E 表示集合类型,使用 K 和 V 表示 key 和 value,使用 T(需要时也可以用临近的字母U和S) 表示任意类型。{ private List values = new ArrayList (); public MyList() { } public void add(T value) { values.add(value); } public T get(int index) { return values.get(index); }}
事实上,我们也可以给一个普通类定义一个泛型方法,下面是一个简单的例子。
public class Test { public staticT 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 是继承自某个类或实现了多个接口的类型,采用如下的形式。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; }}
由于 Java 是单继承,所以上面的限定结构中只能有一个类且必须是第一个。
我们先看一个例子。
import java.util.ArrayList;import java.util.List;public class Test { public static void main(String[] args) { ListprintInformation 方法的参数类型是 List<Person>, 虽然 Student 是 Person 的子类, 但是该方法却不能接受 List<Student> 类型的参数, 所以上面有一处编译错误,解决的办法是,将printInformation方法改成如下通配符的形式,表示 List 中可以是 Person 或它的子类。pl = new ArrayList (); pl.add(new Person("123456789987654321", "尚波")); printInformation(pl); List sl = new ArrayList (); sl.add(new Student("123456789987654321", "尚波", "五年二班")); printInformation(sl); // 此处编译错误 } public static void printInformation(List 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; }}
public static void printInformation(List 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) { ListselectStudent 方法有一个 List<Student> 类型的参数,它用来存储姓尚的学生,理论上 List<Person> 和 List<Object> 都可以用来存储学生,因为 Person 和 Object 是 Student 的超类,但是现在该方法却不能接受 List<Person> 和 List<Object>,所以上面的程序有两处编译错误,解决的办法是,将 selectStudent 方法改成如下通配符的形式,表示 List 中可以是 Student 或它的超类。sl = new ArrayList (); sl.add(new Student("123456789987654321", "尚波", "五年二班")); List
public static void selectStudent(List我们再看一个例子。sl, List 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看到了吗?我们甚至还可以只使用问号来限定 List,初看起来,使用问号限定和不使用限定没有任何区别,事实上它们之间有本质区别,使用问号限定后我们将不能往 List 中添加对象,所以上面有一处编译错误。sl = new ArrayList (); 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; }}
事实上,虚拟机并不认识泛型,所有的类型变量在编译的时候都会被擦除,从而将一个泛型类转换成为一个普通类。
--- 更多参见: -- 声 明:转载请注明出处 -- Last Updated on 2015-10-29 -- Written by ShangBo on 2012-06-12 -- End