前言

在 Java 早期开发中,集合可以存放任意类型对象,取出数据时需要强制类型转换,不仅代码繁琐,还极易引发类型转换异常泛型就是为了解决这类问题而生,它可以在编译阶段约束数据类型,实现代码通用、类型安全,同时避免强制转型,是集合、接口、方法中非常重要的语法特性。

一、泛型的概念与作用

1. 什么是泛型

泛型(Generics)即参数化类型,将数据类型作为参数传递,在定义类、接口、方法时不指定具体类型,而是在使用时再确定。

2. 核心作用

  1. 类型安全:编译期检查数据类型,非法类型直接报错,规避运行时 ClassCastException
  2. 省去强制类型转换:存取数据无需手动转型,代码更简洁
  3. 代码复用:一套代码可以适配多种数据类型

二、不使用泛型的弊端

先看传统写法的问题,集合默认存放 Object 类型:

java

运行

import java.util.ArrayList;

public class NoGenericDemo {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        // 存入字符串、数字,类型混乱
        list.add("Java");
        list.add(100);

        // 取出时必须强制类型转换
        String str = (String) list.get(0);
        // 运行报错:类型转换异常
        String error = (String) list.get(1);
    }
}

问题总结:类型不受约束、需要强转、存在运行时异常风险。

三、泛型在集合中的使用

集合是泛型最常用的场景,语法格式:容器<数据类型>

1. 基本使用

java

运行

import java.util.ArrayList;

public class GenericListDemo {
    public static void main(String[] args) {
        // 限定集合只能存储 String 类型
        ArrayList<String> list = new ArrayList<>();
        list.add("Java");
        list.add("MySQL");
        // list.add(123); 编译报错,类型不匹配

        // 直接取值,无需强制转换
        String s = list.get(0);
        System.out.println(s);
    }
}

2. 泛型简写(钻石运算符)

Java 7 及以上支持钻石运算符 <>, 右侧可以省略泛型类型:

java

运行

// 标准写法
ArrayList<String> list1 = new ArrayList<String>();
// 简写写法(推荐)
ArrayList<String> list2 = new ArrayList<>();

四、自定义泛型类

我们可以自己定义包含泛型的类,格式:类名<泛型标识> 常用泛型标识约定:

  • T:Type 代表任意类型
  • E:Element 元素(集合专用)
  • K:Key 键、V:Value 值(Map 专用)

java

运行

// 自定义泛型类
class MyGeneric<T> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

public class CustomGenericClass {
    public static void main(String[] args) {
        // 使用时指定为 String 类型
        MyGeneric<String> strObj = new MyGeneric<>();
        strObj.setData("泛型测试");
        System.out.println(strObj.getData());

        // 使用时指定为 Integer 类型
        MyGeneric<Integer> intObj = new MyGeneric<>();
        intObj.setData(666);
        System.out.println(intObj.getData());
    }
}

五、泛型方法

在普通方法、静态方法上定义泛型,格式:<泛型标识> 返回值 方法名()

java

运行

public class GenericMethod {
    // 定义泛型方法
    public static <T> void show(T t) {
        System.out.println(t);
    }

    public static void main(String[] args) {
        show("字符串类型");
        show(999);
        show(3.14);
    }
}

六、泛型通配符

当不确定泛型具体类型时,可以使用通配符 ?,代表任意未知类型。

1. 无界通配符?

java

运行

import java.util.ArrayList;
import java.util.List;

public class WildcardDemo {
    // 参数可以接收任意泛型类型的 List
    public static void printList(List<?> list) {
        for (Object obj : list) {
            System.out.println(obj);
        }
    }

    public static void main(String[] args) {
        List<String> strList = new ArrayList<>();
        strList.add("A");
        List<Integer> intList = new ArrayList<>();
        intList.add(1);

        printList(strList);
        printList(intList);
    }
}

2. 受限通配符

  • <? extends 类>上限通配符,只能接收该类及其子类
  • <? super 类>下限通配符,只能接收该类及其父类

七、总结

  1. 泛型核心作用:编译期类型检查,避免类型转换异常,简化代码
  2. 集合优先指定泛型类型,是开发规范。
  3. 可以自定义泛型类、泛型方法,提升代码通用性。
  4. 通配符 ? 用于接收未知泛型类型,分为上限、下限通配符。
  5. 泛型只在编译阶段生效,运行时会被擦除(泛型擦除)。

 

更多推荐