2014-04-04 45 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()。