简体   繁体   中英

Casting objects in list using generics

I'm having problems using generics and lists with interfaces.

I have an interface Comment, which is extended by the class CommentNews.

Comment:

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;

    }
}

The problem is with the setCommentsList method, the class cast doesn't actually cast each object in the list. I can't change the methods signature as that will generate a name clash with the interface.

Is there a way to make the casting using generics? I would like to refrain from iterating through the list and casting each object manually.

UPDATE : If I change the Comment interface to If I change the interface to

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

and CommentNews class to

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

it should be typesafe, but this results in a name clash between the interface and class.

Fundamentally, your interface isn't type-safe. There's nothing to stop someone from doing something like this:

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

Do you really want to allow that?

You could have a list wrapper which performs the cast whenever it's accessed (rather than up-front) but it would be better to change the interface.

EDIT: If you want any kind of comment to only hold sub-comments of the same kind, you probably want to make your Comment interface generic, like this:

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

(You could still use wildcards if you wanted to, but you may well not need to, and it will complicate things.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM