本文为从网上东拼西凑的java泛型学习笔记,摘出了我认为有价值的部分,尚未整理,先放在这里备份。
http://docs.oracle.com/javase/1.5.0/docs/guide/language/generics.html
泛型在类、接口和方法中定义,在实现(extends,implements)和实例化时使用。 定义类或接口时,使用"<E extends Fruit>"这种形式,之后就可以在类中对E进行操作。 定义方法所接收的参数时,使用"List<? extends Fruit>"这种形式,就可以接收这个范围的List做参数。 实例化时,不能使用问号这种形式来指定泛型——不能new List<? extends Apple>(); 继承或实现时,也不能使用问号这种形式来指定泛型——不能public interface MyList extends List<? extends Apple> 关于extends和super关键字的PECS(producer-extends, consumer-super)原则: 如果参数化类型表示一个T生产者,就使用<? extends T>,因为它只能get,用于将数据从生产者取出(只要生产者可以生产T的子类,那就一定可以生产T); 如果参数化类型表示一个T消费者,就使用<? super T>,因为它只能add,用于将数据add入消费者(只要消费者可以消费T的超类,那就一定可以消费T)。http://www.infoq.com/cn/articles/cf-java-generics 泛型的继承原则: 1,相同类型参数的泛型类的关系取决于泛型类自身的继承体系结构。即List<String>是Collection<String> 的子类型,List<String>可以替换Collection<String>。这种情况也适用于带有上下界的类型声明。 2,当泛型类的类型声明中使用了通配符的时候, 其子类型可以在两个维度上分别展开。如对Collection<? extends Number>来说,其子类型可以在Collection这个维度上展开,即List<? extends Number>和Set<? extends Number>等;也可以在Number这个层次上展开,即Collection<Double>和 Collection<Integer>等。如此循环下去,ArrayList<Long>和 HashSet<Double>等也都算是Collection<? extends Number>的子类型。 3,如果泛型类中包含多个类型参数,则对于每个类型参数分别应用上面的规则。 泛型的定义原则: 1,泛型类与一般的Java类基本相同,只是在类和接口定义上多出来了用<>声明的类型参数。 2,一个类可以有多个类型参数,如 MyClass<X, Y, Z>。 3,每个类型参数在声明的时候可以指定上界。 4,所声明的类型参数在Java类中可以像一般的类型一样作为方法的参数和返回值,或是作为域和局部变量的类型。 5,由于类型擦除机制,类型参数并不能用来创建对象或是作为静态变量的类型。
http://www.ibm.com/developerworks/cn/java/j-jtp01255.html 如果没有向后兼容性顾虑,那么Collection框架会这么设计(而实际上不是): interface Collection<E> { public T[] toArray(Class<T super E> elementClass); } 这样很通用,假设E是Apple类,那么传入任何一个Apple的父类(例如Fruit)都合法,会返回Fruit数组。 如果传入Object,那就相当于现在Collection接口的Object[] toArray()方法了。 同样,如果没有向后兼容性顾虑,那么Collection框架的remove和removeAll会这么写(而实际上不是): interface Collection<E> { public boolean remove(E e); // not really public void removeAll(Collection<? extends E> c); // not really } 缺陷是:只能传入当前泛型的兼容类型,不能传入任意Object或Collection<Object>——这样无法到兼容之前的API定义。 不能创建泛型类型的对象,因为编译器不知道要调用什么构造函数。如果泛型类需要构造用泛型类型参数来指定类型的对象,那么构造函数应该接受类文字(Foo.class)并将它们保存起来,以便通过反射创建实例(类似于上述Collection的toArray方法)
http://www.cnblogs.com/stephen-liu74/archive/2012/01/20/2228938.html 类型安全的异构容器(内部用Map<Class<?>,Object>来实现): public class Favorites { public <T> void putFavorite(Class<T> type,T instance); public <T> T getFavorite(Class<T> type); } 例如用于数据库不定数目的columns:每个cell的数据都以这种方式指定类型保存Favorites到容器中,再将此容器当作元素保存到更上层的结果容器中。 不能实例化泛型类型的数组:new List<String>[3]是不合法的。 但是在可以确定类型的情况下,将Object数组强制转换成泛型数组是合法的,例如ArrayList的源码:return (T[]) Arrays.copyOf(elementData, size, a.getClass()); 泛型方法: 声明方法时将用到的类型参数列在前面即可(所在类上不需要定义此参数类型): public static <E> Set<E> union(Set<E> s1,Set<E> s2) ; 静态工具方法特别适合这样写。
http://blog.csdn.net/mai0net/article/details/7320399 一般来说编写java泛型方法时,返回值类型和至少一个参数类型应该是泛型,而且类型应该是一致的,如果只有返回值类型或参数类型之一使用了泛型,这个泛型方法的使用就大大的限制了,基本限制到跟不用泛型一样的程度。 第一种:public static <T extends CommonService> T getService(Class<T> clazz); NoticeService noticeService=CommonService.getService(NoticeService.class);//正确的使用第一种泛型方法,不会出现编译错误。 NoticeService noticeService=CommonService.getService(UserService.class);//不正确的使用第一种泛型方法,会出现编译错误。 第二种:public static <T> T getService(Class<? extends CommonService> clazz); NoticeService noticeService=CommonService.getService(NoticeService.class);//正确的使用第二种泛型方法,不会出现编译错误,逻辑也正确,运行时不会出现异常。 NoticeService noticeService=CommonService.getService(UserService.class);//不正确的使用第二种泛型方法,不会出现编译错误,但逻辑不正确,运行时会出现异常,危险!
网上不少关于泛型的说明很好,可是不知道是不是jdk版本问题,居然没办法实际通过编译,于是我只好自己在jdk1.7下一一重写和尝试,最后加上总结和注释,如下:
public class Fruit{ }
public class Apple extends Fruit { }
public class Basket{ //从泛型化的list中取出Fruit,里面的元素一定是Fruit的子类,所以都可以当作Fruit返回 public static Fruit getFruit(List list){ return list.get(0); } //将Apple放入泛型化的list(这个list可以接收的类型是Apple的父类,所以一定可以接收apple或apple的子类) public static void addApple(List list,Apple apple){ list.add(apple); }}
public class GenericTester extends AbstractTester{ public void test1(){ ListappleList = new ArrayList (); appleList.add(new Apple()); //先定义List ,填入元素 Fruit fruit=Basket.getFruit(appleList); //List 类型符合List 的要求 } public void test2(){ List fruitList=new ArrayList (); Basket.addApple(fruitList, new Apple()); //List 符合List 的要求 } }
public class GenericCompileTester { public void addInteger1(List list){ list.add(1); //编译错误,因为问号代表“编译时不确定,但运行时确定”的类型,Integer不一定符合要求,其实这里相当于 } public void addInteger2(List