Почему выходные данные отличаются между 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");
}
выходы:
на jdk 1.4
str[3] equals result[true] if
на JDK 1,5
str[3] equals result[false] else
4 ответа
Согласно этой странице, 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"
всегда возвращает истину.
Вы можете попробовать с 10 и 11, чтобы проверить это.
Примечание: как уже упоминалось, Javadoc Integer#toString
не говорит, будет ли возвращенная строка интернирована или нет, поэтому оба вывода в вашем вопросе одинаково действительны.
Это деталь реализации, которая не указана в JLS.
Оператор равенства ссылок ==
проверяет, указывают ли две переменные на один и тот же фактический объект, тогда как equals
Метод проверяет, являются ли значения двух переменных "равными" каким-либо образом, который может быть определен программистом. В этом случае, похоже, что 1.4 JVM использует тот факт, что String
s являются неизменными для повторного использования одной и той же копии строки "3"
когда ты звонишь valueOf
а 1,5 JVM нет. Оба варианта совершенно законны, и вы не должны зависеть от какого-либо конкретного такого поведения.
От 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
Это объясняет поведение!
Если вы используете оператор "==" для работы с строковыми литералами, то это зависит от того, присутствует ли строковое литеральное значение в "String Pool" или нет, в вашем случае переменная "str" является строкой, которую JVM сначала проверяет " String Pool "если он найден, то он возвращает TRUE, иначе 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() ().
Я пробовал даже в java 1.7 без intern() вывод
str[3]
equals result[false]
else
с intern() вывод приходит к:
str[3]
equals result[true]
if
Это не проблема jdk 1.4 и 1.5, это "логическая ошибка".