Вызывает ли 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()
, поскольку это относится только к буквальным значениям.
Ответы
Ответ 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. Попробуем.