类型擦除示例:为什么 ArrayList<Integer> 与 ArrayList<Float> 相等

副标题 / 摘要 Java 泛型在运行时会被擦除,导致不同类型参数的 List 拥有相同 Class。本文解释原因与影响。 目标读者 使用 Java 泛型的开发者 想理解类型系统限制的人 进行 API 设计的工程师 背景 / 动机 Java 泛型是编译期特性。 在运行时,类型参数会被擦除,这会影响反射与类型判断。 核心概念 类型擦除:泛型信息在运行时消失 编译期检查:类型安全主要在编译期保证 运行时类型:只剩原始类型 实践指南 / 步骤 理解泛型只在编译期起作用 避免依赖运行时泛型信息 用显式 Class 参数传递类型 在反射场景保持谨慎 可运行示例 import java.util.ArrayList; public class ErasureDemo { public static void main(String[] args) { ArrayList<Integer> li = new ArrayList<>(); ArrayList<Float> lf = new ArrayList<>(); System.out.println(li.getClass() == lf.getClass()); // true } } 解释与原理 泛型类型参数在编译后被擦除为原始类型(如 ArrayList)。 因此运行时类对象相同。 常见问题与注意事项 这会影响类型安全吗? 编译期仍保证类型安全,但运行时反射可能不安全。 为什么 Java 设计成这样? 为了兼容旧版本与字节码格式。 ...

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]

泛型协变与逆变:为什么 List<Cat> 不是 List<Animal>

副标题 / 摘要 很多人困惑为什么 List 不能当作 List。本文用类型安全的角度解释协变与逆变。 目标读者 学习泛型与类型系统的开发者 需要写类型安全 API 的工程师 做语言与框架设计的人 背景 / 动机 如果泛型随意协变,会引发类型不安全。 理解协变/逆变能帮助你正确设计接口与集合使用方式。 核心概念 协变:子类型关系在泛型中保留 逆变:子类型关系方向相反 不变:泛型类型不随子类型变化 实践指南 / 步骤 只读集合可用协变 只写集合可用逆变 读写同时存在时保持不变 用通配符或泛型参数表达意图 可运行示例 import java.util.List; class Animal {} class Cat extends Animal {} public class VarianceDemo { public static void main(String[] args) { List<Cat> cats = List.of(new Cat()); List<? extends Animal> animals = cats; // 协变:只读 Animal a = animals.get(0); System.out.println(a.getClass().getSimpleName()); } } 解释与原理 如果允许 List 当作 List,就可能把 Dog 放进去,破坏类型安全。 因此多数语言让泛型默认不变,需要明确声明协变/逆变。 ...

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]

泛型有什么用:复用、安全与表达力

副标题 / 摘要 泛型让代码在保持类型安全的同时实现复用。本文解释其价值与落地方式。 目标读者 想理解类型系统的开发者 需要写可复用组件的工程师 学习语言设计的同学 背景 / 动机 没有泛型时,复用通常依赖 Object 或手工复制,容易引入类型错误。 泛型提供了编译期类型检查和更高的表达力。 核心概念 类型参数:用类型占位符表达通用逻辑 类型安全:编译期保证类型正确 复用:同一逻辑适配多种类型 实践指南 / 步骤 识别重复逻辑 把类型差异抽成参数 添加约束(如接口) 保持 API 简洁 可运行示例 package main import "fmt" type Stack[T any] struct { data []T } func (s *Stack[T]) Push(v T) { s.data = append(s.data, v) } func (s *Stack[T]) Pop() T { v := s.data[len(s.data)-1] s.data = s.data[:len(s.data)-1] return v } func main() { s := Stack[int]{} s.Push(1) fmt.Println(s.Pop()) } 解释与原理 泛型让编译器在编译期发现类型错误,避免运行期崩溃。 同时避免重复代码,提升维护性。 常见问题与注意事项 泛型会影响性能吗? 取决于语言实现,通常影响可控。 什么时候不该用泛型? 当逻辑过于简单或类型差异极少。 ...

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]