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

泛型的二三事

泛型(Generics)是Java语言的一个重要特性,它允许在定义类、接口和方法时使用类型参数(Type Parameters),从而实现类型安全的代码重用。泛型在Java 5中被引入,极大地增强了代码的灵活性和安全性。以下是关于泛型的详细介绍,包括其基本概念、使用场景和一些高级特性。


1. 泛型的基本概念

1.1 什么是泛型

泛型允许在定义类、接口或方法时使用类型参数,而不是具体的类型。这样可以在运行时动态指定类型,同时保持类型安全。例如:

class Box<T> { // T 是类型参数
    private T t; // 使用类型参数 T

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }
}

在这个例子中,Box 类使用了类型参数 T,可以在实例化时指定具体的类型,例如:

Box<Integer> intBox = new Box<>();
intBox.set(10);
System.out.println(intBox.get()); // 输出 10
1.2 泛型的好处
  1. 类型安全:编译器会在编译时检查类型是否正确,避免了类型转换错误。

  2. 代码复用:通过泛型可以编写通用的类和方法,减少重复代码。

  3. 减少类型转换:在使用泛型时,不需要显式进行类型转换,代码更加简洁。


2. 泛型的使用场景

2.1 泛型类

泛型类是在类定义时使用类型参数。例如:

class Pair<T, U> {
    private T first;
    private U second;

    public Pair(T first, U second) {
        this.first = first;
        this.second = second;
    }

    public T getFirst() {
        return first;
    }

    public U getSecond() {
        return second;
    }
}

使用时:

Pair<String, Integer> pair = new Pair<>("Hello", 123);
System.out.println(pair.getFirst()); // 输出 Hello
System.out.println(pair.getSecond()); // 输出 123
2.2 泛型接口

泛型接口与泛型类类似,可以在接口定义时使用类型参数。例如:

interface Generator<T> {
    T next();
}

实现时:

class RandomNumberGenerator implements Generator<Integer> {
    @Override
    public Integer next() {
        return (int) (Math.random() * 100);
    }
}
2.3 泛型方法

泛型方法是在方法定义时使用类型参数。例如:

public static <T> void printArray(T[] array) {
    for (T element : array) {
        System.out.println(element);
    }
}

调用时:

Integer[] intArray = {1, 2, 3};
String[] strArray = {"Hello", "World"};
printArray(intArray); // 输出 1 2 3
printArray(strArray); // 输出 Hello World

3. 泛型的高级特性

3.1 类型参数的限制(上界)

可以为类型参数指定上界,即类型参数必须是某个类或接口的子类型。例如:

public static <T extends Number> double sum(T[] array) {
    double total = 0;
    for (T element : array) {
        total += element.doubleValue();
    }
    return total;
}

调用时:

Integer[] intArray = {1, 2, 3};
System.out.println(sum(intArray)); // 输出 6.0
3.2 泛型通配符(Wildcards)

泛型通配符用于表示未知类型。主要有以下几种:

  1. 无界通配符(?:表示任意类型

    public static void printList(List<?> list) {
        for (Object element : list) {
            System.out.println(element);
        }
    }
  2. 有界通配符(? extends T:表示类型参数是 T 的子类型

    public static void printNumbers(List<? extends Number> list) {
        for (Number element : list) {
            System.out.println(element);
        }
    }
  3. 有界通配符(? super T:表示类型参数是 T 的父类型

    public static void addNumbers(List<? super Integer> list) {
        list.add(1);
        list.add(2);
    }
3.3 泛型的类型擦除

Java的泛型在运行时会被擦除,即运行时不会保留泛型类型信息。例如:

Box<Integer> intBox = new Box<>();
Box<String> strBox = new Box<>();
System.out.println(intBox.getClass() == strBox.getClass()); // 输出 true

这意味着运行时 intBoxstrBox 的类型是相同的,都是 Box 类。


4. 泛型的常见问题

4.1 泛型方法的类型推断

Java编译器可以自动推断泛型方法的类型参数。例如:

public static <T> T getFirst(T[] array) {
    return array[0];
}

调用时:

Integer first = getFirst(new Integer[]{1, 2, 3}); // 编译器推断 T 为 Integer
4.2 泛型与静态方法

泛型方法不能直接定义在静态方法中,因为静态方法属于类本身,而不是类的实例,而泛型类型参数是与实例相关的。例如:

class Box<T> {
    public static <T> T getFirst(T[] array) { // 错误:静态方法不能使用类的泛型参数
        return array[0];
    }
}
4.3 泛型与数组

不能创建泛型数组,因为数组类型在运行时是固定的,而泛型类型在运行时会被擦除。例如:

T[] array = new T[10]; // 错误:不能创建泛型数组

但可以通过其他方式解决,例如:

T[] array = (T[]) new Object[10];

 5.一个泛型代码分析

先来看一个实例:

这段代码是一个Java程序,用于通过泛型方法找到数组中的最大值。以下是对代码的详细分析和一些需要注意的地方:

5.1代码功能

  1. findmaxvalue 方法

    • 这是一个泛型方法,使用了泛型类型 T,并且要求 T 必须实现 Comparable<T> 接口。这意味着传入的数组元素类型必须是可以比较的(例如 IntegerDoubleString 等)。

    • 方法逻辑:

      • 首先检查数组是否为空或为 null,如果是,则抛出 IllegalArgumentException 异常。

      • 将数组的第一个元素初始化为最大值 max

      • 遍历数组,从第二个元素开始,使用 compareTo 方法比较当前元素和 max 的大小。如果当前元素更大,则更新 max

      • 最后返回最大值。

  2. main 方法

    • 定义了一个 Integer 类型的数组 integers1,并将其设置为 null

    • 调用 Alg.findmaxvalue(integers1) 方法,尝试找到数组中的最大值。

    • 将返回的最大值打印到控制台。

5.2代码运行结果

由于 integers1 被设置为 null,在调用 findmaxvalue 方法时,会触发 findmaxvalue 方法中的异常检查逻辑,抛出 IllegalArgumentException 异常,程序会终止并打印异常信息。

5.3输出结果

运行改进后的代码,输出结果为:

5

如果将 integers1 设置为 null 或空数组,程序会输出:

Error: Array is empty or null

 


6. 总结

泛型是Java语言中一个非常强大的特性,它提供了类型安全、代码复用和减少类型转换的好处。通过泛型类、泛型接口和泛型方法,可以编写更加通用和灵活的代码。同时,理解泛型的高级特性(如类型擦除、通配符等)可以帮助你更好地使用泛型,避免常见问题。

如果你有更多关于泛型的具体问题,欢迎随时提问!

相关文章:

  • oracle DECODE 函数
  • DeeplxFile相关文件下载
  • 七、自动化概念篇
  • Elasticsearch 故障转移及水平扩容
  • 使用Python和Matplotlib可视化字体轮廓:从路径数据到矢量图形
  • C语言中三角与反三角函数的表达
  • 系统编程2(消息队列)
  • 《从零搭建Vue3项目实战》零基础入门一篇通关(AI辅助搭建Vue3+ElemntPlus后台管理项目)
  • c++:new关键字
  • 深度学习(对抗)
  • forms实现快读阅读器
  • 操作系统 第三章 内存管理
  • 爬虫:IP代理
  • HTTP 1.1 比 HTTP1.0 多了什么?(详尽版)
  • Arm CPU安全通告:基于TrustZone的Cortex-M系统面临多重故障注入攻击
  • linux多线(进)程编程——(5)虚拟内存与内存映射
  • 14、nRF52xx蓝牙学习(串口 UART 和 UARTE 外设应用)
  • 【Linux】what is pam?PAM模块学习笔记
  • CTF-WEB排行榜制作
  • JavaWeb 课堂笔记 —— 10 MySQL DML + DQL
  • 江南考古文脉探寻
  • 外交部部长助理兼礼宾司司长洪磊接受美国新任驻华大使递交国书副本
  • 中央提级巡视后,昆明厅官郭子贞接受审查调查
  • 乌克兰官员与法德英美四国官员举行会谈
  • 赡养纠纷个案推动类案监督,检察机关保障特殊群体胜诉权
  • “大型翻车现场”科技满满,黄骅打造现代化港口和沿海新城典范