Java 具有上限的泛型
Java generics with upper bound
假设我有以下示例应用程序,我正在使用 java 8.
我有以下 class 有 child class:
public class GrantedAuthority { }
public class GrantedAuthoritySubClass extends GrantedAuthority { }
接下来的 class 是棘手的部分:
public class UserDetails {
Collection<? extends GrantedAuthority> authorities;
public Collection<? extends GrantedAuthority> getAuthorities(){
return authorities;
}
}
我的主要方法:
public class Main {
public static void main(String[] args) {
UserDetails u = new UserDetails();
List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
list.add(new GrantedAuthoritySubClass());
u.getAuthorities().addAll(list);
}
}
当我 运行 这样做时,我收到以下错误:
Error:(12, 35) java: incompatible types: java.util.List<GrantedAuthority>
cannot be converted to java.util.Collection<? extends capture#1 of ? extends GrantedAuthority>
我的问题是,如何将 GrantedAuthoritySubClass
Objects 的集合传递给 u.getAuthorities()
返回的集合。我想不通,而且我尝试过的各种方法都存在很多编译错误。
根据 PECS 规则,您的 authorities
集合是 producer
个元素(因为它使用扩展)。这意味着集合只能 "produce" 或 "output" GrantedAuthority
对象或其子类。这也意味着您不能将任何东西放入集合中,因为您不知道集合的 实际 类型。
如果你使用 super
你可以把你的对象放在那里(但你不能把它们拿出来),但我怀疑通配符是完全没有必要的。
您尝试使用通配符过于精确(这样会让自己陷入泛型地狱。)
基本上,尽量避免通配符并尽可能使用自然继承。在您的示例中,按如下方式更改您的 UserDetails:
public class UserDetails {
Collection<GrantedAuthority> authorities;
public Collection<GrantedAuthority> getAuthorities(){
return authorities;
}
}
...一切都会好起来的。特别是,您可以添加一个 GrantedAuthoritySubClass 的实例,因为自然继承开始了。
因为UserDetails is an interface for spring security you can't change the method definition. You can't add GrantedAuthority用你的方法。但是在实现中,您可以将 getAuthorities 覆盖为 return 与接口定义匹配的集合:
public class UserDetailsImpl implements UserDetails {
private Collection<GrantedAuthority> authorities = new ArrayList<>();
@Override
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}
}
现在您可以像这样使用它了:
UserDetailsImpl u = new UserDetailsImpl();
u.getAuthorities().add(new GrantedAuthority());
也可以像这样使用您自己的 GrantedAuthority 类型:
public class MyGrantedAuthority extends GrantedAuthority{
}
public class UserDetailsImpl implements UserDetails {
private Collection<MyGrantedAuthority> authorities = new ArrayList<>();
@Override
public Collection<MyGrantedAuthority> getAuthorities() {
return authorities;
}
}
UserDetailsImpl u = new UserDetailsImpl();
u.getAuthorities().add(new MyGrantedAuthority());
你无法编译,因为你不知道你得到的是什么类型的集合。
您需要将签名更改为
Collection<? super GrantedAuthority> getAuthorities()
这说明了问题(c)Andrey Tyukin:
假设我有以下示例应用程序,我正在使用 java 8.
我有以下 class 有 child class:
public class GrantedAuthority { }
public class GrantedAuthoritySubClass extends GrantedAuthority { }
接下来的 class 是棘手的部分:
public class UserDetails {
Collection<? extends GrantedAuthority> authorities;
public Collection<? extends GrantedAuthority> getAuthorities(){
return authorities;
}
}
我的主要方法:
public class Main {
public static void main(String[] args) {
UserDetails u = new UserDetails();
List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
list.add(new GrantedAuthoritySubClass());
u.getAuthorities().addAll(list);
}
}
当我 运行 这样做时,我收到以下错误:
Error:(12, 35) java: incompatible types:
java.util.List<GrantedAuthority>
cannot be converted tojava.util.Collection<? extends capture#1 of ? extends GrantedAuthority>
我的问题是,如何将 GrantedAuthoritySubClass
Objects 的集合传递给 u.getAuthorities()
返回的集合。我想不通,而且我尝试过的各种方法都存在很多编译错误。
根据 PECS 规则,您的 authorities
集合是 producer
个元素(因为它使用扩展)。这意味着集合只能 "produce" 或 "output" GrantedAuthority
对象或其子类。这也意味着您不能将任何东西放入集合中,因为您不知道集合的 实际 类型。
如果你使用 super
你可以把你的对象放在那里(但你不能把它们拿出来),但我怀疑通配符是完全没有必要的。
您尝试使用通配符过于精确(这样会让自己陷入泛型地狱。)
基本上,尽量避免通配符并尽可能使用自然继承。在您的示例中,按如下方式更改您的 UserDetails:
public class UserDetails {
Collection<GrantedAuthority> authorities;
public Collection<GrantedAuthority> getAuthorities(){
return authorities;
}
}
...一切都会好起来的。特别是,您可以添加一个 GrantedAuthoritySubClass 的实例,因为自然继承开始了。
因为UserDetails is an interface for spring security you can't change the method definition. You can't add GrantedAuthority用你的方法。但是在实现中,您可以将 getAuthorities 覆盖为 return 与接口定义匹配的集合:
public class UserDetailsImpl implements UserDetails {
private Collection<GrantedAuthority> authorities = new ArrayList<>();
@Override
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}
}
现在您可以像这样使用它了:
UserDetailsImpl u = new UserDetailsImpl();
u.getAuthorities().add(new GrantedAuthority());
也可以像这样使用您自己的 GrantedAuthority 类型:
public class MyGrantedAuthority extends GrantedAuthority{
}
public class UserDetailsImpl implements UserDetails {
private Collection<MyGrantedAuthority> authorities = new ArrayList<>();
@Override
public Collection<MyGrantedAuthority> getAuthorities() {
return authorities;
}
}
UserDetailsImpl u = new UserDetailsImpl();
u.getAuthorities().add(new MyGrantedAuthority());
你无法编译,因为你不知道你得到的是什么类型的集合。
您需要将签名更改为
Collection<? super GrantedAuthority> getAuthorities()
这说明了问题(c)Andrey Tyukin: