【从零开始学Java | 第二十三篇】泛型(Generics)

前言

在上一篇讲 List 集合时,我们代码里一直写着 <String>、<Integer>,其实这就是泛型。

很多新手都会把泛型当成死记硬背的语法,包括我也一样,但是实际上,它是为了保护程序员不犯错而出现的一个机制。

一、为什么需要泛型

在JDK5之前,是没有泛型这个概念的,集合默认是可以放入任何类型的元素的。

我们写一个没有泛型的Demo:

当我们想调用String类型的length方法时,由于多态无法访问子类的特有功能,所以会报错,那么我如果进行类型的强制转换呢?会发生什么?

报错ClassCastException:

结论:

如果我们没有给集合指定数据类型,默认所有数据类型为Object,那么这个集合就可以存储任何类型的数据,因此带来了一个坏处,我们在获取了数据之后,无法使用该特定数据类型的方法。

在我们加上泛型后,如果我们想往集合中添加非泛型指定类型的数据时,编译都无法通过。

泛型的细节

  • 泛型中不能写基本数据类型,因为Java中的泛型为伪泛型,在编译好后,后台还是以Object的类型来存储的,而基本数据类型如int、double等无法强转为Object,因此只能写基本数据类型对应的包装类。
  • 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型。
java 复制代码
ArrayList<Animal> al = new Arraylist<>();

al.add(new Animal());
al.add(new Dog());
al.add(new Cat());
  • 如果不写泛型,类型默认是Object。

二、泛型的使用

泛型可以在很多地方进行定义。

  1. 定义在类后面,称之为泛型类。
  2. 定义在方法上面,称之为泛型方法。
  3. 定义在接口后面,称之为泛型接口。

1.泛型类

在定义一个类的时候,某个变量的数据类型不确定时,就可以使用带有泛型的类。

格式:

修饰符 class 类名<类型>{

}

例:

public class ArrayList<E>{

}

此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成T、E、K、V等

具体使用:

泛型类的书写:

java 复制代码
import java.util.Arrays;

public class MyArrayList <E>{
    Object[] obj = new Object[10];
    int size;

    public boolean add(E e){
        obj[size] = e;
        size++;
        return true;
    }

    public E get(int index){return (E)obj[index];}

    @Override
    public String toString() {
        return Arrays.toString(obj);
    }
}

泛型类的使用:

java 复制代码
public class GenericsTest02 {
    public static void main(String[] args) {
        MyArrayList<String> mal = new MyArrayList<>();
        mal.add("张三");
        mal.add("李四");
        mal.add("王五");

        System.out.println(mal);
    }
}

运行结果:

2.泛型方法

方法中形参类型不确定时,

  1. 可以使用类名后面定义的泛型,所有类中的方法都可以使用这个泛型。
  2. 也可以在方法声明上定义自己的泛型,仅在声明的这个方法中可以使用。

格式:

修饰符<类型> 返回值类型 方法名(类型 变量名){

}

举例:

public<T> boolean get(T t){

}

定义一个泛型方法:

java 复制代码
public final class ListUtils {
    private ListUtils(){}
    
    public static<E> void addAll(ArrayList<E> al, E e1, E e2, E e3){
        al.add(e1);
        al.add(e2);
        al.add(e3);
    }
}

拓展:上面的addAll方法只能添加确定个数的元素,但是我不确定要添加的元素,应该如何实现?

java 复制代码
public final class ListUtils {
    private ListUtils(){}

    public static <E> void addAll(ArrayList<E> al, E...e){
        for (E e1 : e) {
            al.add(e1);
        }
    }
}

3.泛型接口

格式:

修饰符 interface 接口名<类型>{

}

举例:

public interface List<E>{

}

如何使用一个带泛型的接口?

方式一:实现类给出具体类型。

方式二:实现类延续泛型,在创建对象时再确定具体类型。

①实现类给出具体类型

②实现类延续泛型,在创建对象时再确定具体类型

总结

  1. **为什么用泛型?**把运行时的报错(ClassCastException)提前到编译期拦截,避免手写强制类型转换。
  2. **如何用?**掌握 <T> 在类、接口和方法上的定义语法。
  3. **底层原理?**泛型擦除,运行时全都是 Object。

🐂🐎

相关推荐
掉进电商坑三年没爬出来的东叔14 小时前
青龙面板进阶:一个面板聚合多平台签到,所有积分自动领
java·开发语言
iCxhust14 小时前
51单片机电力载波应用开发(七)广播通讯
c语言·开发语言·单片机·嵌入式硬件·51单片机
殷色玫瑰14 小时前
C++ STL:stack、queue、priority_queue 与容器适配器详解
java·开发语言·数据结构·c++·算法·visualstudio
IT方大同15 小时前
java输入输出+方法
java·开发语言·python
滕州市燕猫虎计算机科技工作室个体工商户15 小时前
《Rust程序设计》学习笔记一
开发语言·rust·学习笔记·rust程序设计
Yyyyyy~15 小时前
【Java】String
java
Wang's Blog15 小时前
Java框架 SpringCloud 快速入门: 服务拆分之服务远程调用
java·开发语言·spring cloud
努力努力再努力wz15 小时前
【CUDA入门系列】CUDA编程实战:设备选择、显存管理、Kernel、Stream 与 Event 全流程梳理
开发语言·c++
Wang's Blog15 小时前
Java框架 SpringCloud 快速入门: 路由断言工厂
java·spring·spring cloud
ym hyd 11115 小时前
门诊挂号系统源码 Java+SpringBoot+Vue3 前后分离
java·vue.js·spring boot·毕设