英文:
Does Java Set<String> contains() check for existence of StringBuilder?
问题
Java中的Set<String> contains()
方法知道如何检查StringBuilder的存在吗?
我在Leetcode上遇到了这个问题,题目是"查找独特的二进制字符串"。请注意,这个问题不是为了解决Leetcode问题,而是为了理解为什么会出现问题。链接:https://leetcode.com/problems/find-unique-binary-string/description/
给定一个包含n个长度为n的唯一二进制字符串的字符串数组nums,请返回一个长度为n的二进制字符串,该字符串不在nums中出现。如果有多个答案,可以返回任何一个。
nums = ["00","01"]
代码输出
"00"
预期答案选择
"10"
问题:
这段代码在!currentResults.contains(currentString)
处失败,其中currentString为"00",当该数字存在于Set中时。
将其更改为!currentResults.contains(currentString.toString()))
将使其成功。我正在尝试理解这背后的原因。
代码:
List<String> results = new ArrayList<>();
Set<String> currentResults = new HashSet<>();
String finalString;
int numsLength;
public String findDifferentBinaryString(String[] nums) {
for (String data: nums) {
currentResults.add(data);
}
if (nums.length == 0) {
return "";
}
numsLength = nums.length;
getDFS(nums, new StringBuilder(""));
return finalString;
}
public void getDFS(String[] nums, StringBuilder currentString) {
if (finalString != null ) {
return;
}
if (currentString.length() == numsLength && !currentResults.contains(currentString)) {
finalString = currentString.toString();
return;
}
if (currentString.length() == numsLength) return;
for (int i = 0; i <= 1; i++) {
currentString.append(String.valueOf(i));
getDFS(nums,currentString);
currentString.deleteCharAt(currentString.length() - 1);
}
}
英文:
Does Java Set<String> contains()
know how to check for the existence of StringBuilder?
I am running this problem in Leetcode. "Find Unique Binary String". Note this Question is not about Solving the Leetcode, but understanding why an issue occurs. https://leetcode.com/problems/find-unique-binary-string/description/
> Given an array of strings nums containing n unique binary strings each
> of length n, return a binary string of length n that does not appear
> in nums. If there are multiple answers, you may return any of them.
nums = ["00","01"]
Code Output
"00"
Expected Answers Choice
"10"
Problem:
This code fails at !currentResults.contains(currentString)
where currentString is "00" ,when the number exists in the Set.
Changing it to !currentResults.contains(currentString.toString()))
will make it succeed. I am trying to understand reason behind this.
Code:
List<String> results = new ArrayList<>();
Set<String> currentResults = new HashSet<>();
String finalString;
int numsLength;
public String findDifferentBinaryString(String[] nums) {
for (String data: nums) {
currentResults.add(data);
}
if (nums.length == 0) {
return "";
}
numsLength = nums.length;
getDFS(nums, new StringBuilder(""));
return finalString;
}
public void getDFS(String[] nums, StringBuilder currentString) {
if (finalString != null ) {
return;
}
if (currentString.length() == numsLength && !currentResults.contains(currentString)) {
finalString = currentString.toString();
return;
}
if (currentString.length() == numsLength) return;
for (int i = 0; i <= 1; i++) {
currentString.append(String.valueOf(i));
getDFS(nums,currentString);
currentString.deleteCharAt(currentString.length() - 1);
}
}
答案1
得分: 3
No, Set.contains(Object o)
检查是否存在一个与指定元素相等的对象。
返回true
如果这个集合包含指定的元素。更正式地说,只有当这个集合包含一个元素e
,使得(o==null ? e==null : o.equals(e))
成立时,才返回true
。
这意味着StringBuilder
类型不会满足.equals()
条件,因为它会调用String.equals()
,而StringBuilder
在未显式调用.toString()
之前不会满足真正的条件。
在Java语言中有其他情况下会隐式调用.toString()
,但String
的.equals()
操作符不是其中之一。
(comment) 我希望它能匹配set类型,并在String
类型与StringBuilder
不匹配时发出警告。
一些代码编辑器,比如IntelliJ,会尝试警告这一点,参见附图:
英文:
> Does Java Set Contains() know how to check for existence of Stringbuilder?
No, Set.contains(Object o)
checks for the existence of an Object that equals.
Quoting:
> 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))
.
This means that a StringBuilder
type will not satisfy the .equals()
clause because it will call String.equals()
and StringBuilder
will not satisfy a true condition without explicitly calling .toString()
first.
There are other cases in the Java language where .toString()
is implicitly called, but the .equals()
operator for String
is not one of those cases.
> (comment) I was hoping it would match set type and give a warning if String
type does not match with StringBuilder
Some code editors -- such as IntelliJ -- will try to warn about this, see attached picture:
答案2
得分: 1
StringBuilder
和 StringBuffer
是可变的,因此它们都没有重写 equals
和 hashcode
方法。因此,当有人调用这些引用的 equals
方法时,它将在内部使用 ==
进行比较,这意味着只会检查地址而不会检查内容。
StringBuilder sb1 = new StringBuilder("ABC");
StringBuilder sb2 = new StringBuilder("ABC");
System.out.println(sb1.equals(sb2));
尽管两者具有相同的值,输出将是 false
,因为这两个引用指向不同的内存位置。因此,重要的和首要的事情是要理解 StringBuilder
和 StringBuffer
中的 equals
方法不会检查内容。
对于 Set
,contains()
方法将在内部使用 equals
和 hashcode
来检查元素是否存在。现在,如果对象的类型是 StringBuilder
或 StringBuffer
,则 equals
将比较 Set 中的内容和 contains()
方法的参数的地址。
因此,在你的示例中,这一行 currentResults.contains(currentString)
不会按照你的期望工作,因为 Set
将在 currentString
上调用 equals
,而 currentString
是一个 StringBuilder。它将类似于以下方式:
currentString.equals(someElementInSet)
当然,currentString
和 Set 中的元素位于不同的内存位置,会返回 false。
现在,当你调用 currentResults.contains(currentString.toString()))
时,currentString
的值会转换为 String
类型,其中 equals
方法会检查内容而不是内存位置。因此,在这种情况下,如果 currentString
是 "00",contains()
将返回 true。
英文:
StringBuilder
and StringBuffer
are mutable and so the equals
and hashcode
are not overridden in both. So when someone calls the equals
method on these references it would internally use ==
for comparison, which means only the addresses will be checked and not the content.
StringBuilder sb1 = new StringBuilder("ABC");
StringBuilder sb2 = new StringBuilder("ABC");
System.out.println(sb1.equals(sb2));
Even though both are having the same value, the output will be false
because both references are pointing to a different memory location. So the important and primary thing to understand is that the equals
method in StringBuilder
and StringBuffer
will not check for content.
In the case of a Set
, the contains()
method would be internally using equals
and hashcode
to check for existence. Now, if the object is of type StringBuilder
or StringBuffer
the equals
would compare the addresses of the contents in the Set and the argument of the contains()
method.
So, when we get into your example at this line currentResults.contains(currentString)
won't work as you expected, because the Set
will be calling equals
on the currentString
which is a StringBuilder. It will be something like this
currentString.equals(someElementInSet)
And definitely, both currentString
and elements in the Set are in different memory locations and would return false.
Now when you call currentResults.contains(currentString.toString()))
, the value of currentString
gets converted to a String
type in which equals
method checks for content rather than the memory location. So, in this case, if currentString is 00, the contains()
will return true.
Areas you can improve
Do the length check of nums
at the beginning of the method, you don't have to run a loop if it is empty.
答案3
得分: 1
以下是翻译好的内容:
伟大的问题,因为这与某些框架方法相反,这些方法利用了_Object_参数。在这些情况下,它们通过_String#valueOf_来外推_StringBuilder_。
区别在于_Collections Framework_只是传播对象类型,而不是内容。
> “Java Set contains() 是否知道如何检查 StringBuilder 的存在? ...
>
> ... 将它更改为 !currentResults.contains(currentString.toString()))
将使它成功。我正在尝试理解背后的原因...”
你在暗示_Set#contains_应该解释_StringBuilder_的内容,即_currentString.toString()_。
这并不是事实。它只是比较对象类型。
这是最终由_HashSet#contains_执行的代码。
GitHub – jdk/src/java.base/share/classes/java/util/HashMap.java
英文:
Great question, as this is contrary to some framework methods which utilize the Object parameter.
In these cases, they are extrapolating the StringBuilder through String#valueOf.
The difference is that the Collections Framework is simply disseminating the object type, and not the content.
> "Does Java Set contains() know how to check for the existence of StringBuilder? ...
>
> ... Changing it to !currentResults.contains(currentString.toString()))
will make it succeed. I am trying to understand reason behind this. ..."
You're implying that Set#contains should interpret the content of StringBuilder—i.e., currentString.toString().
This isn't the case. It's just comparing the object type.
Here is the code, ultimately executed by HashSet#contains.
GitHub – jdk/src/java.base/share/classes/java/util/HashMap.java
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论