英文:
How Set<List<Integer>> is working conceptually
问题
This Java program uses a HashSet
to store lists of integers and then checks if certain lists are present in the set. The key concept behind this is how HashSet
internally uses the equals
and hashCode
methods to compare and store elements.
When you add a list (e.g., l1
) to the HashSet
, it computes the hash code of the list and checks if there's already an element with the same hash code. If there's no element with the same hash code, it adds the list to the set.
When you later check for containment using contains
, it first calculates the hash code of the list you're checking (e.g., l2
or l3
). Then, it looks for an element with the same hash code. If it finds one, it uses the equals
method to perform a more detailed comparison to ensure that the list you're checking is indeed equal to the one in the set.
In this case, l2
is considered equal to l1
because they have the same elements in the same order. So, l2
is found in the set, and the program prints "l2 is already present."
However, l3
has the same elements but in a different order compared to l1
and l2
. Since the order matters, l3
is not considered equal to l1
, and it's not found in the set. Hence, the program prints "l3 is absent."
The key takeaway is that HashSet
uses the hashCode
to narrow down potential matches quickly and then uses the equals
method for detailed equality checks. Order matters in this case, so lists with the same elements but different orders are treated as distinct.
英文:
I wrote a program as below:
public static void main(String[] args) {
Set<List<Integer>> s = new HashSet<>();
List<Integer> l1 = new ArrayList<>(List.of(1,2,3));
List<Integer> l2 = new ArrayList<>(List.of(1,2,3));
List<Integer> l3 = new ArrayList<>(List.of(3,2,1));
s.add(l1);
if(s.contains(l2)) {
System.out.println("l2 is already present");
}
if(s.contains(l3)) {
System.out.println("l3 is present");
} else {
System.out.println("l3 is absent");
}
}
Here is the output:
l2 is already present
l3 is absent
I have a general idea of equals
and hashcode
in Java and rough idea of Object
type, etc.
Can someone explain conceptually how this thing able to compare internally a list of integers and find if it is already present? Notice that it works only if the order of elements in the list is same.
答案1
得分: 4
HashSet
依赖于元素类型(在您的情况下为 List
)的 equals
和 hashCode
方法。List
类型的这些方法的文档如下:
> equals
- 将指定的对象与此列表进行比较以确定相等性。仅当指定的对象也是列表,两个列表具有相同的大小,并且两个列表中对应的元素对相等时,返回 true
。(如果 Objects.equals(e1, e2),则元素 e1 和 e2 相等。)换句话说,如果两个列表以相同的顺序包含相同的元素,则定义这两个列表相等。
> hashCode
- 返回此列表的哈希码值。列表的哈希码定义为以下计算结果:
>
> int hashCode = 1;
> for (E e : list)
> hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
>
> 这确保了对于任意两个列表 list1 和 list2,如果 list1.equals(list2) 则必须有 list1.hashCode()==list2.hashCode(),符合 Object.hashCode() 的一般契约要求。
总之,List
的 hashCode
和 equals
实现只是对列表的每个元素进行操作。
英文:
HashSet
relies on the equals
and hashCode
methods of the element type (which in your case is List
). The documentation for those methods on the List
type is as follows:
> equals
- Compares the specified object with this list for equality. Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elements e1 and e2 are equal if Objects.equals(e1, e2).) In other words, two lists are defined to be equal if they contain the same elements in the same order.
> hashCode
- Returns the hash code value for this list. The hash code of a list is defined to be the result of the following calculation:
>
> int hashCode = 1;
> for (E e : list)
> hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
>
> This ensures that list1.equals(list2) implies that list1.hashCode()==list2.hashCode() for any two lists, list1 and list2, as required by the general contract of Object.hashCode().
I.e. in summary, the hashCode
and equals
implementations for List
s simply operate on each element of the list.
答案2
得分: 2
HashSet#contains(Object o)
javadoc指出如下(我强调了部分):
如果此集合包含指定元素,则返回true。更正式地说,仅当此集合包含一个使得(o==null ? e==null : o.equals(e))成立的元素e时,才返回true。
这意味着当你检查s.contains(l2)
时,实际上是通过List#equals()
在内部检查s
中的List
与l2
的相等性。
而List#equals(Object o)
javadoc指出(我强调了部分):
将指定对象与此列表进行比较以确定相等性。如果指定对象也是一个列表,并且两个列表具有相同的大小,并且两个列表中相应对应的元素都相等,则返回true。(如果两个元素e1和e2相等,则为(e1==null ? e2==null : e1.equals(e2))。)换句话说,如果两个列表包含相同顺序的相同元素,则定义它们相等。 这个定义确保了equals方法在List接口的不同实现之间正常工作。
这正是为什么l2
被发现包含在s
中,但l3
却没有。
英文:
The HashSet#contains(Object o)
javadoc states the following (emphasis mine):
> Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e)).
So, this means when you check s.contains(l2)
, the List
s in s
are actually checked for equality against l2
via List#equals()
internally.
And the List#equals(Object o)
javadoc states (emphasis mine):
> Compares the specified object with this list for equality. Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elements e1 and e2 are equal if (e1==null ? e2==null : e1.equals(e2)).) In other words, two lists are defined to be equal if they contain the same elements in the same order. This definition ensures that the equals method works properly across different implementations of the List interface.
Which is exactly why l2
is found to be contained in s
, but l3
is not.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论