Java高级特性之泛型
前言
想写一下关于 Java 一些高级特性的文章,虽然这些特性在平常实现普通业务时不必使用,但如果想写出优雅而高扩展性的代码,或是想读得懂一些优秀的源码,这些特性又是不可避免的。
如果对这些特性不了解,不熟悉特性的应用场景,使用时又因为语法等原因困难重重,很难让人克服惰性去使用它们,所以身边总有一些同事,工作了很多年,却从没有用过 Java 的某些高级特性,写出的代码总是差那么一点儿感觉。
为了避免几年后自己的代码还是非常 low,我准备从现在开始深入理解一下这些特性。本文先写一下应用场景最多的泛型。
文章欢迎转载,请尊重作者劳动成果,带上原文链接:http://www.cnblogs.com/zhenbianshu/p/9029148.html
泛型是什么
首先来说泛型是什么。泛型的英文是 generics
,中文意思是通用的、一类的,结合其应用场景,我理解泛型是一种 通用类型
。但我们一般指泛型都是指其实现方式,也就是 将类型参数化。
对于 Java 这种强类型语言来说,如果没有泛型的话,处理相同逻辑不同类型的需求会非常麻烦。
如果想写一个对 int 型数据的快速排序,我们编码为(不是主角,网上随便找的=_=):
public static void quickSort(int[] data, int start, int end) { int key = data[start]; int i = start; int j = end; while (i < j) { while (data[j] > key && j > i) { j--; } data[i] = data[j]; while (data[i] < key && i < j) { i++; } data[j] = data[i]; } data[i] = key; if (i - 1 > start) { quickSort(data, start, i - 1); } if (i + 1 < end) { quickSort(data, i + 1, end); } }
可是如果需求变了,现在需要实现 int 和 long 两种数据类型的快排,那么我们需要利用 Java 类方法重载功能,复制以上代码,将参数类型改为 double 粘贴一遍。可是,如果还要实现 float、double 甚至字符串、各种类的快速排序呢,难道每添加一种类型就要复制粘贴一遍代码吗,这样未必太不优雅。
当然我们也可以声明传入参数为 Object,并在比较两个元素大小时,判断元素类型,并使用对应的方法比较。这样,代码就会恶心在类型判断上了。不优雅的范围小了一点,并不能解决问题。
这时,我们考虑使用通用类型(泛型),将快排方法的参数设置为一个通用类型,无论什么样的参数,只要实现了 Comparable 接口,都可以传入并排序。
public static <T extends Comparable<T>> void quickSort(T[] data, int start, int end) { T key = data[start]; int i = start; int j = end; while (i < j) { while (data[j].compareTo(key) > 0 && j > i) { j--; } data[i] = data[j]; while (data[i].compareTo(key) < 0 && i < j) { i++; } data[j] = data[i]; } data[i] = key; if (i - 1 > start) { quickSort(data, start, i - 1); } if (i + 1 < end) { quickSort(data, i + 1, end); } }
那么,可以总结一下泛型的应用场景了,当遇到以下场景时,我们可以考虑使用泛型:
- 当参数类型不明确,可能会扩展为多种时。
- 想声明参数类型为
Object
,并在使用时用instanceof
判断时。
需要注意,泛型只能替代Object的子类型
,如果需要替代基本类型,可以使用包装类,至于为什么,会在下文中说明。
使用
然后我们来看一下,泛型怎么用。
声明
泛型的声明使用 <占位符 [,另一个占位符] >
的形式,需要在一个地方同时声明多个占位符时,使用 ,
隔开。占位符的格式并无限制,不过一般约定使用单个大写字母,如 T 代表类型(type),E 代表元素*(element)等。虽然没有严格规定,不过为了代码的易读性,最好使用前检查一下约定用法。
泛型指代一种参数类型,可以声明在类、方法和接口上。
我们最常把泛型声明在类上: