在审核 Android 源代码时,我发现了一个字符串比较错误,该错误使用 == 而不是 equals()。然而,该应用程序运行得令人惊讶!
经过一些测试,我发现replaceAll()方法隐藏了这个bug。
String description = " ";
description = description.trim();
Result1.setText(description + " == " + "" + ": " + (description == ""));
按照我的预期打印“==:false”。然而,
String description = " ";
description = description.trim().replaceAll("\\s+|\\r+|\\n+", " ");
Result1.setText(description + " == " + "" + ": " + (description == ""));
打印“==:true”! (Android 4.4.2,API 19)
我在桌面上运行相同的代码 (javac 1.6.0_45),它按照我的预期打印“==:false”。
这是 Android 中的错误还是有意为之?
最佳答案
不,这不是一个错误——它只是泄露了一个实现细节。
java 编译器创建代码中使用的字符串池。空字符串肯定是其中之一。任何时候在编译时将变量设置为空字符串时,它都会指向空字符串的同一个实例。所以
String a = "";
String b = "";
if (a == b) {
//this will always be true in practice, although I don't know if it's guaranteed
}
现在想象一下trim()和replaceAll()的实现方式不同:
String trim() {
byte[] b = getBytes();
...
return new String(b, 0, len);
}
String replaceAll (String needle, String replacement) {
String result = "";
int pos = 0;
while (indexOf(needle, pos) != -1) {
...
result = result + replacement;
pos = ...;
}
return result;
}
因为trim()调用String构造函数,所以它必然创建一个新的String。但replaceAll从一个空字符串开始并建立起来。它开头的空字符串与源代码中的所有其他空字符串相同。
这些都是假的实现——这只是一个假设,即它是如何工作的。与观察到的数据相符,但我没有阅读Android代码。不过,它表明类似函数的不同实现可能会导致您所看到的效果。
换句话说,这不是一个错误,但它不是您想要依赖的行为。如果您确实想依赖 .equal() 也为 == 的两个字符串,则可以使用 String.intern()。
关于java - Android的replaceAll和字符串比较与==,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22851852/