Android replaceAll и сравнение строк с ==

При проверке исходного кода на Android я обнаружил ошибку сравнения строк, которая использовала == вместо equals(). Однако приложение работает на удивление!

После некоторого тестирования я обнаружил, что метод 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), и он печатает "==: false", как я ожидал.

Это ошибка в Android или это предполагаемое поведение?

1 ответ

Нет, это не ошибка - это просто утечка информации о реализации.

Компилятор java создает пул строк, используемых в коде. Пустая строка, безусловно, одна из них. Каждый раз, когда вы устанавливаете переменную в пустую строку во время компиляции, она указывает на тот же экземпляр пустой строки. Так

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

if (a == b) {
 //this will always be true in practice, although I don't know if it 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().

licensed under cc by-sa 3.0 with attribution.