博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java 泛型
阅读量:4050 次
发布时间:2019-05-25

本文共 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
list2 = new ArrayList
(); list2.add("尚波"); name = list2.get(0); // 从 Java SE 7 开始,只要编译器从上下文中能够推断出类型参数,你就可以使用 <> 代替
List
list3 = new ArrayList<>(); }}

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

 

 

定义泛型类

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

class MyList
{ private List
values = new ArrayList
(); 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 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 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 是继承自某个类或实现了多个接口的类型,采用如下的形式。

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

 

通配符类型

 我们先看一个例子。

import java.util.ArrayList;import java.util.List;public class Test {	public static void main(String[] args) {		List
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; }}

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

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) {		List
sl = new ArrayList
(); sl.add(new Student("123456789987654321", "尚波", "五年二班")); List
result1 = new ArrayList(); selectStudent(sl, result1); // 此处编译错误 List
result2 = new ArrayList
(); selectStudent(sl, result2); // 此处编译错误 List
result3 = new ArrayList
(); selectStudent(sl, result3); } public static void selectStudent(List
sl, List
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
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
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; }}

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

擦除类型

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

 

---
更多参见:
--
声 明:转载请注明出处
-- Last Updated on 2015-10-29
-- Written by ShangBo on 2012-06-12
-- End
你可能感兴趣的文章
linux安装usb wifi接收器
查看>>
多线程使用随机函数需要注意的一点
查看>>
getpeername,getsockname
查看>>
让我做你的下一行Code
查看>>
浅析:setsockopt()改善程序的健壮性
查看>>
关于对象赋值及返回临时对象过程中的构造与析构
查看>>
VS 2005 CRT函数的安全性增强版本
查看>>
Visual Studio 2010:C++0x新特性
查看>>
drwtsn32.exe和adplus.vbs进行dump文件抓取
查看>>
cppcheck c++静态代码检查
查看>>
在C++中使用Lua
查看>>
一些socket的编程经验
查看>>
socket编程中select的使用
查看>>
可以在线C++编译的工具站点
查看>>
关于无人驾驶的过去、现在以及未来,看这篇文章就够了!
查看>>
所谓的进步和提升,就是完成认知升级
查看>>
为什么读了很多书,却学不到什么东西?
查看>>
长文干货:如何轻松应对工作中最棘手的13种场景?
查看>>
如何用好碎片化时间,让思维更有效率?
查看>>
No.174 - LeetCode1305 - 合并两个搜索树
查看>>