为什么Java不允许向声明为<? extends User>的集合添加子类实例?
错误原因
你遇到的是Java泛型通配符的PECS规则限制:
? extends T属于生产者通配符,只允许读取操作,不允许写入操作。该类型修饰的集合除了null之外,不能添加任何元素,因为编译器无法确定这个通配符实际匹配的是User的哪个具体子类,无法校验你添加的元素是否符合列表的实际类型要求,哪怕你添加的确实是User的子类也会被直接拒绝。- 你尝试换成
? super User属于消费者通配符,允许写入User的子类,但此时你的LinkedList<Administrator>这类列表不符合类型要求,因为Administrator是User的子类而非父类,所以初始化阶段就会报错。
解决方案
方案1:简化泛型声明(最推荐)
你不需要使用通配符,直接把Map的值类型声明为LinkedList<User>即可,三个子类都是User的实现,既可以正常初始化,也可以正常写入,完全满足你按角色分组返回的需求:
HashMap<String, LinkedList<User>> signedUpUsers = new HashMap<>(); // 手动初始化各角色的用户列表 signedUpUsers.put("Administrator", new LinkedList<>()); signedUpUsers.put("Employee", new LinkedList<>()); signedUpUsers.put("Customer", new LinkedList<>()); for (String userName : userNameList) { userPropertyValue = usersProperties.getProperty(userName).split(","); String password = userPropertyValue[0].replaceAll("\\s", ""); String role = userPropertyValue[1].replaceAll("\\s", ""); if (role.equals("Administrator")) { signedUpUsers.get("Administrator").add(new Administrator(userName, password)); } else if (role.equals("Customer")) { signedUpUsers.get("Customer").add(new Customer(userName, password)); } else { signedUpUsers.get("Employee").add(new Employee(userName, password)); } }
后续遍历各角色列表时,元素默认是User类型,如果你需要调用子类特有方法,根据角色做对应类型转换即可。
方案2:严格限制每个列表仅存对应角色用户
如果你必须保留LinkedList<? extends User>的声明,严格保证每个角色列表只能存储对应类型的用户,可以加一个带类型校验的包装方法绕过编译器检查:
@SuppressWarnings("unchecked") private <T extends User> void addToRoleList(LinkedList<? extends User> list, T user, Class<T> roleType) { LinkedList<T> typedList = (LinkedList<T>) list; typedList.add(user); }
调用时对应修改写入逻辑即可:
if (role.equals("Administrator")) { addToRoleList(signedUpUsers.get("Administrator"), new Administrator(userName, password), Administrator.class); } else if (role.equals("Customer")) { addToRoleList(signedUpUsers.get("Customer"), new Customer(userName, password), Customer.class); } else { addToRoleList(signedUpUsers.get("Employee"), new Employee(userName, password), Employee.class); }
内容的提问来源于stack exchange,提问作者Gius
相关产品推荐
相关产品推荐

