Примитивный тип "короткий" - литье в Java

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

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

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

компилятор не хочет компилировать - он говорит, что он "не может преобразовать из int в short" и предлагает сделать команду cast 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.

Ответ 1

Как объясняется в short С# (но также и для других компиляторов языка, например 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

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

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

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

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

Хороший следующий вопрос:

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

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

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

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

Напротив, C (и большинство широко используемых императивов и объектно-ориентированные языки программирования) более неряшлив и оставляет многие важные характеристики открытыми. Замысел этого неточного языка спецификация понятна. Те же программы на C должны работать на 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: Sabine GLESNER, Jan Olaf BLECH,
Fakultät für Informatik,
Universität Karlsruhe
Карлсруэ, Германия]

Ответ 2

EDIT: Хорошо, теперь мы знаем это Java...

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

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

[...]

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

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

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

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

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);

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

decimal operator +(decimal x, decimal y);

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

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

Ответ 3

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

Ответ 4

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

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

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

(5/4) * 1000.0

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

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

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

byte x = (byte)0xC0;
System.out.println(x >> 2);

Ответ 5

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

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

Ответ 6

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

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

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

Ответ 7

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

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

x всегда будет иметь по крайней мере значение int или 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

Ответ 8

Любой тип данных witch меньше, чем "int" (кроме булева), неявно преобразуется в "int".

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

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

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

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

Ответ 9

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

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

Ответ 10

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

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

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

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

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