Чому "int i = 2147483647 + 1;" Гаразд, але "байт b = 127 + 1;" не комбінується?


126

Чому це int i = 2147483647 + 1;нормально, але byte b = 127 + 1;його не можна компілювати?


16
У мене теж є справжні сумніви: чому такий byteтип даних болить ?!
BoltClock

9
це, безумовно, помилка дизайну, яка byteпідписується замість непідписаної.
незаперечний

4
@BoltClock Це лише біль, коли ти не знаєш, як правильно їх використовувати. stackoverflow.com/questions/397867 / ...
starblue

2
@starblue, чи є приклад із реального життя, де застосовано тип байту Java?
Thorbjørn Ravn Andersen

Якщо є дані, які вказані як байт, то byteдля чіткості використовуйте Java , наприклад у параметрах. У такому випадку той факт, що ви не можете призначити intзначення, навіть спричинить деякі помилки. Або використовувати byteдля економії місця в масивах. Я не використовував byteби жодне значення, яке просто трапляється в байті.
starblue

Відповіді:


172

Константи оцінюються як 2147483647 + 1int , тому переповнює і дає вам новий int, який можна присвоїти int, а 127 + 1також оцінювати як intрівний 128, і це не можна присвоїти byte.


10
Насправді сьогодні я прочитав деякі загадки Java , зокрема головоломку саме про це ... Дивіться тут: javapuzzlers.com/java-puzzlers-sampler.pdf - пазл 3
MByD

3
Питання - тип, intобумовлений двійковим числовим просуванням, значення 127- червона оселедець.
starblue

Я вважаю за краще, щоб константи оцінювались з нескінченною точністю, а також давали помилку на int i = 2147483647 + 1;
Едуардо

@MByD: Як ви сказали " while 127 + 1 also evaluated as int equals to 128, and it is not assignable to byte.", чи означає це, що 50 + 1 буде оцінено як byteі, отже, призначається byte?
Бхушань

1
@ 10101010 - не зовсім так. його можна присвоїти байту, але спочатку (відповідно до стандарту) він буде оцінюватися як int.
MByD

35

Буквальний 127 позначає значення типу int. Так само і в прямому значенні 1. Сума цих двох становить ціле число 128. Проблема, у другому випадку, полягає в тому, що ви присвоюєте це змінній байту типу. Це не має нічого спільного з фактичним значенням виразів. Це стосується Java, що не підтримує примуси (*). Ви повинні додати набір тексту

byte b = (byte)(127 + 1);

а потім він компілює.

(*) принаймні не такого типу String-to-integer, float-to-Time, ... Java підтримує примушування, якщо вони, в певному сенсі, не втрачають (Java називає це "розширенням").

І ні, слово «примус» виправляти не потрібно було. Він був обраний дуже свідомо і правильно. З найближчого джерела (Вікіпедія): "У більшості мов слово примус використовується для позначення неявного перетворення або під час компіляції, або під час виконання". та "В інформатиці перетворення типів, передача типу та примус - це різні способи, неявно або явно, змінювати сутність одного типу даних на іншу".


Ваш приклад коду, мабуть, повинен бути байт b = (байт) 127 + 1; що є "Додати 1 до значення зміщеного байта", ваш приклад просто перетворює int значення 128 у байт.
NKCSS

6
@NKCSS - Я не думаю, що ти маєш рацію, це - (byte)(127 + 1)кидає 128 (ціле число) в байт, тоді (byte)127 + 1як це додає 127 в байт, але потім знову до int, оскільки додано до 1 (int), і ти отримати 128 (int) та помилка залишається.
MByD

6

Як доказ @MByD:

Складається наступний код:

byte c = (byte)(127 + 1);

Оскільки, хоча вираз (127 + 1)є int і виходить за межі області off off, byteрезультат піддається кастингу byte. Цей вираз породжує -128.


3

JLS3 # 5.2 Перетворення призначення

(змінна = вираз)

Крім того, якщо вираз є постійним виразом (§15.28) типу байт, короткий, char або int:

Примітивне перетворення звуження може бути використане, якщо тип змінної є байтовим, коротким або знаковим, а значення постійного вираження є представним у типі змінної.


Без цього пункту ми не могли б написати

byte x = 0;
char c = 0;

Але чи мусимо ми це робити? Я не думаю, що так. У перетворенні серед примітивів відбувається чимало магії, треба бути дуже обережним. Я б пішов зі свого шляху писати

byte x = (byte)0;

що стосується питання, чи повинні ми мати можливість ... я не бачу насправді нічого поганого, byte x = 0але знову ж таки, я програміст на С.
Граді гравець

Можливо, я можу побачити аргумент проти char c = 0, але чому байт x = 0 неправильний?
Майкл Бердж

Це вводить в оману нетренованих очей, думаючи, що вони присвоюють байт 0 змінній байту. Немало шкоди в цьому прикладі, але в цілому, робота з байтом / коротким / символом може стати дуже заплутаною через неявні перетворення. Вони набагато складніші, ніж думають люди. Я хочу, щоб в моєму коді було якомога більше ясності, не вводити жодних невизначеностей заради економії декількох ключових штрихів.
незаперечний

Чи застосовується аналогічне правило, коли примитивне перетворення звуження є від довгого до int, наприклад, int i = 1 + 0L? Просто запитую, оскільки текст, який цитується, явно не виключає цього випадку.
Erwin Smout

@Erwin ні, int i=0Lце незаконно.
незаперечний
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.