2016-04-26 3 views
1

Скажем, у меня есть следующий пример приложения, я использую Java 8.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); 
    } 
} 

Когда я запускаю это я получаю следующее сообщение об ошибке:

Error:(12, 35) java: incompatible types: java.util.List<GrantedAuthority> cannot be converted to java.util.Collection<? extends capture#1 of ? extends GrantedAuthority>

Моя проблема в том, как я могу передать коллекцию GrantedAuthoritySubClass объектов в коллекции, возвращаемой u.getAuthorities(). Я не могу понять это, и есть много ошибок компиляции, связанных с различными способами, которые я пробовал.

+3

, что смысл иметь подстановочные в вашем примере? посмотрите http://stackoverflow.com/questions/2745265/is-listdog-a-subclass-of-listanimal-why-arent-javas-generics-implicitly-p?rq=1 – JEY

+0

@JEY Это о весне -security 4.0.3 и UserDetails весом, подобным выше. Я просто хотел сделать вопрос проще, не упоминая об этом. – nilan59

+0

just return Collection Я не вижу смысла иметь подстановочный знак. – JEY

ответ

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

В соответствии с правилом PECS ваша коллекция authorities представляет собой элемент producer (так как он использует расширения). Это означает, что сбор может только «производить» или «выводить» объекты GrantedAuthority или его подклассы. Это также означает, что вы не можете поместить что-либо в коллекцию, так как вы не знаете тип коллекции, действительный тип.

Если вы использовали super, вы можете поместить туда свои объекты (но вы не смогли их вытащить), но я подозреваю, что подстановочный шаблон совершенно не нужен.

1

Вы пытаетесь быть слишком точным, используя подстановочные знаки (и получить себе в дженериков-ад таким образом.)

В основном, стараются избегать групповых символов и использовать природное наследство, когда это возможно. В вашем примере измените UserDetails следующим образом:

public class UserDetails { 
    Collection<GrantedAuthority> authorities; 

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

... и все будет хорошо. В частности, вы можете добавить экземпляр GrantedAuthoritySubClass, поскольку естественное наследование начинается.

2

Вы не можете скомпилировать причину, по которой вы не знаете, какую коллекцию вы получаете.

Вы должны изменить подпись

Collection<? super GrantedAuthority> getAuthorities() 

Это иллюстрирует проблему (с) Andrey Tyukin: enter image description here

Смежные вопросы