Почему выход отличается от 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
    

Ответ 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, это "логическая ошибка".