? 是编译器推断的固定但未知类型占位符,禁止非null写入、读取返回object;object是真实顶层父类,允许任意写入但需手动强转,放弃泛型类型安全。

Java 中的 ? 和 Object 看似都能“装各种类型”,但语义、编译行为和安全机制完全不同。它们不是替代关系,而是两类完全不同的设计:一个是类型系统中的占位符,一个是真实存在的具体类。
❓ ? 是未知但确定的类型占位符
它不表示“任意类型”,而是表示“某个具体、固定但编译器不告诉你是什么”的类型。比如:
-
List> list = new ArrayList<string>();</string>→ 此时?就是String,只是你不能写死它 - 你不能调用
list.add("hi"),因为编译器无法验证字符串是否匹配那个“已定但未知”的类型 - 唯一允许的写入是
list.add(null),因为null可赋值给任何引用类型 -
list.get(0)返回Object,这是类型系统推理出的安全上界,不是强制转型
? Object 是真实的顶层父类
List<object></object> 明确声明容器元素类型就是 Object,这意味着:
- 可以自由添加
String、Integer、Boolean等任意对象 - 但取出后必须手动强转才能当原类型使用,否则运行时可能抛
ClassCastException - 它放弃泛型的类型约束能力,无法参与
? extends Number或? super Integer这类边界控制 - 它不是泛型的“退化方案”,而是一种主动放弃类型安全的选择
? 写操作限制差异最直观
这是区分二者最实用的判断点:
-
List>:禁止所有非null写入 —— 安全由编译器保障 -
List<object></object>:允许任意写入 —— 安全责任完全交给开发者
? 使用场景根本不同
选哪个,取决于你要解决的问题:
- 用
List>:写工具方法,只读集合,兼容List<string></string>、List<date></date>等多种实参(如void print(List> list)) - 用
List<object></object>:极少数需混存不同类型且能自行管控转型逻辑的场景(应尽量避免) - 永远不要用
List<object></object>替代List>来“绕过编译错误”——那是把问题从编译期推迟到运行期
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











