假设我有两个嵌套的集合,类似于多个OneToMany关系的集合。例如,一个Post有多个Comments,一个Comment可以有多个Tags,集合。因此,让我们仅限于定义为POJO的Post和Comments关系:
@Getter
@Setter
private static class Post {
private String title;
private Set < Comment > comments = new HashSet < > ();
public Post(String title) {
this.title = title;
}
public Post addComment(Comment comment) {
getComments().add(comment);
return this;
}
}
@Getter
@Setter
private static class Comment {
private String text;
public Comment(String text) {
this.text = text;
}
}让我们创建两个带评论的帖子:
Post post1 = new Post("post-1").
addComment(new Comment("com-1")).
addComment(new Comment("com-2"));
Post post2 = new Post("post-2").
addComment(new Comment("com-21")).
addComment(new Comment("com-22")).
addComment(new Comment("com-1")).
addComment(new Comment("com-2"));问题是如何找到具有相同text值的上述帖子的评论集合?我尝试使用retainAll,但它不能解决这个问题:
Set <Comment> post1Comments = new HashSet(post1.getComments());
System.out.println("post1 comments before: " + post1Comments);
post1Comments.retainAll(post2.getComments());
System.out.println("post1 comments after: " + post1Comments);有什么想法吗?
发布于 2021-03-12 17:51:24
Set使用equals和hashcode方法来比较对象。如果您没有在Comment类中覆盖它们,那么它将拥有从java.lang.Object类继承的那些方法。该实现使用对象标识,其中具有相同内容的两个对象将被识别为不同的实体。要解决此问题,必须正确覆盖Comment类中的equals和hashcode方法。
发布于 2021-03-12 17:56:42
只需在注释类中添加equals和hashCode方法即可。像这样的东西
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Comment comment = (Comment) o;
return Objects.equals(text, comment.text);
}
@Override
public int hashCode() {
return Objects.hash(text);
}发布于 2021-03-12 18:56:12
retainAll()是计算两个集合之间交集的标准方法。
但是,任何需要比较元素的等价性或排序的集合方法都依赖于equals()和hashCode()。
如果不提供这些方法的实现,Object中的默认设置只在两个对象是完全相同的实例时才会认为它们是等价的,并且每次执行new Comment()时都会得到一个物理上新的实例,而不管注释的文本是否与其他Comment对象相同。
为了做您想做的事情,您应该使用this.text作为委托来重写Comment等价方法。
一般来说,这很棘手,因为它迫使你采用唯一的等价标准,这并不总是可行的,例如,如果你只想列出在一篇文章上发表的独特评论,上面的方法就可以了,如果你想知道相同的事情重复了多少次,你需要一些其他的等价标准(例如,添加作者或时间戳)。
除了以上两种情况,还有其他选择。
一种是手动计算,使用streams作为suggested by Hulya是一个很好的方法(一旦你了解了streams),因为它很快,你可以很容易地利用并行性(尽管在这种情况下,你需要Collections.synchronizedSet(),也许所需的同步量不会让它这么快)。
另一种方法是实现委托,即new CommentDelegate( originalComment )),每个委托将提供自己风格的equals()和hashCode()。它的变体是可能的,例如,你可以为每个评论创建一个CustomCommentKey,并填充一个HashMap来创建一个自定义的评论索引,地图总是包含你添加到其中的任何评论集的交集,因为它是按键的单一性分解的。
另一个非常简洁的选择是使用集合实现,它是标准Java语言中可用的集合实现的替代品,在标准Java语言中,新的实现接受具有equals ( o1, o2 )和hashCode ( o )等方法的HashingStrategy接口。这就像现有的Comparator一样,允许将给定类型的对象与自定义条件进行比较,自定义条件与原始类型(即来自Comment)解开,并允许组合。虽然我从来没有尝试过,但我要感谢Eclipse has a library。
https://stackoverflow.com/questions/66597397
复制相似问题