一.泛型
泛型相比于Object类型的优点:
a.泛型提供了编译时类型安全监测机制,允许在编译时监测到非法的类型数据结构
b.消除了强制类型转化
泛型的本质是参数化类型,处理的数据类型不是固定的,可以作为参数传入。
Java泛型是通过擦除实现的,类定义中的类型参数会被替换为Object,程序运行过程中虚拟机不知道泛型的实际类型参数。
1.泛型类
public class GenericClass<E>{
private E name;
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}
GenericClass<String> gen = new GenericClass<>();
gen.setName("abc");
System.out.println(gen.getName());
GenericClass<Integer> gen1 = new GenericClass<>();
gen1.setName(1);
System.out.println(gen1.getName());
System.out.println(gen.getClass() == gen1.getClass());//返回true
//如果实现没有使用泛型,也需要类型转化
GenericClass genericClass = new GenericClass();
genericClass.setName("111");
System.out.println((String) genericClass.getName());
从泛型类派生子类
a.子类也是泛型类,子类和父类的泛型类型要一致(如果父类不设置类型,默认类型是Object)
b.子类不是泛型类,父类要明确泛型的数据类型
2.泛型方法
泛型方法的类型变量放在修饰符后面,返回值的前面
public static T min(T[] a)
public static T min(T []a)
一个类型变量或通配符可以有多个限定 T extends Comparable & Serializable
public class GenericMethod {
public <M> void Method01(M m){
System.out.println(m);
}
public static <S> void Method02(S s){
System.out.println(s);
}
}
GenericMethod gm = new GenericMethod();
gm.Method01(1);
gm.Method01("aaa");
gm.Method01(true);
GenericMethod.Method02(8.8);
GenericMethod.Method02("static method");
3.类型通配符?
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(2);
printArray(list01);
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("b");
printArray(list02);
}
public static void printArray(ArrayList<?> list){
Iterator<?> iterator = list.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
}
}
注意:数组和泛型有所不同,假设Foo是Bar的一个子类型(子类或者子接口),那么Foo[]依然是Bar[]的子类型;但G不是G的子类型。Foo[]自动向上转型为Bar[]的方式被称为型变。也就是说,Java的数组支持型变,但Java集合并不支持型变
3.1设定类型通配符的上限 <? extends 类型>
指定通配符上限就是为了支持类型型变。比如Foo是Bar的子类,这样A就相当于A<? extends Bar>的子类,可以将A赋值给A<? extends Bar>类型的变量,这种型变方式被称为协变。
public static void getElement01(Collection<? extends Number> collections){
}
Collection<Integer> list01 = new ArrayList<>();
Collection<Number> list02 = new ArrayList<>();
Collection<Object> list03 = new ArrayList<>();
getElement01(list01);
getElement01(list02);
getElement01(list03);//报错
对于协变的泛型而言,它只能调用泛型类型作为返回值类型的方法;而不能调用泛型类型作为参数的方法。口诀是:协变只出不进!
3.2设定类型通配符的下限 <? super 类型>
Foo是Bar的子类,当程序需要一个A<? super Foo>变量时,程序可以将A、A赋值给A<? super Foo>类型的变量,这种型变方式被称为逆变。
public static void getElement02(Collection<? super Number> collections){
}
Collection<Integer> list01 = new ArrayList<>();
Collection<String> list02 = new ArrayList<>();
Collection<Number> list03 = new ArrayList<>();
Collection<Object> list04 = new ArrayList<>()
Collection<Integer> list01 = new ArrayList<>();
Collection<Number> list02 = new ArrayList<>();
Collection<Object> list03 = new ArrayList<>();
getElement02(list01);//报错
getElement02(list02);
getElement02(list03);
对于逆变的泛型而言,它只能调用泛型类型作为参数的方法;而不能调用泛型类型作为返回值类型的方法。口诀是:逆变只进不出!
带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。