java 泛型详解( 四 )

4.6.3 泛型方法与可变参数再看一个泛型方法和可变参数的例子:
public <T> void printMsg( T... args){for(T t : args){Log.d("泛型测试","t is " + t);}}printMsg("111",222,"aaaa","2323.4",55.55);4.6.4 静态方法与泛型静态方法有一种情况需要注意一下,那就是在类中的静态方法使用泛型:静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上 。
即:如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法。
public class StaticGenerator<T> {......../*** 如果在类中定义使用泛型的静态方法,需要添加额外的泛型声明(将这个方法定义成泛型方法)* 即使静态方法要使用泛型类中已经声明过的泛型也不可以 。* 如:public static void show(T t){..},此时编译器会提示错误信息:"StaticGenerator cannot be refrenced from static context"*/public static <T> void show(T t){}}4.6.5 泛型方法总结泛型方法能使方法独立于类而产生变化,以下是一个基本的指导原则:
无论何时,如果你能做到,你就该尽量使用泛型方法 。也就是说,如果使用泛型方法将整个类泛型化,那么就应该使用泛型方法 。另外对于一个static的方法而已,无法访问泛型类型的参数 。所以如果static方法要使用泛型能力,就必须使其成为泛型方法 。4.6 泛型上下边界在使用泛型的时候,我们还可以为传入的泛型类型实参进行上下边界的限制,如:类型实参只准传入某种类型的父类或某种类型的子类 。
为泛型添加上边界,即传入的类型实参必须是指定类型的子类型
public void showKeyValue1(Generic<? extends Number> obj){Log.d("泛型测试","key value is " + obj.getKey());}Generic<String> generic1 = new Generic<String>("11111");Generic<Integer> generic2 = new Generic<Integer>(2222);Generic<Float> generic3 = new Generic<Float>(2.4f);Generic<Double> generic4 = new Generic<Double>(2.56);//这一行代码编译器会提示错误,因为String类型并不是Number类型的子类//showKeyValue1(generic1);showKeyValue1(generic2);showKeyValue1(generic3);showKeyValue1(generic4);如果我们把泛型类的定义也改一下:
public class Generic<T extends Number>{private T key;public Generic(T key) {this.key = key;}public T getKey(){return key;}} 
//这一行代码也会报错,因为String不是Number的子类Generic<String> generic1 = new Generic<String>("11111");再来一个泛型方法的例子:
 
//在泛型方法中添加上下边界限制的时候,必须在权限声明与返回值之间的<T>上添加上下边界,即在泛型声明的时候添加//public <T> T showKeyName(Generic<T extends Number> container),编译器会报错:"Unexpected bound"public <T extends Number> T showKeyName(Generic<T> container){System.out.println("container key :" + container.getKey());T test = container.getKey();return test;}通过上面的两个例子可以看出:泛型的上下边界添加,必须与泛型的声明在一起。
4.7 关于泛型数组要提一下看到了很多文章中都会提起泛型数组,经过查看sun的说明文档,在java中是”不能创建一个确切的泛型类型的数组”的 。
也就是说下面的这个例子是不可以的:
List<String>[] ls = new ArrayList<String>[10];而使用通配符创建泛型数组是可以的,如下面这个例子:
List<?>[] ls = new ArrayList<?>[10]; 这样也是可以的:
List<String>[] ls = new ArrayList[10];下面使用Sun的一篇文档的一个例子来说明这个问题:
List<String>[] lsa = new List<String>[10]; // Not really allowed.Object o = lsa;Object[] oa = (Object[]) o;List<Integer> li = new ArrayList<Integer>();li.add(new Integer(3));oa[1] = li; // Unsound, but passes run time store checkString s = lsa[1].get(0); // Run-time error: ClassCastException. 
这种情况下,由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给oa[1]赋上一个ArrayList而不会出现异常,但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错 。而对泛型数组的声明进行限制,对于这样的情况,可以在编译期提示代码有类型安全问题,比没有任何提示要强很多 。


推荐阅读