Почему выход отличается от JDK 1.4 и 1.5?
Я запускаю этот код с JDK 1.4 и 1.5 и получаю разные результаты. Почему это так?
String str = "";
int test = 3;
str = String.valueOf(test);
System.out.println("str[" + str + "]\nequals result[" + (str == "3") + "]");
if (str == "3") {
System.out.println("if");
} else {
System.out.println("else");
}
выходы:
Ответы
Ответ 1
В соответствии с этой страницей метод Integer#toString
(который вызывается String#valueOf(int)
) реализуется следующим образом: 1.4:
public static String toString(int i) {
switch(i) {
case Integer.MIN_VALUE: return "-2147483648";
case -3: return "-3";
case -2: return "-2";
case -1: return "-1";
case 0: return "0";
case 1: return "1";
case 2: return "2";
case 3: return "3";
case 4: return "4";
case 5: return "5";
case 6: return "6";
case 7: return "7";
case 8: return "8";
case 9: return "9";
case 10: return "10";
}
char[] buf = (char[])(perThreadBuffer.get());
int charPos = getChars(i, buf);
return new String(buf, charPos, 12 - charPos);
}
Это объяснит ваш результат, потому что строковый литерал "3"
интернирован и "3" == "3"
всегда возвращает true.
Вы можете попробовать с 10 и 11, чтобы проверить это.
Примечание: как уже упоминалось, javadoc Integer#toString
не говорит о том, будет ли возвращенная строка интернирована или нет, так что оба вывода в вашем вопросе одинаково действительны.
Ответ 2
Это деталь реализации, которая не задана JLS.
Оператор ссылочного равенства ==
проверяет, указывают ли две переменные на один и тот же фактический объект, тогда как метод equals
проверяет, являются ли значения двух переменных "равными" каким-либо образом, которые могут быть определены программист. В этом случае, похоже, что 1.4 JVM использует тот факт, что String
неизменяемы для повторного использования одной и той же копии строки "3"
, когда вы вызываете valueOf
, а 1.5 JVM - нет. Оба варианта совершенно законны, и вы не должны зависеть от какого-либо конкретного такого поведения.
Ответ 3
Из java 5 string.valueof(), как ожидается, вернет новую строку. а не intern (ed) (общая) строка!
Рассмотрим следующий пример
int test = 3;
String str = String.valueOf(test);
String str2 = String.valueOf(test);
if(str == str2)
System.out.println("valueOf return interned string");
else
System.out.println("valueOf does not return interned string");
Вывод в java >= 5
valueOf does not return interned string
Но в java 4 вывод
valueOf return interned string
Это объясняет поведение!
Ответ 4
Если вы используете оператор "==" при работе с литералами String, это зависит от того, присутствует ли значение литерала строки в "String Pool" или нет, в вашем случае переменная "str" представляет собой строку JVM first проверяет "String Pool" , если он найден, тогда он возвращает TRUE else FALSE. Попробуйте следующий код с помощью метода intern(), чтобы сделать литерал строки доступным в "String Pool"
String str = "";
int test = 3;
str = String.valueOf(test).intern();
System.out.println("str[" + str + "]\nequals result[" + (str == "3") + "]");
if (str == "3") {
System.out.println("if");
} else {
System.out.println("else");
}
согласно документации для метода intern():
intern() ищет внутреннюю таблицу строк для строки, равной этой Строке. Если строка отсутствует в таблице, она добавляется. Отвечает на строку, содержащуюся в таблице, которая равна этой Строке. Один и тот же строковый объект всегда отвечает за строки, которые равны.
Ну "==" операция не рекомендуется для сравнения строк. используйте equals() или equalsIgnoreCase() method().
Я пробовал даже в java 1.7 без intern(), вывод
str[3]
equals result[false]
else
с intern() выход приходит к:
str[3]
equals result[true]
if
Это не проблема jdk 1.4 и 1.5, это "логическая ошибка".