Приведение объектов в список с использованием дженериков - PullRequest
0 голосов
/ 04 марта 2012

У меня проблемы с использованием шаблонов и списков с интерфейсами.

У меня есть интерфейс Comment, который расширен классом CommentNews.

Комментарий:

public interface Comment {

    public static final String COMMENT_NEWS_PATH = "/comment/news";
    public static final String COMMENT_EVENT_PATH = "/comment/event";
    public static final String COMMENT_GROUP_PATH = "/comment/group";

    public User getUser();

    public void setUser(User user);

    public String getText();

    public void setText(String text);

    public Date getModified();

    public void setModified(Date modified);

    public void setCommentsList(List<?> commentsList);

    public <T extends Comment> List<T> getCommentsList();
}

CommentNews:

public class CommentNews implements Comment {

    private Integer id;
    private User user;
    private News news;
    private String text;
    private List<CommentNews> commentsList;

    public CommentNews() {}

    // Methods snipped for brevity

    public List<CommentNews> getCommentsList() {
        return commentsList;

    }

    public void setCommentsList(List<?> commentsList) {
        this.commentsList = (List<CommentNews>) commentsList;

    }
}

Проблема заключается в методе setCommentsList, в котором приведение класса фактически не приводит к приведению каждого объекта в списке. Я не могу изменить сигнатуру методов, так как это приведет к конфликту имен с интерфейсом.

Есть ли способ сделать кастинг с использованием дженериков? Я хотел бы воздержаться от итерации по списку и приведения каждого объекта вручную.

UPDATE : Если я изменю интерфейс комментария на Если я изменю интерфейс на

public <T extends Comment>void setCommentsList(List<T> commentsList);

и класс CommentNews до

public void setCommentsList(List<CommentNews> commentsList) {
        this.commentsList = commentsList;   
    }

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

1 Ответ

3 голосов
/ 04 марта 2012

По сути, ваш интерфейс не является типобезопасным.Ничто не мешает кому-то сделать что-то вроде этого:

Comment comment = ...; // Wherever
List<Integer> numbers = new List<Integer>();
numbers.add(10);
comment.setCommentsList(numbers);

Вы действительно хотите это разрешить?

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

РЕДАКТИРОВАТЬ: Если вы хотите, чтобы любой вид комментария содержал только вложенные комментарии того же самогодобро, вы, вероятно, захотите сделать свой интерфейс Comment универсальным, например:

public interface Comment<T extends Comment<T>> {

    // Note: no public modifier; it's allowed by the spec but discouraged
    void setCommentList(List<T> comments);
    List<T> getCommentList();
}

(Вы все еще можете использовать символы подстановки, если хотите, но, возможно, вам это и не нужно, и это усложнит ситуацию.)

...