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