当前位置: 首页 > article >正文

【Java 基础】16 泛型

文章目录

    • 什么是泛型?
    • 泛型的声明
    • 泛型的使用
    • 泛型方法
    • 通配符和泛型上下界
      • 1)通配符
      • 2)泛型上下界
    • 泛型的好处
    • 注意事项

泛型提供了一种在编写代码时更好地 支持类型安全的机制。通过泛型,我们可以编写更加 通用灵活可读性高的代码,同时 减少类型转换和运行时错误

什么是泛型?

泛型(Generics)是一种参数化类型的概念

它使得我们可以编写能够适用于多种类型的代码,而不是为每种类型都写一份代码。泛型提供了编译时的类型检查,使得代码更加安全,并且减少了在运行时进行频繁的类型转换

例如:

我们之前有为很多箱子都贴上了固定的标签!

装 苹果,老鼠,小狗,因为不能放一起呀!虽然,狗现在已经不多管闲事去拿耗子啦_

有多少种类就需要多少箱子,新增加一个就需要再增加,就很麻烦

于是我们想到了,箱子不贴固定的名称,来一种就装一种,这样就不需要为每一种单独定义一个标签啦
在这里插入图片描述

之前的 苹果,老鼠,小狗等等箱子,就是具体的类型。而后来的 东西,就是一个泛型。

泛型的声明

在 Java 中,泛型主要通过在接口方法中使用泛型类型参数来实现。

下面就使用泛型去定义一个箱子

// 定义一个泛型类(比如这就是一个装东西的箱子)
class Box<T> {
    private T value;
    public void setValue(T value) {
        this.value = value;
    }
    public T getValue() {
        return value;
    }
}

上述代码中,Box 类使用了泛型类型参数 T,使得这个类可以存储和返回任意类型的数据。

泛型的使用

使用上面已经定义好的箱子去装各种各样的东西

先往里装一种类型的东西,如老鼠

    public static void main(String[] args) {
        // 可以往箱子里装 int 型数字(比如这就是老鼠)
        Box<Integer> integerBox = new Box<>();
        integerBox.setValue(42);
        int intValue = integerBox.getValue();
        System.out.println(intValue);
    }

输出结果:42

再往里装另一种类型的东西,如小狗

    public static void main(String[] args) {
        // 还可以往箱子里装 String 型的字符(比如这就是小狗)
        Box<String> stringBox = new Box<>();
        stringBox.setValue("哈士奇");
        String stringValue = stringBox.getValue();
        System.out.println(stringValue);
    }

输出结果:哈士奇

泛型方法

除了泛型类,Java 还支持泛型方法。泛型方法可以在普通类中定义,也可以在泛型类中定义。

以下是一个简单的泛型方法的例子:

// 定义一个泛型方法
public static <E> void printBoxSaveWhat(E e) {
	System.out.println("箱子里装的是: " + e);
}
// 使用泛型方法
public static void main(String[] args) {
    // 打印第一种类型
    printBoxSaveWhat(42);
    // 打印外一种类型
    printBoxSaveWhat("哈士奇");
}

输出结果:

箱子里装的是: 42
箱子里装的是: 哈士奇

上述代码中,printBoxSaveWhat 方法是一个泛型方法,可以接受任意类型的参数。在使用时,编译器会根据传入的实际参数类型进行类型推断

通配符和泛型上下界

Java 泛型还引入了通配符泛型上下界的特性。

1)通配符

用于表示未知类型

示例代码:

// 使用通配符
public static void printValues(List<?> values) {
    for (Object value : values) {
        System.out.println(value);
    }
}

public static void main(String[] args) {
    System.out.println("开始打印 整数");
    List<Integer> integers = Arrays.asList(1, 2, 3);
    printValues(integers);

    System.out.println("开始打印 小数");
    List<Double> doubles = Arrays.asList(1.1, 2.2);
    printValues(doubles);
}

输出结果:

开始打印 整数
1
2
3
开始打印 小数
1.1
2.2

在上述代码中,printValues 方法使用了通配符 ?,允许接受任意类型的 List。

2)泛型上下界

用于限定泛型类型的范围

示例代码:

// 使用泛型上下界
public static <T extends Number> double sum(List<T> numbers) {
	double total = 0;
	for (T number : numbers) {
		total += number.doubleValue();
	}
	return total;
}

public static void main(String[] args) {
	List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
	System.out.println("整数的加和结果是: " + sum(integers));

	List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3, 4.4);
	System.out.println("小数的加和结果是: " + sum(doubles));
}

输出结果:

整数的加和结果是: 15.0
小数的加和结果是: 11.0

在上述代码中, sum 方法使用了泛型上下界 T extends Number,表示只能接受 Number 类型或其子类型

泛型的好处

  • 类型安全: 泛型提供了编译时的类型检查,避免了在运行时发生类型错误的可能性。
  • 代码复用: 泛型允许编写通用的代码,适用于多种数据类型,提高了代码的复用性。
  • 可读性和可维护性: 使用泛型能够使代码更加清晰、简洁,提高了代码的可读性和可维护性。

注意事项

  • 类型擦除: 泛型在编译时会进行类型擦除,即泛型信息在运行时被擦除,转换为原始类型。这可能导致一些限制,例如不能直接创建泛型数组。
  • 通配符限制: 使用通配符 <?> 时,只能读取,无法修改泛型集合中的元素。如果需要修改,可以使用 <? extends T><? super T>
  • 泛型和继承: 泛型不支持协变(covariant)和逆变(contravariant)。例如,List 不是 List 的子类型。
  • 原始类型和泛型混用: 尽量避免在泛型代码中使用原始类型,以保持类型安全。

用通配符 <?> 时,只能读取,无法修改泛型集合中的元素。如果需要修改,可以使用 <? extends T><? super T>

  • 泛型和继承: 泛型不支持协变(covariant)和逆变(contravariant)。例如,List 不是 List 的子类型。
  • 原始类型和泛型混用: 尽量避免在泛型代码中使用原始类型,以保持类型安全。

在实际编程中,合理利用泛型可以使代码更加健壮、灵活,但也需要注意一些泛型的特性和限制。通过了解和熟练使用泛型,可以写出更加清晰、安全和可维护的 Java 代码。


http://www.kler.cn/a/154521.html

相关文章:

  • Excel超级处理器:高效实现2种批量生成二维码方式
  • 使用视频提升应用在 App Store 中的推广效果
  • Ubuntu 24.04 安装 JDK 21
  • 无效的目标发行版17和无法连接Maven进程问题
  • 自存 关于RestController请求传参数 前端和后端相关
  • 第三百二十三节 Java线程教程 - Java同步器
  • 充电桩自检流程
  • 公司网站遇到HTTPS攻击,有什么办法解决
  • 百度下拉词挖掘工具,百度下拉词挖掘获取软件
  • python程序内存泄漏的解决方法
  • 分享几个可以免费使用GPT工具
  • 毕业论文管理系统的设计与实现
  • Docker 简介及其常用命令详解
  • Android 13 - Media框架(18)- CodecBase
  • 记录 | ssh config免密连接
  • Mybatis 的操作(要结合上个博客一起)续集
  • 抓包 Hook 工具Objection
  • Leecode 【一】
  • 2023年AI时代中小企业智能化发展报告
  • Go 语言中 sync 包的近距离观察
  • MySQL表连接详解:解析内连接与外连接的使用方法
  • 【Element-ui】Element-ui是什么?如何安装
  • YOLOv8改进 | 2023 | 给YOLOv8换个RT-DETR的检测头(重塑目标检测前沿技术)
  • javascript的Proxy
  • HNU-青蛙与蚊子
  • 【动态规划】LeetCode-LCR166.珠宝的最高价值