1. 为何要进行泛型编程?
泛型变成为不同类型集合提供相同的代码!省去了为不同类型而设计不同代码的麻烦!
2. 一个简单泛型类的定义:
1 public class PairTest1 2 { 3 public static void main(String[] args) 4 { 5 String[] arr = {"This","is","the","end","of","the","world"}; 6 Pair<String> mm = ArrayAlg.minmax(arr); 7 System.out.println("min = " + mm.getFirst()); 8 System.out.println("max = " + mm.getSecond()); 9 } 10 } 11 12 class Pair<T> 13 { 14 public Pair() {first = null; second = null;} 15 public Pair(T first,T second) {this.first = first; this.second = second;} 16 17 public T getFirst() {return first;} 18 public T getSecond() {return second;} 19 20 public void setFirst(T newValue) {this.first = newValue;} 21 public void setSecond(T newValue) {this.second = newValue;} 22 23 private T first; 24 private T second; 25 } 26 27 class ArrayAlg 28 { 29 public static Pair<String> minmax(String[] a) 30 { 31 if(a == null || a.length == 0) return null; 32 String min = a[0]; 33 String max = a[0]; 34 for(int i = 1; i < a.length; i++) 35 { 36 if(min.compareTo(a[i]) > 0) min = a[i]; 37 if(max.compareTo(a[i]) < 0) max = a[i]; 38 } 39 return new Pair<String>(min,max); 40 } 41 }
上面这段代码中定义了一个泛型类。
2. 泛型函数:
下面是一个泛型函数定义的实例:
1 class ArrayAlg 2 { 3 public static <T> T getMiddle(T[] a) 4 { 5 return a[a.length / 2]; 6 } 7 }
注意,一个泛型函数可以定义在一个普通类中,也可以定义在一个泛型类中。
注意在上述模板函数的定义中,模板参数变量的位置,是出现在public static 修饰符之后的!
下面是模板函数的调用:
String[] arr = {"this","is","me"}; String middle = ArrayAlg.<String>getMiddle(arr); System.out.println(middle);
在实际中,调用泛型函数时并不需要在函数前加上<String>操作符。java会自动进行类型检查,比如上面getMiddle会自动检查出参数arr的类型是String[]的,这样推测出
T的类型是String。
3. 类型变量的约束:
public static <T extends Comparable> Pair<T> minmax(T[] a) { if(a == null || a.length == 0) return null; T min = a[0]; T max = a[0]; for(int i = 1; i < a.length; i++) { if(min.compareTo(a[i]) > 0) min = a[i]; if(max.compareTo(a[i]) < 0) max = a[i]; } return new Pair<T>(min,max); }
这里为类型变量T添加了约束T extends Comparable,要求T实现Comarable接口中的CompareTo函数!
Java中泛型变量的约束条件是: <T extends BoundingType>, 你可以让T继承一个类,或者继承任意一个接口,或者同时继承一个类和一个接口,但无论如何
不能继承多个类!
4.泛型代码和虚拟机之间的关系:
虚拟机中没有泛型类型的对象,所有的对象都是具体的类型的对象。
当定义了一个泛型类型之后,编译器会自动提供一个相对应的原始类型(raw type):
raw type的类型名和泛型类型名相同,只是泛型类型参数被去掉了。类型变量被替换成成限定类型对象或Object类型对象。
1 class Pair<T> 2 { 3 public Pair() {first = null; second = null;} 4 public Pair(T first,T second) {this.first = first; this.second = second;} 5 6 public T getFirst() {return first;} 7 public T getSecond() {return second;} 8 9 public void setFirst(T newValue) {this.first = newValue;} 10 public void setSecond(T newValue) {this.second = newValue;} 11 12 private T first; 13 private T second; 14 }
上面的类型对应的原始类型是:
class Pair<T> { public Pair() {first = null; second = null;} public Pair(Object first,Object second) {this.first = first; this.second = second;} public Object getFirst() {return first;} public Object getSecond() {return second;} public void setFirst(Object newValue) {this.first = newValue;} public void setSecond(Object newValue) {this.second = newValue;} private Object first; private Object second; }