为什么要使用泛型?
泛型的引入,是java语言的来讲是一个较大的功能增强。同时对于编译器也带来了一定的增强,为了支持泛型,java的类库都做相应的修改以支持泛型的特性。(科普:实际上java泛型并不是 jdk5(2004发布了jdk5) 才提出来的,早在1999年的时候,泛型机制就是java最早的规范之一)
泛型的优点
1.提供了java的类型安全
泛型在很大程度上来提高了java的程序安全。例如在没有泛型的情况下,很容易将字符串 123 转成 Integer 类型的 123 亦或者 Integer 转成 String,而这样的错误是在编译期无法检测。而使用泛型,则能很好的避免这样的情况发生。2.不需要烦人的强制类型转换
泛型之所以能够消除强制类型转换,那是因为程序员在开发的时候就已经明确了自己使用的具体类型,这不但提高了代码的可读性,同样增加了代码的健壮性。3.提高了代码的重用性
泛型的程序设计,意味着编写的代码可以被很多不同类型的对象所重用
在泛型规范正式发布之前,泛型的程序设计是通过继承来实现的,但是这样子有两个严重的问题
① 取值的时候需要强制类型转换,否则拿到的都是 Object
② 编译期不会有错误检查
代码展示;
1.编译期不会有错误检查
public class DonCheckInCompile {
public static void main(String[] args) {
List list = new ArrayList();
list.add("a");
list.add(3);
System.out.println(list);
}
}
程序不会出错,还能正常输出
2.强制类型转换
public static void main(String[] args) {
List list = new ArrayList();
list.add("a");
list.add(3);
for (Object o : list) {
System.out.println((String)o);
}
}
因为你并不知道实际集合中的元素到底是哪些类型的,所以在使用的时候也是不确定的,如果在强转的时候,那必然会带来意想不到的错误,这样潜在的问题就好像是定时炸弹,肯定是不允许发生的。所以这就更体现了泛型的重要性。
3. 泛型方法
在 java 中,泛型方法可以使用在成员方法、构造方法和静态方法中。语法如下:
public <申明泛型的类型> 类型参数 fun();如 public T fun(T t);这里的 T 表示一个泛型类型,而 表示我们定义了一个类型为 T 的类型,这样的 T 类型就可以直接使用了,且 需要放在方法的返回值类型之前。T 即在申明的时候是不知道具体的类型的,只有的使用的时候才能明确其类型,T 不是一个类,但是可以当作是一种类型来使用。下面来通过具体的例子来解释说明,以下代码将数组中的指定的两个下标位置的元素进行交换(不要去关注实际的需求是什么),第一种 Integer 类型的数组
public class WildcardCharacter {
public static void main(String[] args) {
Integer[] arrInt = {1, 2, 3, 4, 5, 6, 7, 8, 9};
change(arrInt, 0, 8);
System.out.println("arr = " + Arrays.asList(arrInt));
}
/**
* 将数组中的指定两个下标位置的元素交换
*
* @param arr 数组
* @param firstIndex 第一个下标
* @param secondIndex 第二个下标
*/
private static void change(Integer[] arr, int firstIndex, int secondIndex) {
int tmp = arr[firstIndex];
arr[firstIndex] = arr[secondIndex];
arr[secondIndex] = tmp;
}
}
第二种是String类型的数组
编译直接都不会通过,那是必然的,因为方法定义的参数就是 Integer[] 结果你传一个 String[],玩呢。。。所以这个时候只能是再定义一个参数类型是 String[]的。
那要是再来一个 Double 呢?Boolean 呢?是不是这就产生问题了,虽然说这种问题不是致命的,多写一些重复的代码就能解决,但这势必导致代码的冗余和维护成本的增加。所以这个时候泛型的作用就体现了,我们将其改成泛型的方式。
/**
* @param t 参数类型 T
* @param firstIndex 第一个下标
* @param secondIndex 第二个下标
* @param <T> 表示定义了一个类型 为 T 的类型,否则没人知道 T 是什么,编译期也不知道
*/
private static <T> void changeT(T[] t, int firstIndex, int secondIndex) {
T tmp = t[firstIndex];
t[firstIndex] = t[secondIndex];
t[secondIndex] = tmp;
}
接下来调用就简单了
public static void main(String[] args) {
//首先定义一个Integer类型的数组
Integer[] arrInt = {1, 2, 3, 4, 5, 6, 7, 8, 9};
//将第 1 个和第 9 个位置的元素进行交换
changeT(arrInt, 0, 8);
System.out.println("arrInt = " + Arrays.asList(arrInt));
// 然后在定义一个String类型的数组
String[] arrStr = {"a", "b", "c", "d", "e", "f", "g"};
//将第 1 个和第 2 个位置的元素进行交换
changeT(arrStr, 0, 1);
System.out.println("arrStr = " + Arrays.asList(arrStr));
}
问题迎刃而解,至于普通的泛型方法和静态的泛型方法是一样的使用,只不过是一个数据类一个属于类的实例的,在使用上区别不大
下篇可以介绍下 构造方法