#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 # имеет такое же поведение. Это дает лучший намек на то, почему он не компилируется, хотя:
Чтобы привести отрицательное значение, вы должны заключить значение в круглые скобки