Java之Java基础十九(泛型)

在 Java 中,泛型是一种强类型约束机制,可以在编译期间检查类型安全性,并且可以提高代码的复用性和可读性。

一个泛型类就是具有一个或多个类型变量的类。Arraylist 类引入的类型变量为 E(Element,元素的首字母),使用尖括号 <> 括起来,放在类名的后面。

然后,我们可以用具体的类型(比如字符串)替换类型变量来实例化泛型类。

Arraylist<String> list = new Arraylist<String>();
list. Add("aaa");
String str = list. Get(0);animals. Get

一、类型参数化

泛型的本质是参数化类型,也就是说,在定义类、接口或方法时,可以使用一个或多个类型参数来表示参数化类型。

例如这样可以定义一个泛型类。

public class Box<T> {
    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

在这个例子中,<T> 表示类型参数,可以在类中任何需要使用类型的地方使用 T 代替具体的类型。通过使用泛型,我们可以创建一个可以存储任何类型对象的盒子。

Box<Integer> intBox = new Box<>(123);
Box<String> strBox = new Box<>("Hello, world!");

泛型在实际开发中的应用非常广泛,例如集合框架中的 List、Set、Map 等容器类,以及并发框架中的 Future、Callable 等工具类都使用了泛型。

二、类型擦除

 

在 Java 的泛型机制中,有两个重要的概念:类型擦除和通配符。

泛型在编译时会将泛型类型擦除,将泛型类型替换成 Object 类型。这是为了向后兼容,避免对原有的 Java 代码造成影响。

例如,对于下面的代码:

List<Integer> intList = new ArrayList<>();
intList.add(123);
int value = intList.get(0);

在编译时,Java 编译器会将泛型类型 List<Integer> 替换成 List<Object>,将 get 方法的返回值类型 Integer 替换成 Object,生成的字节码与下面的代码等价:

List intList = new ArrayList();
intList.add(Integer.valueOf(123));
int value = (Integer) intList.get(0);

Java 泛型只在编译时起作用,运行时并不会保留泛型类型信息。

三、通配符

通配符用于表示某种未知的类型,例如 List<?> 表示一个可以存储任何类型对象的 List,但是不能对其中的元素进行添加操作。通配符可以用来解决类型不确定的情况,例如在方法参数或返回值中使用。

使用通配符可以使方法更加通用,同时保证类型安全。

例如,定义一个泛型方法:

public static void printList(List<?> list) {
    for (Object obj : list) {
        System.out.print(obj + " ");
    }
    System.out.println();
}

这个方法可以接受任意类型的 List,例如 List<Integer>List<String> 等等。

(1)上限通配符

泛型还提供了上限通配符 <? extends T>,表示通配符只能接受 T 或 T 的子类。使用上限通配符可以提高程序的类型安全性。

例如,定义一个方法,只接受 Number 及其子类的 List:

public static void printNumberList(List<? extends Number> list) {
    for (Number num : list) {
        System.out.print(num + " ");
    }
    System.out.println();
}

这个方法可以接受 List<Integer>List<Double> 等等。

(2)下限通配符

下限通配符(Lower Bounded Wildcards)用 super 关键字来声明,其语法形式为 <? super T>,其中 T 表示类型参数。它表示的是该类型参数必须是某个指定类的超类(包括该类本身)。

当我们需要往一个泛型集合中添加元素时,如果使用的是上限通配符,集合中的元素类型可能会被限制,从而无法添加某些类型的元素。但是,如果我们使用下限通配符,可以将指定类型的子类型添加到集合中,保证了元素的完整性。

举个例子,假设有一个类 Animal,以及两个子类 Dog 和 Cat。现在我们有一个 List<? super Dog> 集合,它的类型参数必须是 Dog 或其父类类型。我们可以向该集合中添加 Dog 类型的元素,也可以添加它的子类。但是,不能向其中添加 Cat 类型的元素,因为 Cat 不是 Dog 的子类。

下面是一个使用下限通配符的示例:

List<? super Dog> animals = new ArrayList<>();

// 可以添加 Dog 类型的元素和其子类型元素
animals.add(new Dog());
animals.add(new Bulldog());

// 不能添加 Cat 类型的元素
animals.add(new Cat()); // 编译报错

需要注意的是,虽然使用下限通配符可以添加某些子类型元素,但是在读取元素时,我们只能确保其是 Object 类型的,无法确保其是指定类型或其父类型。因此,在读取元素时需要进行类型转换,如下所示:

List<? super Dog> animals = new ArrayList<>();
animals.add(new Dog());

// 读取元素时需要进行类型转换
Object animal = animals.get(0);
Dog dog = (Dog) animal;

总的来说,Java 的泛型机制是一种非常强大的类型约束机制,可以在编译时检查类型安全性,并提高代码的复用性和可读性。但是,在使用泛型时也需要注意类型擦除和通配符等问题,以确保代码的正确性。

参考链接:https://javabetter.cn/collection/generic.html

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值