Java Set<String> contains()方法检查StringBuilder的存在吗?

huangapple go评论62阅读模式
英文:

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&lt;String&gt; results = new ArrayList&lt;&gt;();
Set&lt;String&gt; currentResults = new HashSet&lt;&gt;();
String finalString;
int numsLength;

public String findDifferentBinaryString(String[] nums) {
    
    for (String data: nums) {
        currentResults.add(data);
    }
    if (nums.length == 0) {
        return &quot;&quot;;
    }
    numsLength = nums.length;
    getDFS(nums, new StringBuilder(&quot;&quot;));
    return finalString;
}

public void getDFS(String[] nums, StringBuilder currentString) {
    if (finalString != null ) {
        return;
    }

    if (currentString.length() == numsLength &amp;&amp; !currentResults.contains(currentString)) {
        finalString = currentString.toString();
        return;
    }

    if (currentString.length() == numsLength) return;

    for (int i = 0; i &lt;= 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,会尝试警告这一点,参见附图:

Java Set<String> contains()方法检查StringBuilder的存在吗?

英文:

> 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:

> Java Set<String> contains()方法检查StringBuilder的存在吗?

答案2

得分: 1

StringBuilderStringBuffer 是可变的,因此它们都没有重写 equalshashcode 方法。因此,当有人调用这些引用的 equals 方法时,它将在内部使用 == 进行比较,这意味着只会检查地址而不会检查内容。

StringBuilder sb1 = new StringBuilder("ABC");
StringBuilder sb2 = new StringBuilder("ABC");

System.out.println(sb1.equals(sb2));

尽管两者具有相同的值,输出将是 false,因为这两个引用指向不同的内存位置。因此,重要的和首要的事情是要理解 StringBuilderStringBuffer 中的 equals 方法不会检查内容。

对于 Setcontains() 方法将在内部使用 equalshashcode 来检查元素是否存在。现在,如果对象的类型是 StringBuilderStringBuffer,则 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(&quot;ABC&quot;);
StringBuilder sb2 = new StringBuilder(&quot;ABC&quot;);

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 &ndash; 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&mdash;i.e., currentString.toString().

This isn't the case.&nbsp; It's just comparing the object type.

Here is the code, ultimately executed by HashSet#contains.
GitHub &ndash; jdk/src/java.base/share/classes/java/util/HashMap.java

huangapple
  • 本文由 发表于 2023年6月15日 13:54:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76479481.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定