Java之泛型:解读类型安全的利器

2023-11-21 11:36:43 浏览数 (1)


theme: healer-readable

highlight: a11y-dark


哈喽,各位小伙伴们,你们好呀,我是喵手。

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

在Java开发中,经常需要处理各种数据类型。但是,传统的Java使用Object类型作为通用数据类型会存在一些问题,如数据类型的转换等。Java泛型的出现就是为了解决这些问题。

摘要

本文将介绍Java泛型的基本概念、语法和应用场景。通过对源代码的分析和案例的讲解,掌握泛型的使用方法和操作技巧,同时分析泛型的优缺点,并介绍相应的应用实例。最后,通过测试用例对泛型的使用进行验证,总结泛型的特点和使用场景。

泛型

简介

Java泛型是Java 5的新特性,是一种将数据类型参数化的机制。它可以使编译器在编译时强制进行类型检查,从而提高代码的可读性和安全性。

泛型可以在类、接口、方法中定义类型参数,使得它们可以使用不同类型的对象而不需要进行数据类型转换。泛型的出现使得程序员可以编写更加通用、类型安全、可重用和简洁的代码。

源代码解析

Java泛型的关键就在于定义类型参数。Java泛型的定义采用尖括号“<>”将类型参数括在一起,如下所示:

代码语言:java复制
class ClassName<T> {  
    // ...
}

其中,T为类型参数,可以是任意非关键字的标识符。通过使用T来代表类型参数,可以在类或方法内部使用该类型。通过在实例化类或调用方法时指定具体类型,可以在编译时进行类型检查。

这是一个泛型类定义,其中 T 是泛型类型参数。它表示该类可以接受任意类型的参数。在类的定义中,可以使用 T 作为类型参数定义类中的各种成员变量、方法或构造函数等。在实例化该泛型类时,会指定实际的类型参数来替换 T。例如:

代码语言:txt复制
ClassName<String> instance = new ClassName<>();

这里实例化了一个 ClassName 类,其中 T 被替换为 String 类型。这意味着在该实例中,可以使用 String 类型的成员变量、方法或构造函数等。

除了类型参数,还有通配符类型参数?,可以用来表示不确定的类型。例如:

代码语言:java复制
public void printList(List<?> list) {
  // ...
}

该方法接受一个List类型的参数,该List中的元素类型可以是任意类型,但是不确定具体是什么类型。

应用场景案例

集合类中使用泛型

在Java集合类中,最常见的使用泛型的地方是在List、Set和Map等容器类中。例如:

代码语言:java复制
List<String> list = new ArrayList<String>();
Set<Integer> set = new HashSet<Integer>();
Map<String, Integer> map = new HashMap<String, Integer>();

这里定义了一个List类型的集合,其中只能添加String类型的元素;定义了一个Set类型的集合,其中只能添加Integer类型的元素;定义了一个Map类型的集合,其中Key的类型是String,Value的类型是Integer。

自定义泛型类和泛型方法

我们也可以自定义泛型类和泛型方法。例如,我们定义一个泛型类来表示一对数据:

代码语言:java复制
class Pair<T, V> {
  private T first;
  private V second;
  public Pair(T first, V second) {
    this.first = first;
    this.second = second;
  }
  // 省略其他代码
}

这里定义了一个类Pair,它包含两个类型参数TV,分别表示第一个数据和第二个数据的类型。我们还可以定义泛型方法来操作泛型类型:

代码语言:java复制
public static <T> T getMax(T[] array) {
  T max = array[0];
  for (int i = 1; i < array.length; i  ) {
    if (array[i].compareTo(max) > 0) {
      max = array[i];
    }
  }
  return max;
}

该方法接收一个泛型数组,返回其中最大的元素。这里使用了类型参数T表示数组中元素的类型。通过compareTo方法比较数组中元素的大小,返回最大元素。

优缺点分析

优点

  1. 提高代码的可读性和安全性;
  2. 实现了代码的类型安全检查,减少了运行时的错误;
  3. 可以在编译时检查代码的类型安全,避免了数据类型转换的问题;
  4. 实现了代码的重用性和通用性。

缺点

  1. 在某些情况下,使用泛型会导致代码的可读性降低;
  2. 泛型的类型参数不能是基本数据类型,只能使用其对应的包装类;
  3. 不能使用泛型数组,只能使用泛型容器。

类代码方法介绍

泛型类

在Java中,泛型类用<T>来替代具体的数据类型。

代码语言:java复制
package com.example.javase.se.classes.generic;

import java.util.List;

/**
 * @Author ms
 * @Date 2023-11-05 19:10
 */
class Pair<T extends Comparable<T>, V> {

    private T first;
    private V second;

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

    public Pair() {
    }


    public static Integer getMax(List<Pair<String, Integer>> array) {
        Integer max = array.get(0).second;
        for (int i = 1; i < array.size(); i  ) {
            if (array.get(i).second > max) {
                max = array.get(i).second;
            }
        }
        return max;
    }

    @Override
    public String toString() {
        return "Pair{"  
                "first="   first  
                ", second="   second  
                '}';
    }
}

这里定义了一个泛型类Pair,包含两个类型参数TV,分别表示第一个数据和第二个数据的类型。通过<T, V>声明类型参数。

该代码定义了一个泛型类Pair,其中含有两个成员变量firstsecond,分别表示泛型类型TV的第一个和第二个值。类中包含了一个有限制的泛型方法getMax,用于返回一个列表中第二个值最大的整数。该方法使用了通配符? extends Comparable<?>来限制泛型类型T必须实现Comparable接口,以便能够进行比较操作。在实例化该类时,可以指定TV的具体类型,也可以不指定,使用默认值。类中还包含了一个重写的toString方法,用于将实例对象转化为字符串。

泛型方法

在Java中,泛型方法需要在方法名前面添加类型参数列表,用<T>来替代具体的数据类型。

代码语言:java复制
    public static Integer getMax(List<Pair<String, Integer>> array) {
        Integer max = array.get(0).second;
        for (int i = 1; i < array.size(); i  ) {
            if (array.get(i).second > max) {
                max = array.get(i).second;
            }
        }
        return max;
    }

这里定义了一个泛型方法getMax,它接收一个泛型数组,并返回其中最大的元素。通过<T>声明类型参数。

通配符

通配符可以用来表示不确定的类型,写法为<?>。例如:

代码语言:java复制
public void printList(List<?> list) {
  // ...
}

这里定义了一个方法printList,它接收一个List类型的参数,该List中的元素类型可以是任何类型。

测试用例

代码语言:java复制
package com.example.javase.se.classes.generic;

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

/**
 * @Author ms
 * @Date 2023-11-05 19:10
 */
public class Test {
    public static void main(String[] args) {
        Pair<String, Integer> p1 = new Pair<>("Java", 5);
        Pair<String, Integer> p2 = new Pair<>("Python", 7);
        Pair<String, Integer> p3 = new Pair<>("C  ", 3);

        List<Pair<String, Integer>> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);

        Integer maxPair = Pair.getMax(list);
        System.out.println("Max Pair: "   maxPair);
    }
}

该测试用例测试了Pair类和Pair类的泛型方法getMax。首先创建了三个Pair对象,并将它们添加到一个List中。然后调用getMax方法,返回其中最大的元素。

测试结果

  根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。

在这里插入图片描述在这里插入图片描述

测试代码分析

  根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。

这段代码演示了如何使用泛型类Pair及其静态方法getMax来实现获取列表中最大值的功能。

首先,我们定义了三个Pair对象p1、p2、p3,这些对象分别包含了一个String类型的值和一个Integer类型的值。

接着,我们创建了一个List对象list,并向其添加了p1、p2、p3三个对象。

最后,我们调用Pair类的静态方法getMax来获取list列表中所有Pair对象中的最大值,并将结果保存在一个Integer类型的变量maxPair中。最终,我们将maxPair打印输出。

值得注意的是,因为Pair类中定义了泛型类型<T extends Comparable<T>>,所以我们才可以使用Pair类提供的getMax方法来获取最大值。此外,我们定义的列表list中的元素类型也必须与Pair对象的类型一致,即都是Pair<String, Integer>类型。

小结

本文介绍了Java泛型的基本概念、语法和应用场景。通过对源代码的分析和案例的讲解,掌握了泛型的使用方法和操作技巧,同时分析了泛型的优缺点,并介绍了相应的应用实例。最后,通过测试用例对泛型的使用进行了验证,总结了泛型的特点和使用场景。

总结

Java泛型是Java 5的新特性,是一种将数据类型参数化的机制。它可以使编译器在编译时强制进行类型检查,从而提高代码的可读性和安全性。泛型可以在类、接口、方法中定义类型参数,使得它们可以使用不同类型的对象而不需要进行数据类型转换。泛型的出现使得程序员可以编写更加通用、类型安全、可重用和简洁的代码。

... ...

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

... ...

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞