MST

星途 面试题库

面试题:Java数据类型在泛型中的深度应用

在Java泛型编程中,定义一个支持多种数据类型(如Integer、String等)的通用容器类,要求在容器中实现数据的添加、获取、遍历操作。在此过程中,请详细说明如何处理类型擦除问题,以及如何利用通配符来增强泛型的灵活性和安全性,同时解释为什么需要使用受限通配符以及它们的具体应用场景。
39.8万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

通用容器类定义

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

public class GenericContainer<T> {
    private List<T> dataList;

    public GenericContainer() {
        dataList = new ArrayList<>();
    }

    // 添加数据
    public void add(T item) {
        dataList.add(item);
    }

    // 获取数据
    public T get(int index) {
        if (index >= 0 && index < dataList.size()) {
            return dataList.get(index);
        }
        return null;
    }

    // 遍历数据
    public void traverse() {
        Iterator<T> iterator = dataList.iterator();
        while (iterator.hasNext()) {
            T item = iterator.next();
            System.out.println(item);
        }
    }
}

类型擦除问题处理

  • 问题:Java 泛型是在编译期实现的,在运行时,泛型类型信息会被擦除,所有泛型类型参数都用其限定类型(无限定的类型参数用 Object)代替。这可能导致在运行时无法获取实际的类型信息,从而引发潜在的类型安全问题。
  • 解决方法:虽然运行时无法获取确切的泛型类型信息,但在编译期编译器会利用泛型类型参数进行类型检查。比如在 GenericContainer 类中,编译器会确保添加到容器中的数据类型与声明的泛型类型一致,避免了在运行时出现 ClassCastException。此外,可以通过 instanceof 结合反射来进行一定程度的类型检查,但要注意反射也有局限性且会增加代码复杂性。

通配符增强泛型灵活性和安全性

  1. 无界通配符 <?>
    • 示例List<?> 表示未知类型的 List
    • 用途:用于当你只需要对集合进行读操作,而不需要关心集合中元素的具体类型时。例如,printList(List<?>) 方法可以接受任何类型的 List 并打印其元素,因为 Object 类型足以处理所有可能的元素类型。
  2. 上界通配符 <? extends Type>
    • 示例List<? extends Number> 表示元素类型是 Number 或其子类型的 List
    • 用途:常用于读取数据。例如,一个方法接受 List<? extends Number> 作为参数,可以安全地读取 Number 类型的值,因为所有 Number 的子类型(如 IntegerDouble 等)都可以赋值给 Number
  3. 下界通配符 <? super Type>
    • 示例List<? super Integer> 表示元素类型是 Integer 或其父类型(如 NumberObject)的 List
    • 用途:常用于写入数据。例如,一个方法接受 List<? super Integer> 作为参数,可以安全地向列表中添加 Integer 类型的元素,因为所有 Integer 的父类型都能接受 Integer 类型的值。

受限通配符的必要性及应用场景

  1. 必要性
    • 增强类型安全性:通过限定泛型类型的范围,确保在编译期捕获更多类型错误,避免运行时的 ClassCastException
    • 提高代码灵活性:在保证类型安全的前提下,允许代码处理不同类型但有一定继承关系的对象,减少重复代码。
  2. 应用场景
    • 上界通配符场景:如编写一个计算 List<? extends Number> 中所有数字之和的方法,方法不需要关心具体是 Integer 还是 Double 等,只需要知道它们都是 Number 的子类型,从而可以安全地调用 Number 的方法进行计算。
    • 下界通配符场景:假设要向一个列表中添加 Integer 类型的元素,而这个列表可能是 List<Integer>List<Number> 甚至 List<Object>,使用 List<? super Integer> 作为参数类型可以确保能正确添加 Integer 元素,同时也增加了方法的通用性。