允许在定义类、接口时通过一个标识表示类中某个属性的类型、方法返回值、参数类型。这个标识将在使用时确定。 参数T必须为类,且可为多个。

  1. ArrayList<Integer> list = new ArrayList<>();//类型推断,该集合仅可存储Integer类型数据
  2. list.add(78);
  3. Iterator<Integer> iterator = list.iterator();
  4. while(iterator.hasNext()){
  5. System.out.println(iterator.next());
  6. }

8.1 自定义泛型结构—类

  1. // 自定义泛型类,指明参数T
  2. public class order<T>{
  3. String orderName;
  4. T orderT;
  5. public Order(){}
  6. public Order(String orderName,T orderT){
  7. this.orderName = orderName;
  8. this.orderT = orderT;
  9. }
  10. public T orderT(){
  11. return orderT;
  12. }
  13. }
  14. // 实例化未指明参数类型时,默认为Object类型
  15. Order order = new Order();
  16. order.setOrderT(123);
  17. order.setOrderT("123");
  18. // 实例化指明参数类型(建议),则参数类型特定
  19. Order<String> order1 = new Order<String>();
  20. //order1.setorderT(123); 报错,仅可为String
  21. // 定义泛型类,
  22. class Person<T extends Info>{}
  1. 泛型不同的引用不能相互赋值,泛型要使用就一路都用,要不用就一路都不用。

    1. 例如:
    2. A是类B的父类,G<A>与G<B>不具备子父类关系,二者为并列关系,共同的父类是G<?>
    3. A是类B的父类,A<G>是B<G>的父类
  2. 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,在静态方法中不能使用类的泛型。

  3. 异常类不能是泛型。
  4. 泛型数组的声明:

    1. T[] arr = new T[10]; // 编译不通过
    2. T[] arr = (T[])new Object[10]; // 编译通过
  5. 子类与父类中的泛型 ```java class Father {}

// 子类不保留父类的泛型 // 1)没有类型 擦除 class Son1 extends Father {// 等价于class Son extends Father } // 2)具体类型 class Son2 extends Father {}

// 子类保留父类的泛型 // 1)全部保留 class Son3 extends Father {} // 2)部分保留 class Son4 extends Father {} // 3)保留同时又增加了泛型 class Son5 extends Father{}

  1. <a name="uRyFm"></a>
  2. ## 8.2 自定义泛型结构--方法
  3. 泛型方法在调用时才指明参数的类型,可以是static的,因为泛型确定与是否为类、对象是没有关系的。<br />`[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称])`
  4. ```java
  5. public <E> List<E> copyFromArrayToList(E[] arr){
  6. ArrayList<E> list = new ArrayList<>();
  7. for(E e:arr)
  8. list.add(e);
  9. return list;
  10. }

8.3 通配符

类型通配符?用于所有泛型的引用。如:List<?>List<String>、List<Object>等各种泛型List的父类。

读取List<?>中的元素永远都是安全的,因为不论其真实类型是什么其包含的都是Object,所以读出的数据也是Object类型。写入元素是不行的,因为不知道其元素类型,因此不能向其添加对象,唯一的例外是null,它是所有类型的成员。

  1. Collection<?> c = new ArrayList<String>();
  2. c.add(new Object()); // 编译时错误
  3. c.add(null); // 编译通过
  4. List<String> l1 = new ArrayList<String>();
  5. read(l1);
  6. // 通用的List遍历方法
  7. public static void read(List<?> list) {
  8. for (Object o : list) // 元素一定为Object类型
  9. System.out.println(o);
  10. }

8.4 有限制条件的通配符

  1. <? extends Number> (无穷小 , Number] // 只允许泛型为Number及Number子类的引用调用
  2. <? super Number> [Number , 无穷大) // 只允许泛型为Number及Number父类的引用调用声明下限
  3. <? extends Comparable> // 只允许泛型为实现Comparable接口的实现类的引用调用
  1. List<? extends Person> list1 = null; // 可以引用下面的list3和list4
  2. List<? super Person> list2 = null; // 可以引用下面的list4和list5
  3. List<student> list3 = new ArrayList<student>():
  4. List<Person> list4 = new ArrayList<Person>();
  5. List<object> list5 = new ArrayList<object>();
  6. //读取数据:
  7. list1 = list4;
  8. Person p= list1.get(0); // 获取的对象类型最小为Person,这是为了满足定义中的引用条件
  9. list2 = list4;
  10. Object obj = list2.get(0); // 获取的对象类型最小为Object,这是为了满足定义中的引用条件
  11. //写入数据
  12. //list1.add(new Person()); // 子类可能无穷小,因此extends界限不能添加类型
  13. list2.add(new Student()); // Person为下界,最大为Person,子类即父类,因此Person及其子类均可