文章目录
为什么要使用泛型程序
使用泛型前:
public class GenericTest01 { public static void main(String[] args) { List l = new ArrayList(); l.add("abcd"); l.add(100); for(Object obj : l){ String s = (String) obj; System.out.println(s); } } }
缺点分析:
- 每获取一个值需要强制类型转换。
String s = (String) obj
- 这里没有类型检查,可以向ArrayList中添加任何类型对象,这里因为往ArrayList中添加了Integer类型数据,强制类型转换在这里会报错,如下:
使用泛型后:
public class GenericTest01 { public static void main(String[] args) { List<String> l = new ArrayList<>(); l.add("abcd"); for(String obj : l){ String s = obj; System.out.println(s); } } }
优点分析:
- 从ArrayList中得到的数据不需要强制类型转换,编译器就知道返回类型是String而不是Object:
String s = obj;
。 - 编译器可以进行检查,避免加入错误的类型对象,如下:
- 泛型的使用让程序具有更好的可读性和安全性。
定义泛型类
定义一个简单的泛型类:
//这里T是类型变量名,可以自己随便取 //在实例化泛型类时,必须指定T的具体类型 public class GenericTest02<T> { //在类中,就可以用T来代替某一特定类型 //该特定类型在实例化泛型类时确定 private T k; public void add(T k){ this.k = k; } public T get(){ return k; } }
GenericTest02类引入了一个类型变量T,用 < > 括起来,并且放在类名的后边。其中泛型变量的名字可以自己随便,常见的如T、E、K、V等形式的参数常用于表示泛型。
泛型类的实例化
public static void main(String[] args) { GenericTest02<Integer> g = new GenericTest02<Integer>(); } }
泛型类的实例化同样也是在类名后加 < > ,并且在尖括号中加入具体类型。
注意:
具体类型必须是引用数据类型,不能是基本数据类型。
实例化时也可以这样写:
GenericTest02 g = new GenericTest02<>();
后边 < > 内的内容可以省略,因为编译器可以自己判断出来。
引入多个类型变量的泛型类:
public class GenericTest02<T,K> { private T k1; private K k2; public void add(T k1, K k2){ this.k1 = k1; this.k2 = k2; } public T getk1(){ return k1; } public K getk2(){ return k2; } }
Java允许定义泛型类时引入多个泛型变量,如上,在实例化时,每一个泛型变量都需要指定特定类型。
GenericTest02 g = new GenericTest02<>();
定义泛型方法
在普通类中定义一个泛型方法
public class GenericTest03 { public<T> T getMid(T[] name){ return name[name.length / 2]; } }
这是一个在普通类中定义的泛型类,类型变量是放在修饰符的后边(这里是public),返回类型的前面(这里返回类型是T)。
泛型方法的使用
public static void main(String[] args) { GenericTest03 g = new GenericTest03(); String [] s = {"张三","李四","王五"}; String midName = g.<String>getMid(s); }
调用泛型方法时,仍然是在方法名前加 <具体类型>。
在大多数情况下,调用泛型方法时,< String > 是可以省略的,编译器通过参数很容易的判断出T一定是String。
在泛型类中定义泛型方法
public class GenericTest03<K> { public<T> T getMid(T name[]){ return name[name.length / 2]; } public static void main(String[] args) { GenericTest03<Integer> g = new GenericTest03(); String [] s = {"张三","李四","王五"}; String mid = g.<String>getMid(s); System.out.println(mid); } }
类型变量的限定
未使用类型限定时:
public class GenericTest04 { public static<T> T getMin(T[] a){ if(a == null || a.length == 0) return null; T smallest = a[0]; for(int i = 0; i < a.length; i++){ if(smallest.compareTo(a[i]) > 0){ smallest = a[i]; } } return smallest; } }
以上方法编译时就会报错:
因为只有实现了Comparable接口的类才能调用**compareTo()**方法。
但是可以这样做:
这样就限定了,后期指定T的具体类型时,必须是实现了Comparable接口的类。
注意1:
这里Comparable虽然是接口,但是关键字却写的是extends,因为限定可以是类,也可以是接口,T必须是限定类型的子类型,extend更接近于子类的概念,所有Java规定,这里统一用extends。