java - Android的replaceAll和字符串比较与==

标签 java android string

在审核 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/

相关文章:

java - 将字符串转换为java类型

java - 从父类(super class)调用方法的 super 关键字与类名之间的区别

java - java中连接两个url

android - 如何在 Android 应用程序中保持与 facebook 的连接

C: 抑制来自二进制的系统调用

json - Swift::遍历一个json字符串

java - Swing 布局未正确显示

java - 滚动后自定义 ListView 崩溃

java - 未知错误 - 阵列适配器

android - 为什么它以桌面为中心而不是以设备为中心?