Java Set<String>的contains()为何无法匹配StringBuilder对象?
在LeetCode题目「Find Unique Binary String」的测试用例nums = ["00","01"]中,原代码错误返回了"00",核心问题出在!currentResults.contains(currentString)这个判断条件上——明明"00"存在于Set<String>集合currentResults中,但传入StringBuilder类型的currentString时,contains方法却无法检测到它。改成!currentResults.contains(currentString.toString())后代码正常运行,原因如下:
集合元素类型与传入参数类型不匹配
currentResults是Set<String>类型,内部存储的全是String对象。而currentString是StringBuilder对象,二者属于完全不同的类型。equals()方法的类型限制
Java集合的contains方法依赖元素的equals()方法判断相等性:
String类重写了equals(),会比较两个字符串的内容,但它的equals()方法只会接收String类型的参数——如果传入非String对象(比如StringBuilder),会直接返回false。StringBuilder类没有重写equals(),它继承自Object类的equals(),只会比较对象的内存引用是否相同,不会比较内容。
举个简单的例子验证:
String str = "00"; StringBuilder sb = new StringBuilder("00"); System.out.println(str.equals(sb)); // 输出false,因为参数不是String类型 System.out.println(sb.equals(str)); // 输出false,因为比较的是对象引用
所以原代码中,即使currentString的内容是"00",但因为是StringBuilder对象,currentResults.contains(currentString)永远返回false,导致代码错误地认为"00"不在集合中,直接将其作为结果返回。而调用currentString.toString()后,得到的是一个String对象,此时contains方法会正确比较字符串内容,从而判断出该值是否存在于集合中。
原问题代码
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); } }
内容的提问来源于stack exchange,提问作者mattsmith5

