Java泛型中无界通配符?与Object作为类型参数有何区别
?和Object的核心区别 这两个方法签名存在本质差异,核心原因是Java泛型的不变性设计,以及无界通配符?和具体类型Object的定位完全不同:
核心差异对比
参数接收范围不同
Java泛型不支持协变,Collection<Object>和Collection<String>没有继承关系,哪怕String是Object的子类。所以第二种方法的入参Collection<Object>只能接收泛型类型明确为Object的集合,比如new ArrayList<Object>(),如果传入ArrayList<String>、ArrayList<Integer>这类其他泛型类型的集合会直接编译报错。
而Collection<?>中的?是无界通配符,代表任意未知的泛型类型,它可以接收所有泛型类型的集合,不管是Collection<String>、Collection<Integer>还是Collection<Object>都能正常传入。集合操作权限不同
拿到Collection<Object>实例时,你可以往里面添加任意Object类型的元素,比如collection.add("测试文本")、collection.add(123)都是合法操作,读取元素默认得到的也是Object类型,不需要额外强转。
但拿到Collection<?>实例时,你除了null之外不能往里面添加任何元素——因为编译器不知道这个集合实际的泛型类型是什么,随便添加元素会破坏类型安全。读取元素时也只能赋值给Object类型的变量,要使用具体类型必须手动强转。返回值含义不同
第一个方法返回的Something<?>代表返回实例的泛型类型是未知的,你拿到返回值后同样无法对其泛型相关的成员做写入操作,只能做基础的读取操作。
第二个方法返回的Something<Object>的泛型类型是明确的,你可以正常对其泛型成员做读写操作,只要符合Object类型的约束即可。
代码示例验证
// 测试第二种方法:入参为Collection<Object> Collection<String> strList = new ArrayList<>(); doIt(strList); // 编译直接报错,Collection<String>不属于Collection<Object>的子类 // 测试第一种方法:入参为Collection<?> Collection<String> strList = new ArrayList<>(); doIt(strList); // 编译通过,无界通配符支持接收任意泛型类型的集合
内容的提问来源于stack exchange,提问作者Antonio Dragos

