为什么这个 class 不被视为超类型作为参数?
Why is this class not considered a supertype as a parameter?
给出以下示例,为什么我可以将 return 类型 List<? extends IConfigUser>
覆盖为 getUserList()
中的 List<ConfigUser>
,但不能对 setUserList()
?
在这种情况下,ConfigUser
不被视为 IConfigUser
的超类型吗?
public class Test {
public interface IConfigUser {
}
public interface IConfig {
public List<? extends IConfigUser> getUserList();
public void setUserList(List<? extends IConfigUser> list);
}
public class ConfigUser implements IConfigUser {
}
// The type Test.Config must implement the inherited abstract method
// Test.IConfig.setUserList(List<? extends Test.IConfigUser>)
public class Config implements IConfig {
@Override
public List<ConfigUser> getUserList() {
return null;
}
// The method setUserList(List<ConfigUser> list) of type Test.Config
// must override or implement a supertype method
@Override
public void setUserList(List<ConfigUser> list)
{
}
}
}
您可以通过向 IConfig
添加泛型类型参数来实现您的目标:
public class Test {
public interface IConfigUser {
}
public interface IConfig<T extends IConfigUser> {
public List<T> getUserList();
public void setUserList(List<T> list);
}
public class ConfigUser implements IConfigUser {
}
public class Config implements IConfig<ConfigUser> {
@Override
public List<ConfigUser> getUserList() {
return null;
}
@Override
public void setUserList(List<ConfigUser> list)
{
}
}
}
您可以 return 覆盖中的更具体类型,但不能要求您 接受更具体的类型。摆脱泛型,你可以用方法 returning String
覆盖方法 returning Object
,但你不能覆盖接受 [=] 的方法11=] 参数和接受 String
参数的方法。
所有这一切都是为了让来电者兼容。考虑:
IConfig config = new Config();
List<SomeOtherConfigUser> list = new ArrayList<SomeOtherConfigUser>();
list.add(new SomeOtherConfigUser());
config.setUserList(list);
糟糕 - 您的 Config.setUserList
期望每个元素都是 ConfigUser
,而不是 SomeOtherConfigUser
。
由于协方差,您可以 return ("specialize") getUserList()
的 return 类型,即如果您在 IConfig
引用上调用该方法你只知道你会得到一个 List<? extends IConfigUser>
和一个 List<ConfigUser>
是一个 List<? extends IConfigUser>
所以满足要求。
如果您在 Config
参考上调用它,则信息会更具体,但仍满足基本要求。
使用 setUserList(...)
情况不同:它允许您传递 任何 "subclass" of List<? extends IConfigUser>
which can be a List<ConfigUser>
但它也可以是其他东西,例如List<SomeConfigUser>
.
顺便说一句,因为您不知道 setUserList(List<ConfigUser> list)
中 list
的具体通用参数,编译器也只允许您从该列表中读取,永远不会添加到它 - 同样原因如上:你不知道你得到了什么,也不知道是否允许添加 ConfigUser
因为列表只能允许添加 SomeConfigUser
个实例。
给出以下示例,为什么我可以将 return 类型 List<? extends IConfigUser>
覆盖为 getUserList()
中的 List<ConfigUser>
,但不能对 setUserList()
?
在这种情况下,ConfigUser
不被视为 IConfigUser
的超类型吗?
public class Test {
public interface IConfigUser {
}
public interface IConfig {
public List<? extends IConfigUser> getUserList();
public void setUserList(List<? extends IConfigUser> list);
}
public class ConfigUser implements IConfigUser {
}
// The type Test.Config must implement the inherited abstract method
// Test.IConfig.setUserList(List<? extends Test.IConfigUser>)
public class Config implements IConfig {
@Override
public List<ConfigUser> getUserList() {
return null;
}
// The method setUserList(List<ConfigUser> list) of type Test.Config
// must override or implement a supertype method
@Override
public void setUserList(List<ConfigUser> list)
{
}
}
}
您可以通过向 IConfig
添加泛型类型参数来实现您的目标:
public class Test {
public interface IConfigUser {
}
public interface IConfig<T extends IConfigUser> {
public List<T> getUserList();
public void setUserList(List<T> list);
}
public class ConfigUser implements IConfigUser {
}
public class Config implements IConfig<ConfigUser> {
@Override
public List<ConfigUser> getUserList() {
return null;
}
@Override
public void setUserList(List<ConfigUser> list)
{
}
}
}
您可以 return 覆盖中的更具体类型,但不能要求您 接受更具体的类型。摆脱泛型,你可以用方法 returning String
覆盖方法 returning Object
,但你不能覆盖接受 [=] 的方法11=] 参数和接受 String
参数的方法。
所有这一切都是为了让来电者兼容。考虑:
IConfig config = new Config();
List<SomeOtherConfigUser> list = new ArrayList<SomeOtherConfigUser>();
list.add(new SomeOtherConfigUser());
config.setUserList(list);
糟糕 - 您的 Config.setUserList
期望每个元素都是 ConfigUser
,而不是 SomeOtherConfigUser
。
由于协方差,您可以 return ("specialize") getUserList()
的 return 类型,即如果您在 IConfig
引用上调用该方法你只知道你会得到一个 List<? extends IConfigUser>
和一个 List<ConfigUser>
是一个 List<? extends IConfigUser>
所以满足要求。
如果您在 Config
参考上调用它,则信息会更具体,但仍满足基本要求。
使用 setUserList(...)
情况不同:它允许您传递 任何 "subclass" of List<? extends IConfigUser>
which can be a List<ConfigUser>
但它也可以是其他东西,例如List<SomeConfigUser>
.
顺便说一句,因为您不知道 setUserList(List<ConfigUser> list)
中 list
的具体通用参数,编译器也只允许您从该列表中读取,永远不会添加到它 - 同样原因如上:你不知道你得到了什么,也不知道是否允许添加 ConfigUser
因为列表只能允许添加 SomeConfigUser
个实例。