2014-04-04 104 views
0

比较在审计android源代码时,我发现了一个字符串比较bug,它使用==而不是equals()。但是,该应用程序运行得非常出人意料!android replaceAll和字符串与==

一些测试后,我发现的replaceAll()方法被隐藏的错误。

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),并打印 “==:假” 如我所料。

这是Android中的错误还是它的预期行为?

+0

首先,我认为这是Android开源项目的一个片段:反正,我不知道,但基于[这个答案](http://stackoverflow.com/a/513839/2821954)这可能与字符串实习有关。 (这只是我的猜测) –

+0

'description.trim()'是空的所以'replaceAll(“\\ s + | \\ r + | \\ n +”,“”)'什么也没做。底线是,不能保证使用'=='的比较是否会返回true或false。但是'equals'方法的行为已经很好的规定了。因此'description ==“”'应该被替换为'description.equals(“”)或'description.isEmpty()'。 –

回答

1

不,这不是一个错误 - 它只是一个实现细节泄露。

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

由于装饰()调用String构造,这必然会产生一个新的String。但是,replaceAll从一个空字符串开始并建立起来。和它开头的空字符串是与源代码中所有其他空字符串相同的空字符串。

这些都是假的实现 - 它只是一个假设,这是它如何工作的。它与观察到的数据相匹配,但我没有阅读Android代码。尽管如此,它表明类似函数的不同实现可能会导致您看到的效果。

换句话说,它是不是一个错误,但它不是要依赖于行为。如果你想要依赖两个字符串.equal()也是==,你可以使用String.intern()。