具有上限的Java泛型

时间:2016-04-26 11:16:33

标签: java generics spring-security wildcard

假设我有以下示例应用程序,我使用的是java。

我有以下具有子类的类:

public class GrantedAuthority { }
public class GrantedAuthoritySubClass extends GrantedAuthority { }

下课是棘手的部分发生的地方:

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);
    }
}

当我运行时,我收到以下错误:

  

错误:(12,35)java:不兼容的类型:java.util.List<GrantedAuthority>无法转换为java.util.Collection<? extends capture#1 of ? extends GrantedAuthority>

我的问题是,我如何将GrantedAuthoritySubClass个对象的集合传递给u.getAuthorities()返回的集合。我无法解决这个问题,而且我尝试过的各种方法都存在很多编译错误。

4 个答案:

答案 0 :(得分:2)

根据PECS规则,您的authorities集合是producer元素(因为它使用了扩展)。这意味着该集合只能生成&#34;或&#34;输出&#34; GrantedAuthority个对象或其子类。这也意味着您无法将任何内容放入集合中,因为您不知道集合的实际类型。

如果您使用super,您可以将对象放在那里(但是你无法将它们取出),但我怀疑通配符是完全没必要的。

答案 1 :(得分:2)

你无法编译因为你不知道你得到什么样的收藏品。

您需要将签名更改为

Collection<? super GrantedAuthority> getAuthorities()

这说明问题(c)Andrey Tyukinenter image description here

答案 2 :(得分:1)

你试图使用通配符过于精确(并让自己陷入泛型 - 地狱般的地狱。)

基本上,尽可能避免使用通配符并使用自然继承。在您的示例中,按如下所示更改UserDetails:

public class UserDetails {
    Collection<GrantedAuthority> authorities;

    public Collection<GrantedAuthority> getAuthorities(){
        return authorities;
    }
}

......一切都会好的。特别是,您可以添加GrantedAuthoritySubClass的实例,因为自然继承会启动。

答案 3 :(得分:1)

因为UserDetails是弹簧安全性的接口,所以您无法更改方法定义。您无法使用自己的方法添加GrantedAuthority。但是,在实现中,您可以覆盖getAuthorities以返回与接口定义匹配的集合:

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());