第23节课-泛型-笔记

00/ 知识回顾

上一节,学习了Scanner类的导入。

接着,创建了Scanner类的实例对象。

然后,学习了Scanner对象中用于接收各种输入数据的方法。

最后,我们学习了生成随机数的Random类及其方法。

01/ 先导课

之前我们学习1~3节是基础知识,4~10节是循环与判断,11~14节是数组,15~22节是类和对象,接下来进入高级语法阶段。

之前我们学习了方法重载,在同一个类中,创建多个同名方法,根据具体的数据类型,定义不同的参数列表。那我们可不可以进一步简化?用一个方法就可以接收不同的数据类型。

答案是有的,在java中使用泛型,接下来我们开始学习。

泛型概念理解

在日常生活中,“泛”指广泛、普通或不特定。例如,"泛指"意味着不指某一个具体对象,而是指一个范围或类别。在编程中的泛型,也体现了类似的概念,它允许一个类或者方法,通过定义类型参数,能够处理不同类型的数据

02/ 包装类

什么是包装类?

包装类是Java中的类,它们用于将基础类型的数据封装成对象

这些对象具有一些额外的功能,例如提供了一些方法来操作基础类型的数据,支持面向对象编程的特性,以及允许处理null值等。

// int的包装类Integer,可以存储null值
Integer x = null;
// 使用包装类的equals方法判断x与y的值是否相等
Integer x = 10;
Integer y = 20;
System.out.print(x.equals(y));
​
// 输出结果
false

基础类型对应的包装类是什么?

基础类型对应的包装类如下表所示,包装类遵循“类名首字母大写”的约定。

基础类型和包装类之间的关系

基础类型和包装类的关系可以比作现金和银行卡:

基础类型是现金,它直接代表货币价值,使用方便、高效。

包装类是银行卡,它代表数字货币,除了用来消费外它提供了更多的功能,如转账、查询,但处理起来比现金更复杂。

自动装箱(了解即可)

自动装箱是Java中的一个特性,它是指在需要使用包装类的地方,可以自动地将基础数据类型的值转换为对应的包装类对象,而不需要显式地进行类型转换。

// 自动装箱,将int类型的值42转换为Integer对象
Integer num = 42; 

02/ 在方法中使用泛型

方法重载的写法和泛型写法对比

方法重载的写法:

// 支持int类型的printArray方法,用来输出一个数组的每个元素
public static void printArray(int[] inputArray) {
    // 遍历数组的每一个元素并输出
    for (int element : inputArray) {
        System.out.println(element);
    }
}
​
// 支持char类型的printArray方法,用来输出一个数组的每个元素
public static void printArray(char[] inputArray) { 
    for (char element : inputArray) {        
        System.out.println(element);   
    }
}
​
// 支持double类型的printArray方法,用来输出一个数组的每个元素
public static void printArray(double[] inputArray) {   
    for (double element : inputArray) { 
        System.out.println(element);  
    }
}
​
// 支持String类型的printArray方法,用来输出一个数组的每个元素
public static void printArray(String[] inputArray) { 
    for (String element : inputArray) { 
        System.out.println(element);  
    }
}

使用泛型写法:

public static <T> void printArray(T[] inputArray) {  
    for (T element : inputArray) {    
        System.out.println(element);  
    }
}
  1. void前面多了一个符号<T>,它是类型参数,一个占位符,表示方法可以操作任意数据类型,而不是固定在某一特定类型上。

  2. printArray后的括号里面是泛型数组参数,表示该方法接受一个类型为T的数组。

  3. T element是方法中的一个泛型变量,表示一个类型为T的变量。

调用泛型方法

当你调用printArray方法并传递参数时,T会自动识别实参的数据类型,并按照该类型执行方法中的代码。注意,当参数类型为基础类型时,必须替换为对应的包装类,如int替换为Integer

public static <T> void printArray(T[] inputArray) {
    for (T element : inputArray) {
        System.out.println(element);
    }
}
// 传递int类型的数组,需要使用int的包装类Integer
Integer[] arr1 = {1, 2};
printArray(arr);
 
// 传递char类型的数组,需要使用char的包装类Character
Character[] arr2 = {'a', 'b'};
printArray(arr);
​
// 输出结果
1
2
a
b

可以为方法设置泛型返回值

firstElement设置了一个T类型的返回值

// firstElement方法:可以返回任意类型数组的第一个元素
public static <T> T firstElement(T[] inputArray) {
    return inputArray[0];
}
​
// 传递int类型的数组,需要使用int的包装类Integer
Integer[] arr1 = {1, 2};
int firstNum = firstElement(arr1);
System.out.println(firstNum);
​
// 输出结果
1

练习题

编写一个Java程序,创建一个泛型方法 linearSearch,该方法接受一个泛型数组和一个目标元素,返回目标元素在数组中的索引位置(从0开始)。如果目标元素不存在于数组中,则返回 -1。

public class MyTest {
    // 定义一个泛型方法linearSearch,用于在数组中搜索目标值
    public static <T> int linearSearch(T[] inputArray, T target) {
        // 遍历数组
        for (int i = 0; i < inputArray.length; i++) {
            // 使用equals方法比较目标值和当前数组元素是否相等
            if (target.equals(inputArray[i])) {
                // 如果相等,返回当前元素的索引位置
                return i;
            }
        }
        // 如果循环结束仍未找到目标值,返回 -1 表示目标值不存在于数组中
        return -1;
    }
    
    // 这里是主方法
    public static void main(String[] args) {
        // 包装类
        Integer[] nums = {7, 6, 2};
        // 搜索目标值3
        int index3 = linearSearch(nums, 3);
        System.out.println(index3);
        // 搜索目标值6
        int index6 = linearSearch(nums, 6);
        System.out.println(index6);
    }
}
​
// 输出结果
-1
1

03/ 在类中使用泛型

为什么需要有泛型类?

假设你正在开发一个应用程序,需要编写一个通用的类来临时存储各种类型的数据,如用户信息、配置设置或临时计算结果。这些数据可能是字符串、整数、或者更复杂的对象(如自定义的用户类)。此时,你需要定义一个泛型类。

怎么定义泛型类

// 定义了一个TempData类,并为其设置类型参数T
class TempData<T> {
    // 私有属性data用来存储任意类型的临时数据
    private T data;
    // 构造方法TempData为data属性赋值
    public TempData(T data) {
        this.data = data; 
    }
    // 公共方法getData返回data属性当前存储的数据
    public T getData() {
        return data;
    }
}

类型参数:与泛型方法类似,在定义泛型类时,我们可以在类名后添加类型参数<参数名>。其中 T 是一个类型参数,代表可以存储任何类型的数据。

泛型属性:借助类型参数T,你可以在泛型类中创建泛型属性。

泛型方法:借助类型参数T,你同样可以在泛型类中创建泛型方法。例如:构造方法,创建了一个T类型的参数data;公共方法,设置了返回值类型为T。

实例化对象

在声明泛型类的变量时,需要使用类名<数据类型包装类>的格式指定具体的类型。

注意,基础类型必须使用对应的包装类,例如int类就是TempData<Integer>

使用new关键字创建泛型类的对象时,需要在类名后添加一对空的尖括号,格式为:new 类名<>(实参);

		int userId = 1314;
        TempData<Integer> intData = new TempData<>(userId);

练习题

创建一个Box类用于模拟一个抽奖箱,其中包含了不同类型的奖品数据(它们使用任意类型的数组存储)。

该类型提供3个方法:

  1. head() 方法:返回数组的第一个元素。

  2. till() 方法:返回数组的最后一个元素。

  3. search(T target) 方法:在数组中搜索是否包含某个特定元素,若存在返回true,不存在返回false。

// 按要求创建类BOX
class Box<T> {
    // 创建一个私有的data属性,类型为泛型数组
    private T[] data;

    // 构造函数,接受泛型数组作为参数为data赋值
    public Box(T[] data) {
        this.data = data;
    }

    // head方法,返回数组的第一个元素
    public T head() {
        return this.data[0];
    }
    
    // till方法,返回数组的最后一个元素
    public T till() {
        return this.data[data.length - 1];
    }

    // search方法,搜索是否包含某个元素
    // 若包含返回true,不包含返回false
    public boolean search(T target) {
        for (T t : data) {
            if (t.equals(target)) {
                return true;
            }
        }
        return false;
    }
}

public class MyTest {
    public static void main(String[] args) {
        // 调用box
        String[] gifts = {"稀有", "传奇", "史诗", "金币10", "金币20", "金币30", "稀有"};
        Box<String> gameBox = new Box<>(gifts); // 创建 Box 对象,并传入字符串数组
        System.out.println("本次抽奖有史诗级奖品吗:" + gameBox.search("史诗")); // 检查是否包含 "史诗"
    }
}

// 输出
本次抽奖有史诗级奖品吗:true

04/ 扩展

05/ 总结

  1. 理解包装类,了解自动装箱。

  2. 学习在方法中使用泛型,并调用泛型方法。

  3. 学习在类中使用泛型,在泛型类中创建泛型属性、泛型方法,并学习实例化泛型类的对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值