2015-07-16 9 views
48

Я пытаюсь определить, являются ли следующие утверждения гарантированно верно:Имеет ли значение autoboxing valueOf()?

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

Я всегда считал, что Autoboxing был эквивалентен вызову valueOf() по соответствующему типу. Каждый discussion, который я видел на topic, кажется support моим предположением. Но все, что я мог бы найти в 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(), то есть теоретически может быть реализация, которая хранит отдельный выделенный кеш для автономных значений. В таком случае может существовать не равенство идентичности между кешированными значениями autoboxed и регулярными кэшированными значениями в коробке.

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


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

+5

@ Jean-FrançoisSavard Это не дубликат 408661. На самом деле я связан с этим в моем вопросе. Я знаю, что он обычно компилируется в 'valueOf()'; мой вопрос заключается в том, дает ли JLS какую-либо гарантию в этом отношении. – shmosel

+0

Интересный теоретический вопрос. Могу ли я спросить, где вы хотите применить это? –

+0

Этот вопрос является трудным (но не невозможным), чтобы дать окончательный ответ, потому что он (технически говорящий) требует, чтобы вы прочитали всю JLS назад и убедитесь, что таких гарантий нет. (Я [разместил вопрос] (http://stackoverflow.com/questions/27566938/could-the-jit-collapse-two-volatile-reads-as-one-in-certain-expressions) с той же проблемой a while назад.) При этом я искал всю JLS для 'valueOf', и ни один из хитов не был связан с autoboxing (только материал о' Enum.valueOf' и т. д.). По-моему, это решает. – aioobe

ответ

29

Я первый учил ваш вопрос был контратип What code does the compiler generate for autoboxing?

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

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

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

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

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

-2

Учебное пособие по autoboxing от Oracle указывает на то, что li.add (i) скомпилирован в li.add (Integer.valueOf (i)), где 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. Попробуем.

+3

Как это отвечает на вопрос? –

+2

@ Jean-FrançoisSavard, я не нашел предложений, которые заканчивались вопросительными знаками в исходном посте. Поэтому я догадался, что последнее предложение звучит как вопрос для меня. Сообщение составлено из нескольких утверждений и открывает и заканчивается словами «Но я не знаю, следует ли считать учебник авторитетным источником. '. Поэтому для меня это выглядело как вопрос, стоящий на пути. –

+0

@JoseMartinez, первое предложение было вопросом, несмотря на отсутствие вопросительного знака. Если бы я искал анекдотические доказательства, я мог бы ответить на мой вопрос, просто выполнив свой собственный код. – shmosel

16

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

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

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

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

2

Autoboxing - абсолютно реализован с использованием 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, который кэшируется при запуске (хотя это может быть изменено, как). Он может также работает для больших значений, если он часто используется достаточно для кэширования. Если вы не работаете в «безопасных» предположениях о кеше Integer, не ожидайте, что эталонное сравнение будет равенством.

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


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

 Смежные вопросы

  • Нет связанных вопросов^_^