背景
JAVA推出泛型以前,程序员可以构建一个元素类型为Object的集合,该集合能够存储任意的数据类型对象,而在使用该集合的过程中,需要程序员明确知道存储每个元素的数据类型,否则很容易引发ClassCastException异常。
什么是泛型
泛型的本质就是参数化类型,也就是所操作的数据类型被指定为一个参数。
泛型类的定义语法
/**
* class类名称<泛型标识,泛型标识, … > {
* private 泛型标识变量名;
* .....
* }
*/
public class ProductGetter<T> {
private T product;
ArrayList<T> list = new ArrayList<>();
public void addProduct(T t){
list.add(t);
}
public T getProduct(){
return list.get(new Random().nextInt(list.size()));
}
}
使用语法
- 常用的泛型标识:T、E、K、V
- 类名<具体的数据类型>对象名= new类名<具体的数据类型>();
- Java1.7以后,后面的<>中的具体的数据类型可以省略不写类名<具体的数据类型>对象名= new类名<>();
- 引用数据类型。因为基本类型没有继承object 基本数据类型是在栈中创建的,存储的是值本身。引用数据类型本体在堆中,栈中存的是堆中的指针
- 同一泛型类型,根据不同的数据类型创建的对象,本质上是同一类型
泛型类注意事项
- 泛型类,如果没有指定具体的数据类型,此时,操作类型是0bject
- 泛型的类型参数只能是类类型,不能是基本数据类型
- 泛型类型在逻辑上可以看成是多个不同的类型,但实际上都是相同类型
- 子类也是泛型类,子类和父类的泛型类型要一致
class ChildGeneric<T> extends Generic<T>
- 子类不是泛型类,父类要明确泛型的数据类型
class ChildGeneric extends Generic<String>
- 泛型类派生子类,子类也是泛型类,那么子类的泛型标识要和父类一致。
泛型接口的定义语法
interface 接口名称〈泛型标识,泛型标识,…> {泛型标识方法名();
.....
}
泛型接口的使用
- 实现类不是泛型类,接口要明确数据类型 实现类也是泛型类,
- 实现类和接口的泛型类型要一致
- 实现泛型接口的类,不是泛型类,需要明确实现泛型接口的数据类型。
泛型方法
修饰符<T,E,...> 返回值类型 方法名(形参列表){方法体}
- public 与返回值中间的
<T>
非常重要,可以理解为声明此方法为泛型方法只有声明了<T>
的方法才是泛型方法, - 泛型类中使用了泛型成员的方法并不是泛型方法
<T>
表示该方法将使用泛型类型T,此时才可以在方法中试用贴泛型类型T - 与泛型类的定义一样,此处的T可以为任意标识,常见的T、E、K、V等形式参数都常用于表示泛型
//定义泛型方法
//list 参数
//<E> 泛型标识,具体类型,由调用方法的时候来指定
public <E> E getProduct(ArrayList<E> list){
return list.get(random.nextInt(list.size()))
}
//泛型 方法的使用
public class Test{
public static void main(String[] args){
ProductGetter<Integer> productGetter = new ProductGetter<>();
ArrayList<String> strList = new ArrayList<>();
strList.add("笔记本电脑");
strList.add("苹果手机");
strList.add("扫地机器人");
//泛型方法的调用,类型是通过调用方法的时候指定的;这里定义的泛型方法的类型是独立与类类型存在的,如果是成员方法则和泛型类的类型一致
System.out.println(productGetter.getProduct(strList));
ArrayList<Integer> intList = new ArrayList<>();
inList.add(1000);
inList.add(5000);
inList.add(3000);
Integer product2 = productGetter.getProduct(intList);
System.out.println(product2+"\t"+product2.getClass().getSimpleName)
}
}
//定义多个泛型的方法
public static <T,E,K> void printType(T t,E e ,K k){
System.out.println(t + "\t" + t.getClass().getSimpleName());
System.out.println(t + "\e" + e.getClass().getSimpleName());
System.out.println(t + "\k" + k.getClass().getSimpleName());
}
//调用多个泛型类型的静态方法
ProductGetter.prinType(100, "java", true)
泛型方法与可变参数
//泛型0可变参数的定义
public <E> void print(E... e){
for(E el : e){
System.out.println(e);
}
}
//可变参数泛型方法的调用
ProductGetter.print(1, 2, 3, 4, 5);
泛型方法的总结
- 泛型方法能使方法独立于类而产生变化
- 如果static方法要使用泛型能力,就必使其成为泛型方法
public static void main(String[] args){
Box<Number> box1 = new Box<>();
box1.setFirst(100);
showBox(box1);
Box<Integer> box2 = new Box<>();
box2.setFiorst(200);
showBox(box2);
}
public static void showBox(Box<? extends NUmber> box){
Number first = box.getFirst();
System.out.println(first);
}
类型通配符的上限
类/接口<? extends 实参类型>
- 要求该泛型的类型名,只能事实参类型,或实参类型的子类型
- 类型通配符的下限
- 类/接口<? super 实参类型>
- 要求该泛型的类型名,只能事实参类型,或实参类型的父类型
//上下限演示代码
/**
* @author : zpb
* @date : 2022/7/3016:24
* @description : some description
*/
@Slf4j
@SpringBootTest
public class AnimalTest {
@Test
public void Main(){
ArrayList<Animal> animals = new ArrayList<>();
ArrayList<Cat> cats = new ArrayList<>();
ArrayList<MiniCat> miniCats = new ArrayList<>();
// showAnimal(animals);
showAnimal(cats);
showAnimal(miniCats);
showAnimals(animals);
showAnimals(cats);
// showAnimals(miniCats);
TreeSet<Cat> animals1 = new TreeSet<>(new Comparator1());
animals1.add(new Cat("jerry", 20));
animals1.add(new Cat("amy", 25));
animals1.add(new Cat("frank", 35));
animals1.add(new Cat("jim", 15));
for (Cat cat:
animals1) {
System.out.println(cat);
}
}
/**
* 泛型上限通配符,传递的集合类型,只能是Car或Car子类类型
* @param list
*/
public static void showAnimal(ArrayList<? extends Cat> list){
//不允许在这里对list进行追加,因为list类型无法确定
for (Cat c:
list) {
System.out.println(c);
}
}
/**
* 类型通配符下限,要求集合只能是Cat或Cat的父类类型
*/
public static void showAnimals(List<? super Cat> list){
//这里允许对list进行追加,但不能保证对元素的约束要求
for (Object c:
list) {
System.out.println(c);
}
}
}
class Comparator1 implements Comparator<Animal> {
@Override
public int compare(Animal o1, Animal o2) {
return o1.getName().compareTo(o2.getName());
}
}
class Comparator2 implements Comparator<Cat> {
@Override
public int compare(Cat o1, Cat o2) {
return o1.getAge()-o2.getAge();
}
}
class Comparator3 implements Comparator<MiniCat> {
@Override
public int compare(MiniCat o1, MiniCat o2) {
return o1.getLevel()-o2.getLevel();
}
}