泛型是JDK5引入的一种特性,是一种类型安全检测机制,开发者在编译阶段发现类型相关的报错。
泛型即参数类型化,将操作的数据类型定义为参数,可定义在类、接口、方法中。
可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。
我们都知道java中泛型又称为“伪泛型”,为什么称为伪泛型呢?是因为泛型只存在编译阶段,编译完成之后泛型会被擦除,并没有作用在程序的执行阶段,所以他存在的目的就是“为了规范”。
泛型的主要目标是提高 Java 程序的类型安全,保证程序的可读性和安全性。
泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。
public class Test {
public T test2(T params){}
}
public interface Test1{}
比如常见的?,T,K,V 就是通配符,比如其中的T换成A-Z其中任何一个都可以,java中是讲究约定的,就是大家共同约定,某个字符代表什么意思,这样也有利于代码维护。
通配符上界,可以限制传入的类型必须是上界这个类或者是这个类的子类
extends 上界>
extends Number>//可以传入的实参类型是Number或者Number的子类
public class Test {
public static void printList1(List extends Number> list) {
for (Object x:list) {
System.out.println(x);
}
}
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(1);
printList1(list); // ok
List list1 = new ArrayList<>();
list1.add(1.0D);
printList1(list1); // ok
List list2 = new ArrayList<>();
list2.add("1");
printList1(list2); // compile error
List extends Number> list3 = list;
// get能用上界
Number o = list3.get(0);
// 不能add
list3.add(5); // compile error
list3.add(new Object()); // compile error
}
}
小结:
Number o = list3.get(0);
list3.add(5);
,5虽然是Number的子类,依然不能add。上界通配符:用 super关键字声明,表示类型为T类型及T类型的父类
super 下界>
super Integer>//代表 可以传入的实参的类型是Integer或者Integer的父类类型
public static void printList1(List super Integer> list) {
for (Object x:list) {
System.out.println(x);
}
}
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(1);
printList1(list); // ok
List list1 = new ArrayList<>();
list1.add(1.0D);
printList1(list1); // compile error
List list2 = new ArrayList<>();
list2.add("1");
printList1(list2); // compile error
List super Integer> list3 = list;
// 不能用下界接收
Integer o = list3.get(0); // compile error
// 能add
list3.add(5); // ok
list3.add(new Number(5)); // compile error
}
Integer o = list3.get(0); // compile error
,比如例子中用Integer接收,万一list3中放的是Object类型,就凉凉了。list3.add(5)
, list3的通配符是 super Integer>
,说明该集合存放的是Integer或者Integer的子类,我只要向容器中放Integer和它的子类都是成立的。源码中使用例子:
类Collections 中binarySearch方法 【List extends Comparable super T>> list】入参list中存储对象A或者A的父类是Comparable子类都可以。
public static
int binarySearch(List extends Comparable super T>> list, T key) {
if (list instanceof RandomAccess || list.size()
可通过以下代码辅助理解
public class Test2 {
public static > void sort1(List list) {
Collections.sort(list);
}
public static > void sort2(List list) {
Collections.sort(list);
}
public static void t1() {
List animals = new ArrayList();
animals.add(new Animal(20));
animals.add(new Animal(30));
List dogs = new ArrayList();
dogs.add(new Dog(5));
dogs.add(new Dog(10));
sort1(animals);
// sort1(dogs); 会报错
sort2(animals);
sort2(dogs);
}
}
class Animal implements Comparable {
public int age;
public Animal(int age) {
this.age = age;
}
public int compareTo(Animal other) {
return this.age - other.age;
}
}
class Dog extends Animal {
public Dog(int age) {
super(age);
}
}
T 是一个确定的类型,通常用于泛型类和泛型方法的定义,?是一个不确定的类型,通常用于泛型方法的调用代码和形参,不能用于定义类和泛型方法。
泛型在编译阶段会进行泛型擦除,擦除为原始类型,但是object并不是基本数据类型的父类。