简体   繁体   中英

Android replaceAll and string comparison with ==

While auditing an android source code, I found a string comparison bug which used == instead of equals(). However, the app is working well surprisingly!

After some testing, I found that replaceAll() method is hiding the bug.

String description = " ";
description = description.trim();
Result1.setText(description + " == " + "" + ": " + (description == ""));

prints "==:false" as I expected. However,

String description = " ";
description = description.trim().replaceAll("\\s+|\\r+|\\n+", " ");
Result1.setText(description + " == " + "" + ": " + (description == ""));

prints "==:true"! (Android 4.4.2, API 19)

I run the same code in my desktop (javac 1.6.0_45) and it prints "==:false" as I expected.

Is it a bug in Android or is it intended behavior?

No, it's not a bug -- it's just an implementation detail leaking out.

The java compiler creates a pool of strings used in the code. The empty string is surely one of these. Any time you set a variable to the empty string at compile-time, it will point to the same instance of the empty string. So

String a = "";
String b = "";

if (a == b) {
   //this will always be true in practice, although I don't know if it's guaranteed
}

Now imagine that trim() and replaceAll() are implemented differently:

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;
}

Because trim() calls a String constructor, it necessarily creates a new String. But replaceAll starts with an empty String and builds up. And the empty String that it starts with is the same empty string as all the other empty strings in your source code.

These are fake implementations -- it's just a hypothesis that this is how it works. It matches the observed data, but I didn't read the Android code. Still, it demonstrates that different implementations of similar functions could lead to the effect that you're seeing.

In other words, it's not a bug, but it's not a behavior you want to depend on. If you do want to depend on two strings that .equal() also being ==, you can use String.intern().

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM