Есть идеи, почему мне нужно привести целочисленный литерал к (int) здесь?

#java #syntax #casting

#java #синтаксис #Кастинг

Вопрос:

В следующем примере

 int i = -128;
Integer i2 = (Integer) i; // compiles

Integer i3 = (Integer) -128; /*** Doesn't compile ***/

Integer i4 = (Integer) (int) -128; // compiles
Integer i4 = -128; // compiles
Integer i5 = (int) -128; // compiles
Integer i6 = (Integer) (-128); // compiles
Integer i7 = (Integer) 0-128; // compiles
  

Я не могу использовать -128 , (Integer) но я могу использовать (int) -128 .

Я всегда думал -128 , что это int тип, и приведение его к (int) нему должно быть избыточным.

Ошибка в строке с i3

 cannot find symbol variable Integer
  

Я пробовал это с Java 6 update 29 и Java 7 update 1.

РЕДАКТИРОВАТЬ: вы получаете то же поведение с 128 помощью вместо -128 . Похоже, это путаница между унарными и двоичными операторами.

Комментарии:

1. какой у вас компилятор? Integer i = -128; однако это должно скомпилироваться.

2. странно, Integer i3 = (Integer) (-128); соответствует.

3. @Eng. Фуад, Питер, унарные символы ( -) имеют ассоциативность справа налево, а плюс, минус — слева направо. Эффект -128 будет таким же, как 128, и добавление 0 впереди должно быть исправлено, т. Е. 0-128 или 0 128. (не могу проверить atm, но я уверен, что так и будет)

4. Хороший вопрос! Я лично хотел бы увидеть ссылку JLS для разрешения унарных / двоичных операторов и когда приведение обрабатывается как выражение. В противном случае возможно, что другие компиляторы не считают это ошибкой!

5. Также, к вашему сведению, ошибка, которую я получаю в своей IDE Expression expected , — это то, где Integer находится.

Ответ №1:

Компилятор пытается вычесть 128 из (Integer) вместо приведения -128 к Integer . Добавить () , чтобы исправить это

 Integer i3 = (Integer) -128; // doesn't compile
Integer i3 = (Integer) (-128); // compiles
  

Согласно BoltClock в комментариях, приведение к int работает по назначению, потому что это зарезервированное слово и поэтому не может быть интерпретировано как идентификатор, что имеет смысл для меня.

И Bringer128 нашел ссылку на JLS 15.16.

 CastExpression:
 (PrimitiveType затемняет opt) UnaryExpression
 (ReferenceType ) UnaryExpressionNotPlusMinus

Как вы можете видеть, для приведения к примитивному типу требуется any UnaryExpression , тогда как для приведения к ссылочному типу требуется a UnaryExpressionNotPlusMinus . Они определены непосредственно перед CastExpression в JLS 15.15.

Комментарии:

1. Я думаю, это потому int , что это ключевое слово в Java, но Integer это не так. Поскольку int это ключевое слово, вы не можете использовать его в качестве идентификатора переменной или класса, оставляя единственной возможностью для него быть приведением к типу. Это все объясняет.

2. @BoltClock включил ваш комментарий в ответ.

3. Чтобы сделать это еще более звездным ответом, вы хотите добавить мою ссылку на JLS?

4. Интересная (для меня) проблема в этой проблеме заключается в том, как мы решаем аналогичную проблему в C #, которая также имеет двусмысленность в грамматике между «выражением в скобках в качестве операнда для оператора двоичного вычитания» и «оператором приведения, где правый операнд приведения является унарным выражением минус». Подробное описание эвристики, которую мы используем, чтобы попытаться разумно разрешить неоднозначность, см. В разделе 7.7.6 спецификации C #.

5. @BillK Почему ты так говоришь? Спецификация C # не ссылается на перегрузку оператора в разделе 7.7.6, поэтому для них это не было проблемой.

Ответ №2:

Я нашел ссылку на JLS. 15.16.

 CastExpression:
 (PrimitiveType затемняет opt) UnaryExpression
 (ReferenceType ) UnaryExpressionNotPlusMinus

Как вы можете видеть, для приведения к примитивному типу требуется any UnaryExpression , тогда как для приведения к ссылочному типу требуется a UnaryExpressionNotPlusMinus . Они определены непосредственно перед CastExpression в JLS 15.15.

Вам нужно либо изменить приведение к примитивному типу:

 ... (int) -128;
  

Или вы можете изменить выражение справа от приведения на унарное выражение, отличное от плюс-минус:

 ... (Integer) (-128);  // Either
... (Integer) 0 - 128; // Or
  

Ответ №3:

Компилятор интерпретирует - как оператор минус с двумя аргументами, т. Е. Он пытается вычесть 128 из какого-то другого числа с именем Integer , но в области видимости такой переменной нет.

Это компилирует:

 Integer i3 = (Integer) (-128)
  

Комментарии:

1. Вы могли бы добавить комментарий о том, почему (int) это имеет значение.

2. Это из-за автоматической упаковки, нет?

Ответ №4:

Возможно, это связано с синтаксическим анализом. Обратите внимание, что

 Integer i4 = (Integer) (-128); 
  

работает просто отлично.

В общем, вы не должны приводить к целочисленному классу. Это связано с чем-то, называемым автоматической упаковкой, и может вызвать некоторые незначительные ошибки в вашем коде. Предпочтительный способ сделать то, что вы хотите, это:

 Integer i6 = Integer.valueOf(-128)
  

Комментарии:

1. приведение к целому числу — это точно синтетический сахар для valueOf .

2. да, но иногда синтетический сахар терпит неудачу тонкими способами. Мне было трудно отследить исключения нулевого указателя в больших приложениях из-за автоматической упаковки. Мы зашли так далеко, что рассматривали автобокс как ошибки, чтобы избежать головной боли в будущем. Магия хороша, но когда она терпит неудачу, голова болит. Я считаю, что лучше быть явным и избавить себя от головной боли.

3. NPE — это b1tch без отправки, true. Особенно в таких случаях, как for (int i in Collection<Integer>) b / c, NPE находится в абсолютно неожиданном месте. На самом деле я не использую Integer без автоматической упаковки, поскольку диапазон кэша невелик (хотя его можно увеличить с помощью опции XX), но у меня есть класс с именем IntegerProvider (начиная с 1.1) для выполнения тех же действий. Использование Map (любого из java.util) Integer-> Anything обычно снижает производительность, если оно не используется для тривиальных случаев, и почти всегда есть лучшее решение.

4. Приведение int к Integer никогда не может вызвать никаких ошибок, кроме переполнения кучи, возможно. Однако обратное неверно.

5. @MattBall, я не совсем понимаю, синтетический сахар широко используется: eggcorns.lascribe.net/forum/viewtopic.php?id=4400 и синтетика, по-моему, звучит лучше.

Ответ №5:

Он анализирует его как Integer <minus operator> 128 и не находит переменную Integer . Вам нужно будет заключить -128 в скобки:

 Integer i3 = (Integer) (-128);  // compiles
  

Комментарии:

1. Я присвоил 1 всем остальным ответам, потому что все они тоже правильные 🙂

Ответ №6:

 Integer i3 = (Integer) (-128);
  

Проблема - в том, что компилятор видит его как оператор.

Ответ №7:

Строка 3 интерпретируется так, как будто вы пытаетесь вычесть 128 из выражения в круглых скобках, а выражение в круглых скобках не является выражением типа int (оно обрабатывает ‘-‘ как оператор ‘-‘). Если вы измените выражение на:

 Integer i3 = (Integer) (-128);
  

тогда компилятор поймет, что ‘-‘ — это унарный минус, который указывает на отрицательное целое число.

Ответ №8:

Компилятор C # имеет такое же поведение. Это дает лучший намек на то, почему он не компилируется, хотя:

Чтобы привести отрицательное значение, вы должны заключить значение в круглые скобки