泛型允许创建具有类型参数的类、接口和方法,这在编译时提供了类型检查,并帮助避免ClassCastException。
关键特性与潜在问题:
new List<String>[10] — 编译错误。T obj = new T();if(obj instanceof List<String>) — 错误。? extends T — 协变(读取),? super T — 逆变(写入)。示例:
// 协变的读取方式 void printNumbers(List<? extends Number> numbers) { for (Number n : numbers) { System.out.println(n); } } // 逆变的写入方式 void addIntegers(List<? super Integer> list) { list.add(10); }
问题: "List<Object>和List<?>有什么区别?可以将任何对象放入List<?>吗?"
回答: 不,不能在List<?>中添加任何内容(除了null),因为编译器不知道具体的类型参数。而在List<Object>中可以添加任何对象。
示例:
List<?> list1 = new ArrayList<String>(); // list1.add("test"); // 编译错误! List<Object> list2 = new ArrayList<>(); list2.add("test"); // 正确
故事
开发团队试图基于参数化类型的数组
T[]实现缓存。由于类型擦除和无法创建泛型类型的数组,解决方案未按预期工作:得到了一个Object[]数组,导致在运行时进行类型转换时出现ClassCastException。
故事
在其中一个微服务中,开发者尝试实现一个使用List<?>作为参数的接收器,并试图修改集合。这导致了编译错误,并拖延了发布日期,因为需要根据PECS重构逻辑。
故事
在与外部系统的集成项目中,开发者犯了一个错误,通过未处理的原始类型覆盖了一种类型的集合:List list = new ArrayList<String>(),这导致ClassCastException,并在生产环境中尝试将元素转换为其他类型时服务崩溃。