Java Language
Примитивные типы данных
Поиск…
Вступление
byte
, short
, int
, long
, char
, boolean
, float
и double
- это типы, которые хранят большинство исходных числовых данных в Java-программах.
Синтаксис
int aInt = 8; // Определяющая (числовая) часть этого объявления int называется литералом.
int hexInt = 0x1a; // = 26; Вы можете определить литералы с шестнадцатеричными значениями с префиксом 0x .
int binInt = 0b11010; // = 26; Вы также можете определить бинарные литералы; с префиксом 0b .
long goodLong = 10000000000L; // По умолчанию целочисленные литералы имеют тип int. Добавив L в конец литерала, вы сообщаете компилятору, что литерал длинный. Без этого компилятор будет вызывать ошибку «Целое число слишком большое».
double aDouble = 3,14; // Литералы с плавающей запятой по умолчанию имеют тип double.
float aFloat = 3.14F; // По умолчанию этот литерал был бы двойным (и вызвал ошибку «Несовместимые типы»), но, добавив F, мы скажем компилятору, что это float.
замечания
Java имеет 8 примитивных типов данных , а именно: boolean
, byte
, short
, char
, int
, long
, float
и double
. (Все остальные типы являются ссылочными типами, включая все типы массивов и встроенные типы объектов / классы, которые имеют особое значение на языке Java, например String
, Class
и Throwable
и его подклассы).
Результат всех операций (сложение, вычитание, умножение и т. Д.) В примитивном типе - это, по меньшей мере, int
, поэтому добавление short
в short
вызывает int
, как и добавление byte
в byte
, или char
для char
, Если вы хотите присвоить результат этого значения значению того же типа, вы должны его бросить. например
byte a = 1;
byte b = 2;
byte c = (byte) (a + b);
Неисполнение операции приведет к ошибке компиляции.
Это связано со следующей частью Java Language Spec, §2.11.1 :
Компилятор кодирует нагрузки буквенных значений
byte
типов иshort
с помощью инструкций Java Virtual Machine, которые подписывают эти значения до значений типаint
во время компиляции или времени выполнения. Загрузка значений букв типовboolean
иchar
кодируется с использованием инструкций, которые нулевым образом расширяют литерал до значения типаint
во время компиляции или времени выполнения. [..]. Таким образом, большинство операций над значениями фактических типовboolean
,byte
,char
иshort
корректно выполняются инструкциями, действующими на значения вычислительного типаint
.
Причина этого также указана в этом разделе:
Учитывая однобайтовый размер кода операции Java Virtual Machine, типы кодирования в opcodes оказывают давление на дизайн своего набора команд. Если каждая типизированная команда поддерживает все типы данных во время выполнения Java Virtual Machine, будет больше инструкций, чем может быть представлено в
byte
. [...] Отдельные инструкции могут использоваться для преобразования между неподдерживаемыми и поддерживаемыми типами данных по мере необходимости.
Int примитив
Примитивный тип данных, такой как int
содержит значения непосредственно в переменной, которая его использует, между тем переменная, которая была объявлена с использованием Integer
содержит ссылку на значение.
Согласно java API : «Класс Integer обертывает значение примитивного типа int в объекте. Объект типа Integer содержит одно поле, тип которого является int».
По умолчанию int
представляет собой 32-разрядное целое число со знаком. Он может хранить минимальное значение -2 31 и максимальное значение 2 31 - 1.
int example = -42;
int myInt = 284;
int anotherInt = 73;
int addedInts = myInt + anotherInt; // 284 + 73 = 357
int subtractedInts = myInt - anotherInt; // 284 - 73 = 211
Если вам нужно сохранить номер за пределами этого диапазона, следует использовать его в качестве long
. Превышение диапазона значений int
приводит к переполнению целых чисел, в результате чего значение, превышающее диапазон, будет добавлено к противоположному сайту диапазона (положительное становится отрицательным и наоборот). Значение равно ((value - MIN_VALUE) % RANGE) + MIN_VALUE
или ((value + 2147483648) % 4294967296) - 2147483648
int demo = 2147483647; //maximum positive integer
System.out.println(demo); //prints 2147483647
demo = demo + 1; //leads to an integer overflow
System.out.println(demo); // prints -2147483648
Максимальное и минимальное значения int
можно найти по адресу:
int high = Integer.MAX_VALUE; // high == 2147483647
int low = Integer.MIN_VALUE; // low == -2147483648
Значение по умолчанию для int
равно 0
int defaultInt; // defaultInt == 0
Короткий примитив
short
является 16-разрядное целое число со знаком. Он имеет минимальное значение -2 15 (-32,768), а максимальное значение составляет 2 15 -1 (32 767)
short example = -48;
short myShort = 987;
short anotherShort = 17;
short addedShorts = (short) (myShort + anotherShort); // 1,004
short subtractedShorts = (short) (myShort - anotherShort); // 970
Максимальные и минимальные значения short
можно найти по адресу:
short high = Short.MAX_VALUE; // high == 32767
short low = Short.MIN_VALUE; // low == -32768
Значение по умолчанию short
равно 0
short defaultShort; // defaultShort == 0
Длинный примитив
По умолчанию long
- это 64-разрядное целое число со знаком (в Java 8 оно может быть либо подписано, либо без знака). Подписано, оно может хранить минимальное значение -2 63 и максимальное значение 2 63 - 1, а без знака оно может хранить минимальное значение 0 и максимальное значение 2 64 - 1
long example = -42;
long myLong = 284;
long anotherLong = 73;
//an "L" must be appended to the end of the number, because by default,
//numbers are assumed to be the int type. Appending an "L" makes it a long
//as 549755813888 (2 ^ 39) is larger than the maximum value of an int (2^31 - 1),
//"L" must be appended
long bigNumber = 549755813888L;
long addedLongs = myLong + anotherLong; // 284 + 73 = 357
long subtractedLongs = myLong - anotherLong; // 284 - 73 = 211
Максимальное и минимальное значения long
можно найти по адресу:
long high = Long.MAX_VALUE; // high == 9223372036854775807L
long low = Long.MIN_VALUE; // low == -9223372036854775808L
Значение по умолчанию long
равно 0L
long defaultLong; // defaultLong == 0L
Примечание: буква «L», добавленная в конце long
литерала, нечувствительна к регистру, однако хорошей практикой является использование капитала, поскольку ее легче отличить от цифры один:
2L == 2l; // true
Предупреждение: Java кэширует объекты Integer объектов из диапазона от -128 до 127. Объяснение здесь объясняется: https://blogs.oracle.com/darcy/entry/boxing_and_caches_integer_valueof
Следующие результаты можно найти:
Long val1 = 127L;
Long val2 = 127L;
System.out.println(val1 == val2); // true
Long val3 = 128L;
Long val4 = 128L;
System.out.println(val3 == val4); // false
Чтобы правильно сравнить значения 2 объекта Long, используйте следующий код (начиная с Java 1.7):
Long val3 = 128L;
Long val4 = 128L;
System.out.println(Objects.equal(val3, val4)); // true
Сравнение примитива long long с Object long не приведет к ложному отрицанию, сравнив 2 объекта с.
Булевский примитив
boolean
может сохранять одно из двух значений: true
или false
boolean foo = true;
System.out.println("foo = " + foo); // foo = true
boolean bar = false;
System.out.println("bar = " + bar); // bar = false
boolean notFoo = !foo;
System.out.println("notFoo = " + notFoo); // notFoo = false
boolean fooAndBar = foo && bar;
System.out.println("fooAndBar = " + fooAndBar); // fooAndBar = false
boolean fooOrBar = foo || bar;
System.out.println("fooOrBar = " + fooOrBar); // fooOrBar = true
boolean fooXorBar = foo ^ bar;
System.out.println("fooXorBar = " + fooXorBar); // fooXorBar = true
Значение по умолчанию для boolean
равно false
boolean defaultBoolean; // defaultBoolean == false
Байт-примитив
byte
представляет собой 8-разрядное целое число со знаком. Он может хранить минимальное значение -2 7 (-128), а максимальное значение 2 7 - 1 (127)
byte example = -36;
byte myByte = 96;
byte anotherByte = 7;
byte addedBytes = (byte) (myByte + anotherByte); // 103
byte subtractedBytes = (byte) (myBytes - anotherByte); // 89
Максимальное и минимальное значения byte
можно найти по адресу:
byte high = Byte.MAX_VALUE; // high == 127
byte low = Byte.MIN_VALUE; // low == -128
Значение по умолчанию byte
равно 0
byte defaultByte; // defaultByte == 0
Поплавковый примитив
float
- это 32-битное число с плавающей запятой IEEE 754 с одной точностью. По умолчанию десятичные знаки интерпретируются как двойные. Чтобы создать float
, просто добавьте f
в десятичный литерал.
double doubleExample = 0.5; // without 'f' after digits = double
float floatExample = 0.5f; // with 'f' after digits = float
float myFloat = 92.7f; // this is a float...
float positiveFloat = 89.3f; // it can be positive,
float negativeFloat = -89.3f; // or negative
float integerFloat = 43.0f; // it can be a whole number (not an int)
float underZeroFloat = 0.0549f; // it can be a fractional value less than 0
Поплавки обрабатывают пять общих арифметических операций: сложение, вычитание, умножение, деление и модуль.
Примечание. В результате ошибок с плавающей запятой могут незначительно отличаться. Некоторые результаты были округлены для ясности и удобочитаемости (т. Е. Напечатанный результат примера добавления был фактически 34.600002).
// addition
float result = 37.2f + -2.6f; // result: 34.6
// subtraction
float result = 45.1f - 10.3f; // result: 34.8
// multiplication
float result = 26.3f * 1.7f; // result: 44.71
// division
float result = 37.1f / 4.8f; // result: 7.729166
// modulus
float result = 37.1f % 4.8f; // result: 3.4999971
Из-за того, что хранятся числа с плавающей точкой (т. Е. В двоичной форме), многие числа не имеют точного представления.
float notExact = 3.1415926f;
System.out.println(notExact); // 3.1415925
Хотя использование float
подходит для большинства приложений, для хранения точных представлений десятичных чисел (например, денежных сумм) или чисел, где требуется более высокая точность, не следует использовать float
или double
. Вместо этого следует использовать класс BigDecimal
.
Значение по умолчанию для float
равно 0.0f .
float defaultFloat; // defaultFloat == 0.0f
float
точностью до ошибки составляет 1 из 10 миллионов.
Примечание: Float.POSITIVE_INFINITY
, Float.NEGATIVE_INFINITY
, Float.NaN
- значения с float
. NaN
означает результаты операций, которые невозможно определить, например, деление 2 бесконечных значений. Кроме того, 0f
и -0f
различны, но ==
дает true:
float f1 = 0f;
float f2 = -0f;
System.out.println(f1 == f2); // true
System.out.println(1f / f1); // Infinity
System.out.println(1f / f2); // -Infinity
System.out.println(Float.POSITIVE_INFINITY / Float.POSITIVE_INFINITY); // NaN
Двойной примитив
double
- это 64-битное число с плавающей запятой IEEE 754 с двойной точностью.
double example = -7162.37;
double myDouble = 974.21;
double anotherDouble = 658.7;
double addedDoubles = myDouble + anotherDouble; // 315.51
double subtractedDoubles = myDouble - anotherDouble; // 1632.91
double scientificNotationDouble = 1.2e-3; // 0.0012
Из-за того, что хранятся числа с плавающей запятой, многие номера не имеют точного представления.
double notExact = 1.32 - 0.42; // result should be 0.9
System.out.println(notExact); // 0.9000000000000001
Хотя для большинства приложений используется double
для хранения точных чисел, таких как валюта, не следует использовать ни float
ни double
. Вместо этого следует использовать класс BigDecimal
Значение по умолчанию double
равно 0.0d
public double defaultDouble; // defaultDouble == 0.0
Примечание: Double.POSITIVE_INFINITY
, Double.NEGATIVE_INFINITY
, Double.NaN
- double
значения. NaN
означает результаты операций, которые невозможно определить, например, деление 2 бесконечных значений. Кроме того, 0d
и -0d
различны, но ==
-0d
true:
double d1 = 0d;
double d2 = -0d;
System.out.println(d1 == d2); // true
System.out.println(1d / d1); // Infinity
System.out.println(1d / d2); // -Infinity
System.out.println(Double.POSITIVE_INFINITY / Double.POSITIVE_INFINITY); // NaN
Первоначальный символ
char
может хранить один 16-разрядный символ Юникода. Символьный литерал заключен в одинарные кавычки
char myChar = 'u';
char myChar2 = '5';
char myChar3 = 65; // myChar3 == 'A'
Он имеет минимальное значение \u0000
(0 в десятичном представлении, также называемое нулевым символом ) и максимальное значение \uffff
(65,535).
Значением по умолчанию char
является \u0000
.
char defaultChar; // defaultChar == \u0000
Чтобы определить значение символа «char '
использовать escape-последовательность (символ, которому предшествует обратная косая черта):
char singleQuote = '\'';
Существуют также другие escape-последовательности:
char tab = '\t';
char backspace = '\b';
char newline = '\n';
char carriageReturn = '\r';
char formfeed = '\f';
char singleQuote = '\'';
char doubleQuote = '\"'; // escaping redundant here; '"' would be the same; however still allowed
char backslash = '\\';
char unicodeChar = '\uXXXX' // XXXX represents the Unicode-value of the character you want to display
Вы можете объявить char
любого символа Юникода.
char heart = '\u2764';
System.out.println(Character.toString(heart)); // Prints a line containing "❤".
Также можно добавить char
. например, для повторения каждой строчной буквы, вы можете сделать следующее:
for (int i = 0; i <= 26; i++) {
char letter = (char) ('a' + i);
System.out.println(letter);
}
Представление отрицательного значения
Java и большинство других языков хранят отрицательные целые числа в представлении , обозначаемом дополнением 2 .
Для уникального двоичного представления типа данных с использованием n
бит значения кодируются следующим образом:
Наименее значимые n-1
биты сохраняют положительное целое число x
в интегральном представлении. Наиболее значимое значение хранит бит с значением s
. Значение, представленное этими битами, равно
x - s * 2 n-1
т.е. если самый старший бит равен 1, то значение, которое просто на 1 больше, чем число, которое вы могли бы представить с другими битами ( 2 n-2 + 2 n-3 + ... + 2 1 + 2 0 = 2 n-1 - 1
), что дает уникальное двоичное представление для каждого значения от - 2 n-1 (s = 1; x = 0) до 2 n-1 - 1 (s = 0; x = 2 n-1 - 1).
Это также имеет хороший побочный эффект, что вы можете добавить двоичные представления, как если бы они были положительными двоичными числами:
v1 = x1 - s1 * 2n-1 v2 = x2 - s2 * 2n-1
s1 | s2 | переполнение x1 + x2 | результат добавления |
---|---|---|---|
0 | 0 | нет | x1 + x2 = v1 + v2 |
0 | 0 | да | слишком большой, чтобы быть представленным типом данных (переполнение) |
0 | 1 | нет | x1 + x2 - 2n-1 = x1 + x2 - s2 * 2n-1 |
0 | 1 | да | (x1 + x2) mod 2n-1 = x1 + x2 - 2n-1 |
1 | 0 | * | см. выше (сменные слагаемые) |
1 | 1 | нет | слишком мал, чтобы быть представленным типом данных (x1 + x2 - 2 n <-2 n-1 , underflow) |
1 | 1 | да | (x1 + x2) mod 2n-1 - 2n-1 = (x1 + x2 - 2n-1) - 2n-1 |
Обратите внимание, что этот факт упрощает поиск двоичного представления аддитивного обратного (т. Е. Отрицательного значения):
Обратите внимание, что добавление побитового дополнения к числу приводит к тому, что все биты равны 1. Теперь добавьте 1, чтобы сделать переполнение значения, и вы получите нейтральный элемент 0 (все биты 0).
Таким образом, отрицательное значение числа i
можно вычислить, используя (игнорируя возможную рекламу для int
здесь)
(~i) + 1
Пример: принятие отрицательного значения 0 ( byte
):
Результатом отрицания 0
является 11111111
. Добавление 1 дает значение 100000000
(9 бит). Поскольку byte
может хранить только 8 бит, самое левое значение усекается, а результат равен 00000000
оригинал | Процесс | Результат |
---|---|---|
0 (00000000) | сводить на нет | -0 (11111111) |
11111111 | Добавить 1 в двоичный | 100000000 |
100000000 | Усекать до 8 бит | 00000000 (-0 равно 0) |
Потребление памяти примитивов против бокс-примитивов
Примитивный | В штучной упаковке | Размер памяти примитива / в штучной упаковке |
---|---|---|
логический | логический | 1 байт / 16 байт |
байт | Байт | 1 байт / 16 байт |
короткая | короткий | 2 байта / 16 байт |
голец | голец | 2 байта / 16 байт |
ИНТ | целое число | 4 байта / 16 байт |
долго | Долго | 8 байт / 16 байт |
поплавок | терка | 4 байта / 16 байт |
двойной | двойной | 8 байт / 16 байт |
Объектам в штучной упаковке всегда требуется 8 байтов для управления типом и памятью, а так как размер объектов всегда кратен 8, для всех типов в штучной упаковке требуется всего 16 байтов . Кроме того , каждое использование объекта в штучной упаковке влечет за собой хранение ссылки, которая учитывает еще 4 или 8 байтов, в зависимости от параметров JVM и JVM.
В операциях с интенсивным использованием данных потребление памяти может существенно повлиять на производительность. Потребление памяти растет еще больше при использовании массивов: для массива float[5]
требуется только 32 байта; тогда как Float[5]
хранящий 5 различных ненулевых значений, потребует всего 112 байтов (на 64-разрядном без сжатых указателей, это увеличивается до 152 байт).
Вложенные кеширование значений
Косвенные накладные расходы в штучной упаковке могут быть в некоторой степени смягчены кэшами в штучной упаковке. Некоторые из типов в штучной упаковке реализуют кеш экземпляров. Например, по умолчанию класс Integer
будет кэшировать экземпляры для представления чисел в диапазоне от -128
до +127
. Однако это не снижает дополнительные затраты, связанные с дополнительной памятью.
Если вы создаете экземпляр типа boxed либо с помощью autoboxing, либо путем вызова статического метода valueOf(primitive)
, система времени выполнения попытается использовать кешированное значение. Если ваше приложение использует множество значений в кэше, то это может существенно снизить штраф за использование ящиков в коробке. Конечно, если вы создаете экземпляры экземпляров в штучной упаковке «вручную», лучше использовать valueOf
вместо new
. ( new
операция всегда создает новый экземпляр.) Если, однако, большинство ваших значений не находятся в кешированном диапазоне, быстрее можно вызвать new
и сохранить поиск кеша.
Преобразование примитивов
В Java мы можем конвертировать между целыми значениями и значениями с плавающей запятой. Кроме того, поскольку каждый символ соответствует числу в кодировке Unicode, типы char
могут быть преобразованы в типы и с целыми числами и с плавающей точкой. boolean
- единственный примитивный тип данных, который не может быть преобразован в какой-либо другой примитивный тип данных.
Существует два типа конверсий: расширение конверсии и сужение конверсии .
Расширяющееся преобразование - это когда значение одного типа данных преобразуется в значение другого типа данных, который занимает больше битов, чем первый. В этом случае нет проблемы потери данных.
Соответственно, сужение преобразования - это когда значение одного типа данных преобразуется в значение другого типа данных, который занимает меньше битов, чем первый. В этом случае может произойти потеря данных.
Java автоматически расширяет конверсии . Но если вы хотите выполнить сужение конверсии (если вы уверены, что потеря данных не произойдет), вы можете заставить Java выполнить преобразование с использованием языковой конструкции, известной как cast
.
Расширение конверсии:
int a = 1;
double d = a; // valid conversion to double, no cast needed (widening)
Сужение конверсии:
double d = 18.96
int b = d; // invalid conversion to int, will throw a compile-time error
int b = (int) d; // valid conversion to int, but result is truncated (gets rounded down)
// This is type-casting
// Now, b = 18
Примитивные типы
Таблица, показывающая диапазон размеров и значений всех примитивных типов:
тип данных | числовое представление | диапазон значений | значение по умолчанию |
---|---|---|---|
логический | н / | ложный и истинный | ложный |
байт | 8-разрядная подписка | -2 7 до 2 7 - 1 | 0 |
От -128 до +127 | |||
короткая | 16-разрядная подписка | -2 15 - 2 15 - 1 | 0 |
-32,768 до +32,767 | |||
ИНТ | 32-разрядная подписка | -2 31 до 2 31 - 1 | 0 |
-2,147,483,648 до +2,147,483,647 | |||
долго | 64-битная подпись | -2 63 до 2 63 - 1 | 0L |
-9,223,372,036,854,775,808 - 9,223,372,036,854,775,807 | |||
поплавок | 32-битная с плавающей запятой | 1.401298464e-45 до 3.402823466e + 38 (положительный или отрицательный) | 0.0f |
двойной | 64-битная плавающая точка | 4.94065645841246544e-324d до 1.79769313486231570e + 308d (положительный или отрицательный) | 0.0d |
голец | 16-разрядный беззнаковый | 0 до 2 16 - 1 | 0 |
0 до 65535 |
Заметки:
- Спецификация языка Java предусматривает, что подписанные интегральные типы (
byte
черезlong
) используют двоичное представление двухкомпонента, а типы с плавающей точкой используют стандартные двоичные представления с плавающей точкой IEE 754. - Java 8 и более поздние версии предоставляют методы для выполнения беззнаковых арифметических операций по
int
иlong
. Хотя эти методы позволяют программе обрабатывать значения соответствующих типов как неподписанные, типы остаются подписанными типами. - Наименьшая плавающая точка, показанная выше, является субнормальной ; т.е. они имеют меньшую точность, чем нормальное значение. Наименьшие нормальные числа: 1.175494351e-38 и 2.2250738585072014e-308
-
char
обычно представляет собой блок кода Unicode / UTF-16. - Хотя
boolean
содержит только один бит информации, его размер в памяти варьируется в зависимости от реализации виртуальной машины Java (см. Boolean type ).