Подтвердить что ты не робот

Вызывает ли autoboxing значение valueOf()?

Я пытаюсь определить, гарантируются ли следующие утверждения:

((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
((Integer)1) == Integer.valueOf(1)

Я всегда предполагал, что автобоксинг эквивалентен вызову valueOf() соответствующего типа. Каждая дискуссия, которую я видел в , кажется поддержка мое предположение. Но все, что я мог найти в JLS, было следующим (§5.1.7):

Если введенное значение p является целым литералом типа int между -128 и 127 включительно (§3.10.1) или булевым литералом true или false (§3.10).3) или символьный литерал между '\u0000' и '\u007f' включительно (§3.10.4), затем пусть a и b будут результатом любых двух преобразований бокса в p. Всегда бывает, что a == b.

Это описывает поведение идентичное похожее * с символом valueOf(). Но, похоже, нет никакой гарантии, что valueOf() действительно вызывается, то есть теоретически может быть реализация, которая хранит отдельный выделенный выделенный кеш для автономных значений. В таком случае может существовать не равенство идентичности между кешированными автобоксами и регулярными кэшированными значениями в коробке.

Учебник по autoboxing для Oracle утверждает, что li.add(i) скомпилирован в li.add(Integer.valueOf(i)), где i является int. Но я не знаю, следует ли считать учебник авторитетным источником.


* Это немного слабее, чем valueOf(), поскольку это относится только к буквальным значениям.

4b9b3361

Ответ 1

Сначала я решил, что ваш вопрос был обманом Какой код генерирует компилятор для автобоксинга?

Однако после вашего комментария к @ElliottFrisch я понял, что это было другое:

Я знаю, что компилятор ведет себя так. Я пытаюсь выяснить, это поведение гарантировано.

Для других читателей предположим, что "ведет себя так" означает использование valueOf.

Помните, что для Java есть компиляторы. Чтобы быть "законными", они должны следовать контракту, указанному в JLS. Поэтому, пока соблюдаются все правила, нет гарантии того, что внутренняя реализация autoboxing реализована.

Но я не вижу причин не использовать valueOf, особенно, что он использует кешированные значения и является рекомендуемым способом по этой статье Джозефом Д. Дарси.

Ответ 2

Пока спецификация языка не упоминает об этом, не гарантируется, что автобоксинг эквивалентен вызову статических методов valueOf. Это аспект реализации, а не часть спецификации преобразования бокса. Реализация теоретически свободна в использовании другого механизма, если она соответствует правилу, упомянутому вами в JLS.

На практике существует множество отчетов об ошибках Sun JDK (например, JDK-4990346 и JDK-6628737), которые явно подразумевают, что когда в Java 5 было введено автобоксирование, у намерения было, чтобы компилятор полагался на valueOf, как указано в JDK-6628737:

Статические методы factory Integer.valueOf(int), Long.valueOf(long) и т.д. были введены в JDK 5 для javac для реализации поведения кэширования, требуемого спецификацией autoboxing.

Но это только для javac, не обязательно всех компиляторов.

Ответ 3

Автообъект реализован с использованием valueOf()... в OpenJDK. Если это ваша реализация, прочитайте... если нет, пропустите ниже.

((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)

Документация Java утверждает, что Boolean.valueOf() всегда возвращает Boolean.TRUE или Boolean.FALSE, поэтому ваши сравнения ссылок в этих случаях будут успешными.

((Integer)1) == Integer.valueOf(1)

В этом конкретном примере в рамках реализации OpenJDK с настройками по умолчанию это, вероятно, будет работать в силу того, что вы выбрали значение < 128, который кэшируется при запуске (хотя это можно переопределить в качестве командной строки arg). Он также может работать для больших значений, если он часто используется достаточно для кэширования. Если вы не работаете в "безопасных" предположениях о кеше Integer, не ожидайте, что эталонное сравнение будет равенством.

Long, Short, Character и Byte кстати также реализуют это кэширование, но в отличие от Integer он не настраивается. Byte всегда будет работать, если вы сравниваете ссылки autobox/valueOf(), поскольку, очевидно, вы не можете выйти за пределы диапазона. Float и Double неудивительно всегда создадут новый экземпляр.


Теперь, в чисто общих терминах? См. этот раздел JLS - вам MUST присваиваются равные ссылки для boolean и любых int или char в диапазоне от -128 до 127. нет гарантий для чего-либо еще.

Ответ 4

В учебнике по autoboxing для Oracle указано, что li.add(i) скомпилирован в li.add(Integer.valueOf(i)), где я - int. Но я не знаю, следует ли считать учебник авторитетным источником.

Я запускаю Oracle Java 1.7.0_72, похоже, что он использует valueOf. Ниже приведен код и байт-код для него. Байт-код показывает, что он использует valueOf.

public class AutoBoxing {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Integer x = 5;
        int i = x;
        System.out.println(x.toString());
    }

}





Compiled from "AutoBoxing.java"
public class testing.AutoBoxing {
  public testing.AutoBoxing();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_5
       1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       4: astore_1
       5: aload_1
       6: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
       9: istore_2
      10: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      13: aload_1
      14: invokevirtual #5                  // Method java/lang/Integer.toString:()Ljava/lang/String;
      17: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: return

Но я не знаю, что использует Open JDK. Попробуем.