声明一个泛型类并实例化
Box是一个泛型类,这里的T是参数传递给泛型类的泛型,它可以是任何对象。而t则是T的一个实例。个人理解泛型,就是泛化类型,将具体的类型用统一的类指代。add和get是定义的两个方法。
public class Box<T>{
private T t;
public void add(T t){
this.t = t;
}
public void get(T t){
return t;
}
}
在main方法中,泛型类这样使用。其中intbox和strbox都是泛型类的对象,可以调用泛型类中已定义的方法。
Box<Integer> intbox = new Box<Integer>();
Box<String> strbox = new Box<String>();
intbox.add(new Integer(1));
System.out.println(intbox.get());
//调用了泛型类中的方法,打印数字1
泛型类可以有多个类型参数,这就使得泛型可以当C++中的结构体来使用。当然,凭我现有的知识,结构体与类并无本质的差异。同时,可以用参数化类型来代替,比如传的不只是一个类,而是某个框架,如下例。
public static void main(String[] args){
Box<Integer,String> box = new Box<Integer,String>();
box.add(Integer.valueOf(100),"hello world");
Box2<Integer,List<String>> box2 = new Box2<Integer,List<String>>();
List<String> m = new ArrayList<String>();
m.add("Hello");m.add("world");
box2.add(Integer.valueOf(10),m);//此时的m是一个列表
}
class Box<T,S>{
private T t;
private S s;
public void add(T t,S s){
this.t = t;
this.s = s;
}
}
参数命名约定 也就是尖括号里的字母,这是一般的约定并无强制要求
字符 | 意义 |
---|---|
E | 由Java集合框架使用(list等) |
K | 表示映射中的键值(key) |
V | 表示映射中的值(value) |
N | 表示数字 |
T | 第一类通用参数 |
S | 第二类通用参数 |
U | 第三类通用参数 |
V | 第四类通用参数 |
有界类型参数
什么是泛型有界类型参数?就是限制允许传递给类型参数的类型。简单来说就是给泛型一定的条件,比如只允许接受Char类或者它的子类实例。要声明它,只需要后跟extend关键字和边界上限即可。如果需要多重边界,则用&连接。
public static <T extends Number & Comparable<T>> T maximum(T x,T y,T z){
T max = x;
if(y.compareTo(max)>0){
max = y;
}
if(z.compareTo(max)>0){
max = z;
}
return max;
}
public static void main(String[] args){
System.out.println(maximum(10,20,30));
System.out.println(maximum(22.1,33.2,44.3));
}
Java在List、Set、Map中都提供了泛型的支持,语法如下
List<T> list = new ArrayList<T>();
Set<T> set = new HashSet<T>();
Map<T> map = new HashMap<T>();
通配类型符
首先要知道,为什么需要通配类型?《Java语言程序设计》中有一个例子。
public static void main(String[] args){
GenericStack<Integer> intstack = new GenericStack<Integer>();
intstack.push(1);intstack.push(2);
System.out.println(max(intstack));
}
public static double max(GenericStack<Number> stack){
double max = stack.pop().doubleValue();
while(!stack.empty()){
double value = stack.pop().doubleValue();
if(value>max)max=value;
}
return max;
}
这段程序会出现编译错误,原因是虽然Integer是Number的子类,但GenericStack<Integer>
不是GenericStack<Number>
的子类。因此需要通配符规避这种错误。
?表示非受限通配符
?extend T 表示T或T的一个未知子类
?super T 表示T或T的一个父类
用public static double max(GeericStack<? extends Number> stack)
就可以改正上面的错误。
泛型类型擦除
泛型是使用一种称为类型消除的方法来实现的。编译器使用泛型类型信息来编译代码,但是随后会消除它。因此,泛型信息在运行时是不可用的。这种方法可以使泛型代码向后兼容使用原始类型的遗留代码。
泛型在编译的时候一旦确认其是安全的,就会将它转换为原始类型。不管实际的具体类型是什么,泛型类是被它所有实例共享的。
限制
不能使用E object = new E();
,因为运行时泛型类型E是不可用的。同理不能创建数组。
异常类不能是泛型。
静态环境下不允许类的参数是泛型类型。
除非由无界通配符进行参数化,否则不允许转换为参数化类型。如下段代码。
private static void add(Box<?> box){
Box<Integer> intbox = (Box<Integer>) box;
}
无法用instanceof验证。