一、泛型引入
1、为什么需要泛型
传统方式存在的问题
-  不能对加入到集合中的数据类型进行约束 
-  遍历时,需要进行类型转换 
泛型的理解与好处
-  编译时能检查添加元素的类型 
-  能减少类型转换的次数 
2、泛型初体验
(1)说明
- 这里以 Dog 类为例
ArrayList<Dog> list = new ArrayList<Dog>();
-  不使用泛型:放入集合时,Dog 类型会先转换为 Object 类型,取出时,需要转换为 Dog 类型 
-  使用泛型:放入集合和取出时,不需要进行类型转换 
(2)演示
package com.my.test;import java.util.ArrayList;
import java.util.Iterator;public class GenericTest {public static void main(String[] args) {ArrayList<Dog> list = new ArrayList<>();list.add(new Dog("小黄", 2));list.add(new Dog("小汪", 3));list.add(new Dog("小多", 4));System.out.println("========== 增强 for 循环遍历 ==========");for (Dog dog : list) {System.out.println(dog);}System.out.println("========== 迭代器循环遍历 ==========");Iterator<Dog> iterator = list.iterator();while (iterator.hasNext()) {Dog dog = iterator.next();System.out.println(dog);}}
}class Dog {String name;int age;public Dog(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +", age=" + age +'}';}
}
- 输出结果
========== 增强 for 循环遍历 ==========
Dog{name='小黄', age=2}
Dog{name='小汪', age=3}
Dog{name='小多', age=4}
========== 迭代器循环遍历 ==========
Dog{name='小黄', age=2}
Dog{name='小汪', age=3}
Dog{name='小多', age=4}
3、泛型概述
-  在类声明或实例化时制定好需要的具体类型 
-  可以保证在编译时没有警告,运行时就不会产生 ClassCastException(类型转换异常) 
-  通过标识表示类中某个属性的类型,某个方法的参数类型或返回值类型 
4、泛型语法
- 自定义泛型类
class 【类名】 <T> {}
- 自定义泛型接口
class 【接口名】 <T> {}
- 自定泛型方法
【修饰符】 <T> 【返回数据类型】 【方法名】(【参数列表】) {}
5、注意事项
-  T 表示类型(Type 的缩写,也可以为 K、V 等),且必须是引用类型 
-  指定泛型具体类型后,可以传入该类型或者其子类类型 
-  泛型的简写 
// 完整写法
ArrayList<Dog> list = new ArrayList<Dog>();
// 简写
ArrayList<Dog> list = new ArrayList<>();
- 这样写 ArrayList<> list = new ArrayList<>();,默认指定泛型具体类型为 Object 类型
二、自定义泛型类
1、基本介绍
class 【类名】 <T> {}
2、注意事项
- 普通成员可以使用泛型
T t;
- 使用泛型的数组不能初始化,因为不能确定 T 的类型,无法开辟空间,在指定泛型的具体类型后才能初始化
// 错误写法
T arr[] = new T[];
-  静态成员不能使用泛型,因为静态成员与类相关,类加载时,静态成员无法确定泛型的具体类型,无法完成初始化 
-  泛型的具体类型在创建对象时确定 
-  创建对象时,没有指定泛型的具体类型,默认为 Object 类型 
3、演示
- CustomGenericsClassTest.java
package com.my.test;public class CustomGenericsClassTest {public static void main(String[] args) {Person<String> person1 = new Person<>("jack");Person<Integer> person2 = new Person<>(10);person1.show();person2.show();}
}class Person<T> {T t;public Person(T t) {this.t = t;}public void show() {System.out.println(this.t);}
}
- 输出结果
jack
10
三、自定义泛型接口
1、基本介绍
class 【接口名】 <T> {}
2、注意事项
-  接口中静态成员不能使用泛型 
-  接口的泛型的具体类型,在继承接口或实现接口时确定 
-  没有指定泛型的具体类型,默认为 Object 类型 
3、演示
- CustomGenericInterfaceTest.java
package com.my.test;public class CustomGenericInterfaceTest {public static void main(String[] args) {new Student().show("jack");}
}class Student implements Person<String> {@Overridepublic void show(String s) {System.out.println(s);}
}interface Person<T> {public void show(T t);
}
- 输出结果
jack
四、自定义泛型方法
1、基本介绍
【修饰符】 <T> 【返回数据类型】 【方法名】(【参数列表】) {}
2、注意事项
-  泛型方法可以定义在普通类和泛型类中 
-  当泛型方法被调用时,泛型的具体类型被确定 
-  public void method(T t) {} 不是泛型方法,而是使用了泛型 
3、演示
- CustomGenericMethodTest.java
package com.my.test;public class CustomGenericMethodTest {public static void main(String[] args) {Cat<String> cat = new Cat<>();cat.show(10, "tom");}
}class Cat<K> {public<T> void show(T t, K k) {System.out.println(t.getClass());System.out.println(k.getClass());}
}
- 输出结果
class java.lang.Integer
class java.lang.String
五、泛型的继承与通配符
1、基本介绍
- 泛型不具备继承性
// 错误写法
List<Object> list1 = new ArrayList<String>();
-  <?>:支持任意类型 
-  <? extends A>:支持 A 类以及 A 类的子类,规定了泛型的上限 
-  <? super A>:支持 A 类以及 A 类的父类,规定了泛型的下限 
2、演示
- GenericExtends.java
package com.my.test;import java.util.ArrayList;
import java.util.List;public class GenericExtends {public static void main(String[] args) {List<Object> list1 = new ArrayList<>();List<String> list2 = new ArrayList<>();List<AA> list3 = new ArrayList<>();List<BB> list4 = new ArrayList<>();List<CC> list5 = new ArrayList<>();printList1(list1);printList1(list2);printList1(list3);printList1(list4);printList1(list5);//        printList2(list1); // ×
//        printList2(list2); // ×printList2(list3);printList2(list4);printList2(list5);printList3(list1);
//        printList3(list2); // ×printList3(list3);
//        printList3(list4); // ×
//        printList3(list5); // ×}public static void printList1(List<?> list) {for (Object o : list) {System.out.println(o);}}public static void printList2(List<? extends AA> list) {for (Object o : list) {System.out.println(o);}}public static void printList3(List<? super AA> list) {for (Object o : list) {System.out.println(o);}}
}class AA {}class BB extends AA {}class CC extends BB {}