为什么Java不允许我添加子类实体?



我在Java项目中遇到了一个问题。产生错误的代码如下:

HashMap<String, LinkedList<? extends User>> signedUpUsers =
new HashMap<>(Map.of(
"Administrator", new LinkedList<Administrator>(),
"Employee", new LinkedList<Employee>(),
"Customer", new LinkedList<Customer>()));
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));
}
}

当我尝试在hashmap的每个列表中添加新元素时,它给了我一个错误,当我创建实例时,intellij告诉我:
所需类型:捕获?扩展用户
提供:客户(或雇员或管理员)

但是为什么,如果客户员工,管理员和User
我应该改变什么?我的意图是拥有一个包含所有注册用户的HashMap(我将它们保存在.properties文件中,该文件被更正为红色,因为我看到了这一点),其中键是用户的角色(管理员、雇员和客户),每个键的值是具有该角色的每个用户的LinkedList。我还尝试使用super代替扩展,但是在这种情况下,我解决了这个错误,但是在使用Map.of()创建hashmap时出现了一个新的错误(因为Administrator, Customer和Employee不是User的超类)。如果我用3个角色对象直接声明了3个不同的列表,那么代码就可以工作,但是我想要hashmap,因为我想返回整个注册用户除以他们的角色。
谢谢大家,我希望我解释得很清楚。

编译器错误的原因已经涵盖在@Thomas的评论中:对于编译器,signedUpUsers.get("Administrator")LinkedList<? extends User>,不知道在"Administrator"键下,您存储了LinkedList<Administrator>(而不是例如LinkedList<Employee>),因此编译器不允许添加Administrator

您的signedUpUsers变量显示了一些明显的泛型过度工程。你声明

HashMap<String, LinkedList<? extends User>> signedUpUsers =
new HashMap<>(Map.of(
"Administrator", new LinkedList<Administrator>(),
"Employee", new LinkedList<Employee>(),
"Customer", new LinkedList<Customer>()));

我建议改成

HashMap<String, LinkedList<User>> signedUpUsers =
new HashMap<>(Map.of(
"Administrator", new LinkedList<User>(),
"Employee", new LinkedList<User>(),
"Customer", new LinkedList<User>()));

你可能会问:"但是现在我没有类型安全,我只能在"Administrator"键下存储Administrator实例。"但是这种类型安全在第一个版本中也是不可能的(在运行时,LinkedList<Administrator>只是一个LinkedList,并且会很高兴地接受任何Object,而在编译时LinkedList<? extends User>将不允许添加任何内容)。

如果你想要列表的类型安全,扔掉Map方法,创建一个类UserList:

public class UserList {
private List<Administrator> administrators;
private List<Employee> employees;
private List<Customer> customers;
// add constructor, getters, adders etc. here
}

这将很容易地提供所需的类型安全。