首页标签分类
001 Java 泛型与类型知识总结
2023-10-12 · 更新 2026-03-03约 6 分钟 · 1483 字
java基础
000

目录

Java 泛型与类型知识总结
一、Java 中基本数据类型和引用数据类型的区别
1. 存储位置
2. 类型分类
3. 内存大小
4. 默认值
5. 传值方式
6. 操作方式
7. 可空性
二、泛型为何不可用基本数据类型声明
1. 类型擦除机制
2. 基本数据类型与对象类型的区别
3. 自动装箱与拆箱机制
三、泛型上下限的使用
1. 上限通配符 ? extends T
2. 下限通配符 ? super T
3. 无界通配符 ?
四、Java 原生 API 中泛型的经典应用
1. Java 集合框架(Java Collections Framework)
a. List 接口
b. Map 接口
c. Set 接口
d. Queue 接口
2. Comparator 接口
3. Optional 类
4. Stream API
5. Future 和 CompletableFuture
6. Class 类
7. 函数式接口
a. Supplier
b. Consumer
c. Function
五、总结

Java 泛型与类型知识总结

本篇总结涵盖了 Java 中基本数据类型与引用数据类型的区别、泛型为何不能使用基本数据类型声明、泛型上下限的使用以及 Java 原生 API 中泛型的经典应用场景。每个知识点都配有详细的解释和代码示例,便于理解和复习。

一、Java 中基本数据类型和引用数据类型的区别

1. 存储位置

  • 基本数据类型:存储在 栈内存 中,变量直接包含实际的值。
  • 引用数据类型:存储在 堆内存 中,变量保存对象的引用(内存地址)。

2. 类型分类

  • 基本数据类型(共 8 种):
    • 整数类型:byteshortintlong
    • 浮点类型:floatdouble
    • 字符类型:char
    • 布尔类型:boolean
  • 引用数据类型
    • 类(Class)
    • 接口(Interface)
    • 数组(Array)
    • 枚举(Enum)
    • 注解(Annotation)

3. 内存大小

  • 基本数据类型:有固定的内存大小,例如:
    • int:4 字节
    • double:8 字节
  • 引用数据类型:大小不固定,取决于对象的具体内容。

4. 默认值

  • 基本数据类型:有默认值,例如:
    • int0
    • booleanfalse
  • 引用数据类型:默认值为 null,表示不引用任何对象。

5. 传值方式

  • 基本数据类型按值传递,方法调用时会复制一份值,不影响原值。
  • 引用数据类型按引用传递,传递对象的引用,可能影响原对象。

6. 操作方式

  • 基本数据类型:可直接进行算术运算。
  • 引用数据类型:需要通过方法调用操作对象。

7. 可空性

  • 基本数据类型:不能为 null
  • 引用数据类型:可以为 null

二、泛型为何不可用基本数据类型声明

1. 类型擦除机制

Java 的泛型是通过 类型擦除(Type Erasure)实现的,编译时会将泛型参数擦除为其上限类型(默认为 Object)。由于基本数据类型不是对象类型,不能被替换为 Object,因此泛型无法直接使用基本数据类型。

java
自动换行:关
放大阅读
展开代码
List<Integer> list = new ArrayList<>(); // 编译后类型擦除为: List list = new ArrayList<>();

2. 基本数据类型与对象类型的区别

基本数据类型不是对象,不能作为泛型的类型参数。泛型要求类型参数是一个对象类型(引用类型)。

3. 自动装箱与拆箱机制

Java 提供了 自动装箱(Autoboxing)和 自动拆箱(Unboxing)机制,将基本数据类型与其对应的包装类互相转换,使得基本数据类型可以间接用于泛型。

  • intInteger
  • doubleDouble
  • charCharacter
  • booleanBoolean 示例:
plaintext
自动换行:关
放大阅读
展开代码
java复制代码List<Integer> intList = new ArrayList<>(); intList.add(10); // 自动装箱,将 int 类型的 10 转换为 Integer 对象 int num = intList.get(0); // 自动拆箱,将 Integer 转换为 int

三、泛型上下限的使用

泛型上下限通过通配符 ? extends T(上限)和 ? super T(下限)来限定类型参数的范围,提高代码的灵活性和类型安全性。

1. 上限通配符 ? extends T

? extends T 表示类型是 TT 的子类,主要用于 读取,不能 写入(除了 null)。 示例:

java
自动换行:关
放大阅读
展开代码
import java.util.List; import java.util.ArrayList; public class ExtendsExample { public static void main(String[] args) { List<? extends Number> list = new ArrayList<Integer>(); // list.add(1); // 编译错误,不能添加元素 Number num = list.get(0); // 可以读取,类型为 Number } }

解释:

  • List<? extends Number> 表示列表中的元素类型是 Number 或其子类(如 IntegerDouble)。
  • 由于无法确定列表的具体子类型,不能安全地添加元素。
  • 可以安全地读取元素,读取的类型为上限 Number

2. 下限通配符 ? super T

? super T 表示类型是 TT 的父类,允许写入 T 及其子类的对象,适合 写入示例:

java
自动换行:关
放大阅读
展开代码
import java.util.List; import java.util.ArrayList; public class SuperExample { public static void main(String[] args) { List<? super Integer> list = new ArrayList<Number>(); list.add(1); // 可以添加 Integer list.add(new Integer(2)); // 可以添加 Integer // list.add(new Object()); // 编译错误,不能添加非 Integer 子类 Object obj = list.get(0); // 读取时只能作为 Object 类型 } }

解释:

  • List<? super Integer> 表示列表中的元素类型是 Integer 或其父类(如 NumberObject)。
  • 可以安全地添加 Integer 及其子类对象,因为它们都可以向上转型为 Integer 的父类。
  • 读取时只能作为 Object 类型,因为无法确定具体类型。 多态性解释:
  • Java 中的多态性允许子类对象赋值给父类引用。
  • 因此,Integer 类型的对象可以存储到 NumberObject 类型的列表中。

3. 无界通配符 ?

? 表示任意类型,由于类型未知,既不能安全地进行 读取,也不能 写入(除了 null)。 示例:

java
自动换行:关
放大阅读
展开代码
java复制代码import java.util.List; import java.util.ArrayList; public class UnboundedExample { public static void main(String[] args) { List<?> list = new ArrayList<String>(); // list.add("hello"); // 编译错误,不能添加元素 Object obj = list.get(0); // 可以读取,类型为 Object } }

解释:

  • List<?> 表示列表中的元素类型未知,可以是任何类型。
  • 由于无法确定类型,不能安全地添加元素,也不能确定读取元素的具体类型。

四、Java 原生 API 中泛型的经典应用

Java 的泛型在标准库中广泛应用,以下是一些经典的使用泛型的地方。

1. Java 集合框架(Java Collections Framework)

a. List 接口

List 接口及其实现类(如 ArrayListLinkedList)使用泛型,确保列表中的元素类型一致。

java
自动换行:关
放大阅读
展开代码
java复制代码List<String> stringList = new ArrayList<>(); stringList.add("Hello"); // stringList.add(1); // 编译错误,不能添加非 String 类型

b. Map 接口

Map<K, V> 是键值对集合,使用泛型参数 KV 表示键和值的类型。

java
自动换行:关
放大阅读
展开代码
java复制代码Map<Integer, String> map = new HashMap<>(); map.put(1, "One"); // map.put("Two", 2); // 编译错误,键必须是 Integer,值必须是 String

c. Set 接口

Set 接口及其实现类(如 HashSetTreeSet)使用泛型,确保集合中的元素类型一致。

plaintext
自动换行:关
放大阅读
展开代码
java复制代码Set<Double> set = new HashSet<>(); set.add(3.14); // set.add("Pi"); // 编译错误,不能添加非 Double 类型

d. Queue 接口

Queue 接口及其实现类(如 LinkedListPriorityQueue)使用泛型,指定队列中元素的类型。

plaintext
自动换行:关
放大阅读
展开代码
java复制代码Queue<Integer> queue = new LinkedList<>(); queue.add(1); // queue.add("String"); // 编译错误,不能添加非 Integer 类型

2. Comparator<T> 接口

Comparator 接口用于比较对象,泛型参数 T 确保类型一致。

plaintext
自动换行:关
放大阅读
展开代码
java复制代码Comparator<String> comparator = new Comparator<String>() { @Override public int compare(String s1, String s2) { return s1.length() - s2.length(); } }; List<String> strings = Arrays.asList("apple", "banana", "cherry"); Collections.sort(strings, comparator);

3. Optional<T>

Optional 是一个容器对象,用于表示可能存在或不存在的值,避免 NullPointerException

plaintext
自动换行:关
放大阅读
展开代码
java复制代码Optional<String> optionalString = Optional.of("Hello"); optionalString.ifPresent(System.out::println); // 输出 "Hello" Optional<Integer> optionalInteger = Optional.ofNullable(null); Integer value = optionalInteger.orElse(0); // 如果为空,返回默认值 0

4. Stream<T> API

Stream API 使用泛型,支持对集合的函数式操作。

plaintext
自动换行:关
放大阅读
展开代码
java复制代码List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); List<String> filteredNames = names.stream() .filter(name -> name.startsWith("A")) .collect(Collectors.toList());

5. Future<T>CompletableFuture<T>

在并发编程中,FutureCompletableFuture 使用泛型表示异步计算的结果类型。

plaintext
自动换行:关
放大阅读
展开代码
java复制代码ExecutorService executorService = Executors.newFixedThreadPool(2); Future<Integer> future = executorService.submit(() -> { // 执行耗时任务 return 42; }); CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello"); completableFuture.thenAccept(result -> System.out.println(result)); // 输出 "Hello"

6. Class<T>

Class<T> 使用泛型表示类的类型信息,常用于反射机制。

plaintext
自动换行:关
放大阅读
展开代码
java复制代码Class<String> stringClass = String.class; String str = stringClass.newInstance(); // 创建新的 String 实例

7. 函数式接口

Java 8 引入的函数式接口广泛使用泛型。

a. Supplier<T>

提供一个类型 T 的值。

plaintext
自动换行:关
放大阅读
展开代码
java复制代码Supplier<String> supplier = () -> "Hello"; String result = supplier.get(); // 返回 "Hello"

b. Consumer<T>

消费一个类型 T 的值。

plaintext
自动换行:关
放大阅读
展开代码
java复制代码Consumer<String> consumer = s -> System.out.println(s); consumer.accept("Hello"); // 输出 "Hello"

c. Function<T, R>

将类型 T 的值映射为类型 R 的值。

plaintext
自动换行:关
放大阅读
展开代码
java复制代码Function<String, Integer> function = s -> s.length(); Integer length = function.apply("Hello"); // 返回 5

五、总结

Java 中基本数据类型和引用数据类型在存储方式、默认值、操作方式等方面存在显著区别。由于泛型的类型擦除机制,泛型无法直接使用基本数据类型,但可以通过包装类和自动装箱/拆箱机制间接地在泛型中使用基本数据类型。 泛型上下限的使用可以提高代码的灵活性和类型安全性。在 Java 原生 API 中,泛型被广泛应用于集合框架、并发编程、函数式编程等方面,提高了代码的可读性和可维护性。

本文作者:hedeoer

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!