创作不易,各位看官点赞收藏.
泛型:通俗来讲就是一个标签,集合在设计时不能确定集合存放元素的类型。JDK5之后引入了泛型,在定义类、接口时,通过一个标识标识类中某个属性、方法的返回值和参数类型。把元素类型设计成一个参数,例如Collection、List、Map
等,E和V就是泛型集合。使用泛型以后集合中就只能存放泛型对应的类型元素。
泛型的好处:
public static void main(String[] args) {
// 将list声明为泛型,这个集合中只能存放对应泛型类型的元素,即只能存放String类型
ArrayList<String> list = new ArrayList<>();
list.add("你好");
list.add("Hello");
list.add("world");
// 遍历集合,list的迭代器自动添加了泛型
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
// 取出的元素也是之前设置的类型
String next = iterator.next();
System.out.println(next);
}
}
注意:
JDK5
之后,集合和集合类中都修改成了泛型结构,在实例化集合类时就可以指明具体的泛型类型。java.lang.Object
。// 自定义泛型类,T就是定义的泛型
public class Student<T> {
String name;
int gae;
// 类中使用自定义泛型
T info;
public Student() {}
public Student(String name, int gae, T info) {
this.name = name;
this.gae = gae;
this.info = info;
}
public T getInfo() {
return info;
}
public void setInfo(T info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", gae=" + gae +
", info=" + info +
'}';
}
}
public static void main(String[] args) {
// 实例化一个自定义泛型类,将Student内部的泛型指定为String类型
Student<String> student = new Student<>("张三",18,"我是张三");
System.out.println(student);
}
注意事项:
public class Student {}
Student<String> student1 = new Student<>();
Student<Integer> student2 = new Student<>();
student1 = student2; // 两个对象的泛型不一致,导致不能相互赋值
// 这是在编译期时报错,但是JVM加载的时候还是同一个Student对象
// T[] array = new T[10]; 因为T始终是一个变量
T[] array = (T[]) new Object[10];
自定义子类泛型:
class SubClass extends SuperClass<Integer> {} // 继承父类指明的泛型,抹除了泛型
class SubClass<T> extends SuperClass<T> {} // 继承父类中的泛型
class SubClass<T1> extends SuperClass<Integer,T1> {} // 继承父类中部分的泛型
class SubClass<T1,A> extends SuperClass<Integer,T1> {} // 继承父类中的部分泛型并且拥有自己的泛型
在方法中出现泛型结构但是和类的泛型参数没有任何关系的方法称为泛型方法。
public class Demo02<T> {
T t;
// 非泛型方法:即使使用了类的泛型参数也不是泛型方法
public void test1(){
System.out.println(t);
}
// 泛型方法:public 表示这是一个泛型方法,泛型参数为E,返回值、参数、方法中都可以使用这个泛型参数
public <E> List<E> test2(E[] e){
ArrayList<E> list = new ArrayList<>();
for (E e1 : e) {
list.add(e1);
}
return list;
}
}
注意事项:
不同泛型参数相互之间不能赋值,但是有时候泛型参数之间可能需要存在子父类关系,我们就使用通配符来表示。泛型中的通配符就是 ?
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
// 使用通配符
ArrayList<?> list3 = null;
list3 = list1; // 可以进行赋值,list3就可以作为list1、list2的通用父类
}
泛型通配操作:
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
// 使用通配符
ArrayList<?> list3 = null;
list3 = list1;
// 使用了泛型通配符后就不能向集合中添加数据了,但是可以添加null值
list3.add(123); // 报错
list3.add(null); // 不报错
// 但是还是可以读取数据,返回值是Object对象数据
for (Object o : list3) {
System.out.println(o);
}
}
有限制条件的通配符:可以限制通配符表示的范围,例如只能是某个类的子类等。
public static void main(String[] args) {
// ?表示的是SuperClass及其子类
List<? extends SuperClass> list1 = null;
// ?表示的是SubClass及其父类
List<? super SuperClass> list2;
List<SubClass> list3 = new ArrayList<>();
List<SuperClass> list4 = new ArrayList<>();
List<Object> list5 = new ArrayList<>();
list1 = list3;
list1 = list4;
// list1 = list5; // 报错
// list2 = list3; // 报错
list2 = list4;
list2 = list5;
// list1不能添加数据,可能表示的是一个能小的子类,然后参数为一个大一点的子类,就会报错
// list2可以添加SuperClass及其子类,因为list2表示的是SuperClass,最小子类就是SuperClass
list2.add(new SubClass());
}