首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【JavaSE】集合类 && 包装类 && 泛型 && 类型擦除问题

【JavaSE】集合类 && 包装类 && 泛型 && 类型擦除问题

原创
作者头像
lirendada
发布2026-03-21 12:02:21
发布2026-03-21 12:02:21
990
举报
文章被收录于专栏:JavaJava

Java 集合类

  1. Collection:是一个接口,包含了大部分容器常用的一些方法
  2. List:是一个接口,规范了 ArrayListLinkedList 中要实现的方法
  3. ArrayList:实现了 List 接口,底层为动态类型顺序表
  4. LinkedList:实现了 List 接口,底层为双向链表
  5. Stack:底层是栈,栈是一种特殊的顺序表
  6. Queue:底层是队列,队列是一种特殊的顺序表
  7. Deque:是一个接口
  8. Set:集合,是一个接口,里面放置的是 K 模型
    1. HashSet:底层为哈希桶,查询的时间复杂度为 O(1)
    2. TreeSet:底层为红黑树,查询的时间复杂度为 O(logn),关于 key 有序
  9. Map:映射,里面存储的是 K-V 模型的键值对
    1. HashMap:底层为哈希桶,查询时间复杂度为 O(1)
    2. TreeMap:底层为红黑树,查询的时间复杂度为 O(logn),关于 key 有序

Ⅰ. 包装类

在 Java 中,由于基本类型不是继承自 Object,为了在泛型代码中可以支持基本类型,Java 给每个基本类型都对应了一个包装类型,如下图所示:

装箱与拆箱

所谓的装箱其实就是将基本数据类型转化为包装类,而拆箱就是将包装类转化为基本数据类型。

为了减少开发者的负担,java 提供了自动机制,即不需要强制类型转换

代码语言:javascript
复制
public static void main(String[] args) {
    Integer i = 10;
    int j = i; // 自动装箱
    System.out.println(i); // 输出 10
    System.out.println(j); // 输出 10

    int a = 20;
    Integer b = a; // 自动拆箱
    System.out.println(a); // 输出 20
    System.out.println(b); // 输出 20
}

🌟面试题

代码语言:javascript
复制
public static void main(String[] args) {
    Integer a = 127;
    Integer b = 127;
    System.out.println(a == b); // true

    Integer c = 128;
    Integer d = 128;
    System.out.println(c == d); // false

    Integer e = -128;
    Integer f = -128;
    System.out.println(e == f); // true

    Integer g = -129;
    Integer h = -129;
    System.out.println(g == h); // false
}

JavaInteger 类型在 [-128, 127] 之间的值进行了缓存,目的是优化内存和性能。

  • 如果值在 [-128, 127] 之间,会直接从缓存中返回同一个 Integer 对象(所以 == 比较结果为 true
  • 如果值超出这个范围,每次会创建新的 Integer 对象(所以 == 比较结果为 false

这就有点像字符串常量池的原理!当然这个值是多少,是由设计者说了算的,我们只需要知道有这个机制在即可

Java 基本数据类型的包装类型的大部分都用到了缓存机制来提升性能。

  • ByteShortIntegerLong 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据
  • Character 创建了数值在 [0,127] 范围的缓存数据
  • Boolean 直接返回 TRUE or FALSE

Ⅱ. 泛型

泛型是一种程序设计中的重要特性,主要用来编写与类型无关的代码

它的核心思想就是:编写一次代码,适用于多种类型,提高代码的复用性、可读性和类型安全性

一、泛型类

代码语言:javascript
复制
class MyClass<T> {
    T a;
    T[] b = (T[])new Object[10]; // 数组的初始化仍然需要Object来构造,并且进行强制类型转换
}

public class demo3 {
    public static void main(String[] args) {
        // 泛型类的实例化
        MyClass<String> a = new MyClass<>(); // 后面尖括号可以忽略类型
        MyClass<Integer> b = new MyClass<Integer>(); 
    }
}

🤖注意:泛型只能接受类,所有的基本数据类型必须使用包装类

二、泛型方法

代码语言:javascript
复制
public class demo {
    // 在返回值之前声明一下<T>表示一个泛型T,然后在返回值和参数列表以及方法体中就能使用了!
    public <T> void swap(T[] arr, int i, int j) {
        T tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void main(String[] args) {
        Integer[] arr = {1, 2, 3, 4, 5};
        System.out.println("交换前:" + arr[1] + " " + arr[3]);
        
        demo d = new demo();
        d.swap(arr, 1, 3);
        System.out.println("交换后:" + arr[1] + " " + arr[3]);
    }
}

三、通配符与泛型的上下界

有时候我们想写更灵活的泛型,就会用到通配符 ?,表示匹配任何一种类型

? extends T(上界)

表示类型是 T 或 T 的子类。

代码语言:javascript
复制
List<? extends Number> nums = new ArrayList<Integer>();

? super T(下界)

表示类型是 T 或 T 的父类。

代码语言:javascript
复制
List<? super Integer> ints = new ArrayList<Number>();

四、类型擦除问题

在模拟实现哈希表的时候,内部需要有一个节点数组,并且采用泛型,此时按下面格式定义会报错:

代码语言:javascript
复制
public Node<K, V>[] arr = new Node<K, V>[10];  // ❌编译错误

这是因为 Java泛型是编译时生效的,但在运行时会被 "擦除",即泛型信息不会保留在字节码中。也就是说,运行时 JVM 看到的其实是 Node[],而不是 Node<K, V>[]

所以只能退而求其次,创建一个原始类型的数组,再手动强转成泛型数组:

代码语言:javascript
复制
// 正确做法:
new Node[10]           // 创建的是原始类型的数组
(Node<K, V>[]) ...     // 强制转换为泛型数组

// 合并起来就是这样子:
public Node<K, V>[] arr = (Node<K, V>)new Node[];

并且为了消除警告,可以加上 @SuppressWarnings("unchecked") 注解来表示你知道这个操作不安全,但你已经检查过了:

代码语言:javascript
复制
@SuppressWarnings("unchecked")
public Node<K, V>[] arr = (Node<K, V>[]) new Node[10];

当然,现代的做法是使用集合类,而避免使用泛型数组,如下所示:

代码语言:javascript
复制
List<Node<K, V>> list = new ArrayList<>();  // 编译通过!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java 集合类
  • Ⅰ. 包装类
    • 装箱与拆箱
    • 🌟面试题
  • Ⅱ. 泛型
    • 一、泛型类
    • 二、泛型方法
    • 三、通配符与泛型的上下界
      • ? extends T(上界)
      • ? super T(下界)
    • 四、类型擦除问题
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档