Примитивный тип 'short' - приведение в Java - PullRequest
75 голосов
/ 25 января 2009

У меня есть вопрос о примитивном типе short в Java. Я использую JDK 1.6.

Если у меня есть следующее:

short a = 2;
short b = 3;
short c = a + b;

компилятор не хочет компилироваться - он говорит, что он "не может конвертировать из int в short" и предлагает мне выполнить приведение к short, так что это:

short c = (short) (a + b);

действительно работает. Но мой вопрос: зачем мне кастовать? Значения a и b находятся в диапазоне short - диапазон коротких значений {-32,768, 32767}. Мне также нужно выполнить приведение, когда я хочу выполнить операции -, *, / (я не проверял другие).

Если я делаю то же самое для примитивного типа int, мне не нужно приводить aa + bb к int. Следующее работает отлично:

int aa = 2;
int bb = 3;
int cc = aa +bb;

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

Небольшое замечание: то же самое происходит и с примитивным типом byte. Итак, это работает:

byte a = 2;
byte b = 3;
byte c = (byte) (a + b);

но это не так:

byte a = 2;
byte b = 3;
byte c = a + b;

Для long, float, double и int нет необходимости разыгрывать. Только для значений short и byte.

Ответы [ 10 ]

60 голосов
/ 25 января 2009

Как объяснено в short C # (но также и для других языковых компиляторов, таких как Java)

Существует предопределенное неявное преобразование из short в int, long, float, double или decimal.

Вы не можете неявно преобразовать нелитеральные числовые типы с большим размером хранилища в короткое (см. Таблицу интегральных типов для размеров хранилища целых типов). Рассмотрим, например, следующие две короткие переменные x и y:

short x = 5, y = 12;

Следующий оператор присваивания приведет к ошибке компиляции, , поскольку арифметическое выражение в правой части оператора присваивания по умолчанию оценивается как int.

short z = x + y;   // Error: no conversion from int to short

Чтобы исправить эту проблему, используйте приведение:

short z = (short)(x + y);   // OK: explicit conversion

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

int m = x + y;
long n = x + y;

Хороший дополнительный вопрос:

"почему арифметическое выражение в правой части оператора присваивания по умолчанию равно int"?

Первый ответ можно найти в:

Классификация и формальная проверка складывания целочисленных констант

Спецификация языка Java точно определяет, как должны представляться целые числа и как должны оцениваться целочисленные арифметические выражения . Это важное свойство Java, так как этот язык программирования был разработан для использования в распределенных приложениях в Интернете. Требуется, чтобы программа на Java выдавала один и тот же результат независимо от того, на каком компьютере его выполняла .

Напротив, С (и большинство широко используемых императивов и объектно-ориентированные языки программирования) более небрежны и оставляют открытыми многие важные характеристики. Намерение за этим неточным языком спецификация понятна. Одни и те же программы на Си должны работать на 16-битной, 32-битная или даже 64-битная архитектура путем создания целочисленной арифметики исходные программы с арифметическими операциями, встроенными в целевой процессор. Это приводит к гораздо более эффективному коду, потому что он может использовать доступный машинные операции напрямую. Пока целочисленные вычисления имеют дело только если числа «достаточно малы», несоответствия не возникнут.

В этом смысле целочисленная арифметика C является заполнителем, который не определен точно спецификацией языка программирования, но только полностью определяется путем определения целевой машины.

Java точно определяет, как представлены целые числа и как должна вычисляться целочисленная арифметика.

      Java Integers
--------------------------
Signed         |  Unsigned
--------------------------
long  (64-bit) |
int   (32-bit) |
short (16-bit) |  char (16-bit)
byte  (8-bit)  |

Char - единственный целочисленный тип без знака. Его значения представляют символы Unicode, от \u0000 до \uffff, то есть от 0 до 2 16 -1.

Если у целочисленного оператора есть операнд типа long, то другой операнд также преобразуется в тип long. В противном случае операция выполняется над операндами типа int, при необходимости более короткие операнды преобразуются в int . Правила конвертации точно указаны.

[Из электронных заметок по теоретической информатике 82 № 2 (2003)
Blesner-Blech-COCV 2003: Сабина ГЛЕСНЕР , Ян Олаф БЛЕХ,
Fakultät für Informatik,
Университет Карлсруэ
Карлсруэ, Германия]

17 голосов
/ 25 января 2009

РЕДАКТИРОВАТЬ: Хорошо, теперь мы знаем, что это Java ...

Раздел 4.2.2 Спецификации языка Java сообщает:

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

[...]

Числовые операторы, в результате которых в значении типа int или long: [...] Аддитивные операторы + и - (§15.18)

Другими словами, это похоже на C # - оператор сложения (при применении к целочисленным типам) всегда приводит только к int или long, поэтому вам необходимо привести приведение к переменной short.

Оригинальный ответ (C #)

В C # (вы не указали язык, поэтому я предполагаю), единственные операторы сложения для примитивных типов:

int operator +(int x, int y);
uint operator +(uint x, uint y);
long operator +(long x, long y);
ulong operator +(ulong x, ulong y);
float operator +(float x, float y);
double operator +(double x, double y);

Это в спецификации C # 3.0, раздел 7.7.4. Кроме того, десятичное сложение определяется:

decimal operator +(decimal x, decimal y);

(Добавление перечисления, конкатенация строк и комбинация делегатов также определены здесь.)

Как видите, оператора short operator +(short x, short y) нет - поэтому оба операнда неявно преобразуются в int, и используется форма int. Это означает, что результатом является выражение типа "int", следовательно, необходимо привести.

16 голосов
/ 25 января 2009

В C # и Java арифметическое выражение в правой части присваивания по умолчанию оценивается как int. Вот почему вам нужно вернуться к короткому, потому что не существует неявного преобразования формы int в короткое по понятным причинам.

7 голосов
/ 25 января 2009

Учитывая, что на вопрос "почему по умолчанию по умолчанию" нет ответа ...

Во-первых, «по умолчанию» не совсем правильный термин (хотя и достаточно близко). Как отмечает VonC, выражение, состоящее из целых и длинных, будет иметь длинный результат. И операция, состоящая из int / logs и double, будет иметь двойной результат. Компилятор переносит условия выражения к любому типу, обеспечивающему больший диапазон и / или точность в результате (типы с плавающей запятой, как предполагается, имеют больший диапазон и точность, чем целочисленные, хотя вы теряете точность, конвертируя большие длинные в двойные). 1003 *

Одно предостережение заключается в том, что эта акция происходит только на тех условиях, которые в ней нуждаются. Таким образом, в следующем примере подвыражение 5/4 использует только целочисленные значения и выполняется с использованием целочисленной математики, даже если общее выражение содержит двойное число. Результат не тот, который вы могли бы ожидать ...

(5/4) * 1000.0

ОК, так почему байт и короткое слово переводятся в int? Без каких-либо ссылок, чтобы поддержать меня, это из-за практичности: количество байт-кодов ограничено.

«Байт-код», как следует из его названия, использует один байт для указания операции. Например, iadd , который добавляет два целых числа. В настоящее время определены 205 кодов операций , а целочисленная математика занимает 18 для каждого типа (т. Е. Всего 36 между целым и длинным), не считая операторов преобразования.

Если короткий и каждый байт имеет свой собственный набор кодов операций, вы будете на 241, ограничивая способность JVM расширяться. Как я уже сказал, никаких упоминаний, подтверждающих это, нет, но я подозреваю, что Гослинг и др. Сказали: «Как часто люди на самом деле используют шорты?» С другой стороны, продвижение байта до int приводит к этому не столь чудесному эффекту (ожидаемый ответ - 96, фактический - -16):

byte x = (byte)0xC0;
System.out.println(x >> 2);
5 голосов
/ 25 января 2009

Какой язык вы используете?

Многие языки на основе C имеют правило, что любое математическое выражение выполняется в размере int или больше. Из-за этого, после добавления двух шортов, результат будет иметь тип int. Это вызывает необходимость в приведении.

2 голосов
/ 18 мая 2016

Java всегда использует как минимум 32-битные значения для расчетов. Это связано с 32-битной архитектурой, которая была распространена в 1995 году, когда была представлена ​​Java. Размер регистра в ЦП составлял 32 бита, и арифметико-логическое устройство принимало 2 числа длины регистра процессора. Таким образом, процессор был оптимизирован для таких значений.

По этой причине все типы данных, которые поддерживают арифметические операции и имеют менее 32 бит, преобразуются в int (32 бит), как только вы используете их для вычислений.

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

1 голос
/ 19 января 2017

AFAIS, никто не упоминает об использовании final для этого. Если вы измените свой последний пример и определите переменные a и b как final переменные, то компилятор уверен , что их сумма, значение 5, может быть присвоено переменная типа byte, без потери точности. В этом случае компилятор хорош назначить сумму a и b c. Вот модифицированный код:

final byte a = 2;
final byte b = 3;
byte c = a + b;
1 голос
/ 26 сентября 2014

Любой тип данных ниже «int» (кроме логического) неявно преобразуется в «int».

В вашем случае:

short a = 2;
short b = 3;
short c = a + b;

Результат (a + b) неявно преобразуется в int. И теперь вы назначаете его на «короткий». Так что вы получаете ошибку.

short, byte, char - для всех этих ошибок мы получим ту же ошибку.

1 голос
/ 02 мая 2010

В Java каждое числовое выражение вроде:

anyPrimitive zas = 1;
anyPrimitive bar = 3;
?? x = zas  + bar 

x всегда будет иметь значение по крайней мере int или long, если один из элементов сложения был long.

Но есть некоторые причуды

byte a = 1; // 1 is an int, but it won't compile if you use a variable
a += 2; // the shortcut works even when 2 is an int
a++; // the post and pre increment operator work
0 голосов
/ 30 января 2009

Я хотел бы добавить что-то, на что не было указано. Java не учитывает значения, которые вы дали переменным (2 и 3) в ...

короткий а = 2; короткий b = 3; короткий c = a + b;

Итак, насколько Java знает, вы могли бы сделать это ...

короткий а = 32767; короткий b = 32767; короткий c = a + b;

Что бы выходило за пределы диапазона short, оно автоматически помещает результат в int, потому что «возможно», что результат будет больше, чем short, но не больше, чем int. Int был выбран в качестве «по умолчанию», потому что в основном большинство людей не будут жестко кодировать значения выше 2 147 483 647 или ниже -2 147 483 648

...