- 泛型:标签
- 举例:
- 药店中,每个药瓶都有不同的名字
- 超市购物架上很多瓶子,每个瓶子装的是什么,有标签
- 泛型的设计背景 集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的 对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时
把元素的类型设计成一个参数,这个类型参数叫做泛型。Collection,List,ArrayList 这个就是类型参数,即泛型
所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时确定。- 从JDK1.5以后,Java引入了“参数化类型(Parameterized type)”的概念, 允许我们在创建集合时再指定集合元素的类型,正如:List,这表明 该List只能保存字符串类型的对象。
- JDK1.5改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持, 从而可以在声明集合变量、创建集合对象时传入类型实参。
集合中使用泛型:
ArrayList<String> arrayList = new ArrayList<>();
类中使用泛型
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
接口上使用泛型:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
参数类型、返回值类型使用泛型
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}


泛型的声明
interface List和class Demo - 其中E、K、V不代表值,而是表示某种引用数据类型,任意的单个字母的大写都可以。
泛型的实例化
- 在类名后面指定类型参数的类型,如:
Listlist = new ArrayList<>() ; Mapmap = new HashMap<>() ; - E只能是引用数据类型的类名,不能使用基本数据类型填充。
- 其实泛型的作用就是约束,约束集合内存储的元素的数据类型。
格式:
public class 类名<泛型> {
//在此类中多了一种 泛型类型 供此类使用
//只有在具体创建此类对象时才确定泛型的具体数据类型
}
举例:ArrayList集合类、HashMap
public class Student<T> {
private String name ;
private T age ;
public Student(String name, T age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getAge() {
return age;
}
public void setAge(T age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Demo2 {
public static void main(String[] args) {
// 创建泛型类Student的实例化对象,并将其泛型类型设置为Integer
// 即age属性接收的类型为Integer
Student<Integer> stu1 = new Student<>();
// 设置属性
stu1.setName("张三");
stu1.setAge(21);
System.out.println("stu1 = " + stu1);
// 创建泛型类Student的实例化对象,并将其泛型类型设置为String类型
// 即age属性接收的类型为String
Student<String> stu2 = new Student<>();
// 设置属性
stu2.setName("张三");
stu2.setAge("23");
System.out.println("stu2 = " + stu2);
}
}
public interface 接口名<泛型> {
//在此接口中多了一种 泛型类型 供此其使用
//只有在具体创建此接口的具体实现类对象时才确定泛型的具体数据类型
}
举例:List接口、Collection接口
权限修饰符 状态修饰符 <泛型> 返回值类型 方法名(形参列表) {
// 在方法体中可以使用 泛型类型
}
示例:
public class Demo3 {
public static void main(String[] args) {
method(new Integer(5));
method("abcd");
}
public static <T> void method(T t) {
System.out.println("t = " + t);
System.out.println("泛型T的具体类型为" + t.getClass());
}
}
t = 5
泛型T的具体类型为class java.lang.Integer
t = abcd
泛型T的具体类型为class java.lang.String
class Cat<T , K , V> {
}
public Cat() {}
E[] elements = (E[])new Object[10];泛型的继承问题:
- 父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
- 子类不保留父类的泛型:按需实现
- 没有类型
- 具体类型
- 子类保留父类的泛型:泛型子类
- 全部保留
- 部分保留
class Father<T , E> {
}
// 子类不保留父泛型
// 1、没有类型,此时等价于class Son1 extends Father
class Son1 extends Father {
}
// 2、将泛型类型替换为具体类型
class Son2 extends Father<String , String> {
}
// 之类保留父类泛型
// 1、全部保留
class Son3<T , E> extends Father<T , E> {
}
// 部分保留
class Son4<E> extends Father<String , E> {
}
?
public class Demo6 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Object> list2 = new ArrayList<>();
System.out.println(list1 instanceof ArrayList<?>); // true
System.out.println(list2 instanceof ArrayList<?>); // true
}
}
读取List>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object。
不能向集合中写入元素。因为我们不知道ArrayList>的元素类型,我们不能向其中添加对象。
注意点
泛型的通配符不能使用在方法的声明上
public static > void test() {} 编译报错
不能使用在泛型类的声明上
public class Demo> {} 编译报错
不能用于创建对象
ArrayList> list = new ArrayList>() ; 编译报错
- 使用通配符指定泛型的上下限
- 通配符指定上限
- 上限extends:使用时指定的类型必须是继承某个类,或者实现某个接口,即<=
- 通配符指定下限
- 下限super:使用时指定的类型不能小于操作的类,即>=
- 举例:
extends Number>(无穷小 , Number],只允许泛型为Number及Number子类的引用调用super Number>[Number , 无穷大),只允许泛型为Number及Number父类的引用调用extends Comparable>,只允许泛型为实现Comparable接口的实现类的引用调用