详解Java泛型(一)之简单介绍
2016-12-09 16:48
477 查看
1. 概述
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。什么叫参数化类型呢?像java的方法有形参,然后调用方法的时候传递实参。而参数化类型,顾名思义就是把类型参数化,就是说类型是不固定的,是靠调用者传入进来的。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
比如说ArrayList类,在没有泛型的时候,获取的元素是Object类型的,要使用该元素,必须知道该元素的具体类型,并对其进行显示强制类型转换,而且一不小心就可能会抛出ClassCastException异常,不仅麻烦还不安全。就像下面的代码那样。
import java.util.ArrayList; import java.util.List; public class ArrayListDemo { public static void main(String[] args) { List list = new ArrayList(); //在list中添加一个字符串元素 list.add("123"); //正常类型转换 String str = (String) list.get(0); //会出现转换异常 Integer val = (Integer) list.get(0); } }
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。 如上面的例子用上了泛型,就可以在编译的时候知道错误。
import java.util.ArrayList; import java.util.List; public class ArrayListDemo { public static void main(String[] args) { List<String> list = new ArrayList<String>(); //在list中添加一个字符串元素 list.add("123"); String str = list.get(0);// 不用进行类型转换 Integer val = (Integer) list.get(0);// 编译出错 } }
下面就来具体介绍一下泛型的用法
2.类型参数
类型参数就是尖括号(“<>”)里的东西,就像是getVal(Intger val)的方法参数是Intger类型变量,到时候调用这个方法的时候传入Intger类型的实参即可,而类型参数传入的不是一个数据类型的变量,而是一个数据类型,如上面代码List<String> list = new ArrayList<String>();的就是传入了一个String类型。
3. 定义泛型类
泛型类即带类型参数的类,像ArrayList类就是带有类型参数的类也就是泛型类,那我们怎么自己定义一个泛型类呢?很简单,在类名的后面加上<>并在里面指定一个或多个类型变量,多个类型变量时使用逗号隔开。 比如说我有一个类,可以存储两个相同类型的值,代码就可以这样子实现。public class Pair<T> { private T t1; private T t2; public T getT1() { return t1; } public void setT1(T t1) { this.t1 = t1; } public T getT2() { return t2; } public void setT2(T t2) { this.t2 = t2; } }
可以看到Pair类有一个类型变量T,这个类型我们并不知道是什么,只有实例化的时候传进来才会知道,然后可以像下面的代码那样实例化泛型类
public class Main { public static void main(String[] args) { Pair<String> p = new Pair<String>(); p.setT1("这是t1"); p.setT2("这是t2"); String t1 = p.getT1(); String t2 = p.getT2(); System.out.println(t1); System.out.println(t2); } }
可以看到我用一个String类型作为实际的类型变量传进去,这样子Pair的set和get方法都是针对String类型的了。
4. 泛型方法
实际上,还可以定义一个带有类型变量的简单方法。如下面的代码public class ArrayMiddle { public static <T> T getMiddle(T ... ts){ return ts[ts.length/2]; } }
这里的泛型方法并不是定义在泛型类中的,而是定义在一个普通类中。其实泛型方法可以定义在普通类中,也可以定义在泛型类中。需要注意的是,类型参数放在修饰符(这里是public static)的后面,返回类型之前。这个泛型方法的功能是接受一些相同类型的变量(数量不确定),然后返回这些变量当中中间的那个变量。
可以像下面那样使用泛型方法
public class Main { public static void main(String[] args) { String middle = ArrayMiddle.<String>getMiddle("a","b","c"); System.out.println(middle); } }
输出结果是b
当然也可以像
String middle = ArrayMiddle.getMiddle("a","b","c");这样子调用泛型方法(一般我们都是这么用的),编译器可以根据上下文信息推断出该类型变量就是String类型。
5.类型变量的限定
现在考虑一个问题,我想让上面的泛型类Pair有一个getMax方法可以返回t1和t2中的最大值,那么我这的代码写出下面这样public class Pair<T> { private T t1; private T t2; public T getT1() { return t1; } public void setT1(T t1) { this.t1 = t1; } public T getT2() { return t2; } public void setT2(T t2) { this.t2 = t2; } public T getMax(){ int result = t1.compareTo(t2); if(result > 0) return t1; else return t2; } }
当然这段代码是不能编译通过的,因为你根本就不知道泛型变量T会是什么,很多类是没有compareTo方法的,但是实现了Comparable接口的类就会有这个方法。所以解决这个问题的的方案就是将T所属的类限制成实现了Comparable接口的类。所以我修改一下将
Pair<T>变为 Pair<T extends Comparable<T>>,就可以编译通过了。然后使用一下这个方法
public class Main { public static void main(String[] args) { Pair<Integer> p = new Pair<Integer>(); p.setT1(11); p.setT2(5); Integer max = p.getMax(); System.out.println(max); } }
输出结果为11
需要注意的是,因为Integer类实现了Comparable接口,所以可以像上面那样使用。而像Thread类是没实现Comparable接口的,如果将Thread类传入类型变量,编译就会出错,所以实例化的时候不可以传入没有实现Comparable接口的类型变量,这样子就把类型变量限定住了。
还需要注意的是,虽然Comparable是接口,但是还是用extends关键字来限定,而不是用implements关键字。无论是类或者接口都是用extends关键字来限定的。
多个限定类型之间用”&”分隔,如
Pair<T extends Comparable & Serializable>
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Debian 7.x 安装Oracle JAVA
- springmvc实现url路由功能
- spring boot 配置 druid/** * 配置druid * Created by adam on 4/11/16. */ @Configuration public class D
- api接口rsa加密
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解