Java Language
Tipos de datos primitivos
Buscar..
Introducción
byte
, short
, int
, long
, char
, boolean
, float
y double
son los tipos que almacenan la mayoría de los datos numéricos sin procesar en los programas Java.
Sintaxis
int aInt = 8; // La parte definitoria (número) de esta declaración int se llama un literal.
int hexInt = 0x1a; // = 26; Puedes definir literales con valores hexadecimales prefijados con 0x .
int binInt = 0b11010; // = 26; También puedes definir literales binarios; prefijado con 0b .
long goodLong = 10000000000L; // Por defecto, los literales enteros son de tipo int. Al agregar la L al final del literal, le está diciendo al compilador que el literal es largo. Sin esto, el compilador arrojaría un error de "Número entero demasiado grande".
doble aDouble = 3.14; // Los literales de punto flotante son de tipo doble de forma predeterminada.
flotar aFloat = 3.14F; // Por defecto, este literal habría sido un doble (y causó un error de "Tipos incompatibles"), pero al agregar una F le decimos al compilador que es un flotador.
Observaciones
Java tiene 8 tipos de datos primitivos , a saber, boolean
, byte
, short
, char
, int
, long
, float
y double
. (Todos los demás tipos son tipos de referencia . Esto incluye todos los tipos de matriz y los tipos / clases de objetos integrados que tienen un significado especial en el lenguaje Java; por ejemplo, String
, Class
y Throwable
y sus subclases).
El resultado de todas las operaciones (suma, resta, multiplicación, etc.) en un tipo primitivo es al menos un int
, por lo que sumar un short
a un short
produce un int
, al igual que agregar un byte
a un byte
, o un char
a un char
. Si desea asignar el resultado de eso a un valor del mismo tipo, debe convertirlo. p.ej
byte a = 1;
byte b = 2;
byte c = (byte) (a + b);
No lanzar la operación dará como resultado un error de compilación.
Esto se debe a la siguiente parte de la especificación del lenguaje Java, §2.11.1 :
Un compilador codifica cargas de valores literales de tipos
byte
yshort
usando instrucciones de la Máquina Virtual Java que extienden sus valores de signo a valores de tipoint
en tiempo de compilación o tiempo de ejecución. Las cargas de valores literales de los tiposboolean
ychar
se codifican utilizando instrucciones que extienden el literal literalmente a un valor de tipoint
en tiempo de compilación o tiempo de ejecución. [..]. Por lo tanto, la mayoría de las operaciones en valores de tipos realesboolean
,byte
,char
yshort
se realizan correctamente mediante instrucciones que operan en valores de tipo computacionalint
.
La razón detrás de esto también se especifica en esa sección:
Dado el tamaño del código de operación de un byte de la Máquina Virtual Java, los tipos de codificación en códigos de operación ejercen presión sobre el diseño de su conjunto de instrucciones. Si cada instrucción escrita admitiera todos los tipos de datos en tiempo de ejecución de la Máquina Virtual Java, habría más instrucciones de las que podrían representarse en un
byte
. [...] Se pueden usar instrucciones separadas para convertir entre tipos de datos no compatibles y compatibles según sea necesario.
El primitivo int
Un tipo de datos primitivos como int
contiene valores directamente en la variable que lo está utilizando, mientras que una variable que se declaró utilizando Integer
contiene una referencia al valor.
De acuerdo con la API de Java : "La clase Integer ajusta un valor del tipo primitivo int en un objeto. Un objeto de tipo Integer contiene un campo único cuyo tipo es int".
Por defecto, int
es un entero con signo de 32 bits. Puede almacenar un valor mínimo de -2 31 , y un valor máximo de 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
Si necesita almacenar un número fuera de este rango, en long
debe usar long
. Si se excede el rango de valores de int
produce un desbordamiento de enteros, lo que hace que el valor que exceda el rango se agregue al sitio opuesto del rango (positivo se convierte en negativo y viceversa). El valor es ((value - MIN_VALUE) % RANGE) + MIN_VALUE
, o ((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
Los valores máximo y mínimo de int
se pueden encontrar en:
int high = Integer.MAX_VALUE; // high == 2147483647
int low = Integer.MIN_VALUE; // low == -2147483648
El valor predeterminado de un int
es 0
int defaultInt; // defaultInt == 0
El primitivo corto
Un short
es un entero con signo de 16 bits. Tiene un valor mínimo de -2 15 (-32,768), y un valor máximo de 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
Los valores máximo y mínimo de short
se pueden encontrar en:
short high = Short.MAX_VALUE; // high == 32767
short low = Short.MIN_VALUE; // low == -32768
El valor predeterminado de un short
es 0
short defaultShort; // defaultShort == 0
El primitivo largo
De forma predeterminada, long
es un entero con signo de 64 bits (en Java 8, puede ser firmado o sin signo). Firmado, puede almacenar un valor mínimo de -2 63 , y un valor máximo de 2 63 - 1, y sin firmar puede almacenar un valor mínimo de 0 y un valor máximo de 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
Los valores máximo y mínimo de long
se pueden encontrar en:
long high = Long.MAX_VALUE; // high == 9223372036854775807L
long low = Long.MIN_VALUE; // low == -9223372036854775808L
El valor predeterminado de un long
es 0L.
long defaultLong; // defaultLong == 0L
Nota: la letra "L" adjunta al final del literal long
distingue entre mayúsculas y minúsculas, sin embargo, es una buena práctica usar mayúscula, ya que es más fácil distinguirla del dígito uno:
2L == 2l; // true
Advertencia: Java almacena en caché instancias de objetos enteros del rango -128 a 127. El razonamiento se explica aquí: https://blogs.oracle.com/darcy/entry/boxing_and_caches_integer_valueof
Se pueden encontrar los siguientes resultados:
Long val1 = 127L;
Long val2 = 127L;
System.out.println(val1 == val2); // true
Long val3 = 128L;
Long val4 = 128L;
System.out.println(val3 == val4); // false
Para comparar correctamente los valores de 2 objetos largos, use el siguiente código (desde Java 1.7 en adelante):
Long val3 = 128L;
Long val4 = 128L;
System.out.println(Objects.equal(val3, val4)); // true
La comparación de un largo primitivo con un objeto largo no dará como resultado un falso negativo como la comparación de 2 objetos con == hace.
El primitivo booleano
Un boolean
puede almacenar uno de dos valores, ya sea true
o 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
El valor predeterminado de un boolean
es falso
boolean defaultBoolean; // defaultBoolean == false
El byte primitivo
Un byte
es un entero con signo de 8 bits. Puede almacenar un valor mínimo de -2 7 (-128), y un valor máximo de 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
Los valores máximo y mínimo de byte
se pueden encontrar en:
byte high = Byte.MAX_VALUE; // high == 127
byte low = Byte.MIN_VALUE; // low == -128
El valor predeterminado de un byte
es 0
byte defaultByte; // defaultByte == 0
El flotador primitivo
Un float
es un número de punto flotante IEEE 754 de 32 bits de precisión simple. Por defecto, los decimales se interpretan como dobles. Para crear un float
, simplemente agregue una f
al literal decimal.
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
Los flotadores manejan las cinco operaciones aritméticas comunes: suma, resta, multiplicación, división y módulo.
Nota: Lo siguiente puede variar ligeramente como resultado de errores de punto flotante. Algunos resultados se han redondeado con fines de claridad y legibilidad (es decir, el resultado impreso del ejemplo de adición fue en realidad 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
Debido a la forma en que se almacenan los números de punto flotante (es decir, en forma binaria), muchos números no tienen una representación exacta.
float notExact = 3.1415926f;
System.out.println(notExact); // 3.1415925
Si bien el uso de float
está bien para la mayoría de las aplicaciones, no se debe usar float
ni double
para almacenar representaciones exactas de números decimales (como cantidades monetarias), o números donde se requiera mayor precisión. En su lugar, se debe utilizar la clase BigDecimal
.
El valor predeterminado de un float
es 0.0f .
float defaultFloat; // defaultFloat == 0.0f
Un float
es preciso para aproximadamente un error de 1 en 10 millones.
Nota: Float.POSITIVE_INFINITY
, Float.NEGATIVE_INFINITY
, Float.NaN
son valores float
. NaN
significa resultados de operaciones que no se pueden determinar, como dividir 2 valores infinitos. Además, 0f
y -0f
son diferentes, pero ==
produce verdadero:
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
El doble primitivo
Un double
es un número de punto flotante IEEE 754 de doble precisión de 64 bits.
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
Debido a la forma en que se almacenan los números de punto flotante, muchos números no tienen una representación exacta.
double notExact = 1.32 - 0.42; // result should be 0.9
System.out.println(notExact); // 0.9000000000000001
Si bien el uso del double
está bien para la mayoría de las aplicaciones, no se debe usar ni float
ni double
para almacenar números precisos, como la moneda. En su lugar, se debe usar la clase BigDecimal
El valor predeterminado de un double
es 0.0d
public double defaultDouble; // defaultDouble == 0.0
Nota: Double.POSITIVE_INFINITY
, Double.NEGATIVE_INFINITY
, Double.NaN
son valores double
. NaN
significa resultados de operaciones que no se pueden determinar, como dividir 2 valores infinitos. Además, 0d
y -0d
son diferentes, pero ==
produce verdadero:
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
El primitivo char
Un char
puede almacenar un solo carácter Unicode de 16 bits. Un literal de carácter está encerrado entre comillas simples
char myChar = 'u';
char myChar2 = '5';
char myChar3 = 65; // myChar3 == 'A'
Tiene un valor mínimo de \u0000
(0 en la representación decimal, también llamado el carácter nulo ) y un valor máximo de \uffff
(65,535).
El valor predeterminado de un char
es \u0000
.
char defaultChar; // defaultChar == \u0000
Para definir un valor de char of '
se debe utilizar una secuencia de escape (carácter precedido por una barra invertida):
char singleQuote = '\'';
También hay otras secuencias de 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
Puedes declarar un char
de cualquier carácter Unicode.
char heart = '\u2764';
System.out.println(Character.toString(heart)); // Prints a line containing "❤".
También es posible añadir a un char
. Por ejemplo, para iterar en cada letra minúscula, puede hacer lo siguiente:
for (int i = 0; i <= 26; i++) {
char letter = (char) ('a' + i);
System.out.println(letter);
}
Representación de valor negativo
Java y la mayoría de los otros lenguajes almacenan números integrales negativos en una representación llamada notación de complemento a 2 .
Para una representación binaria única de un tipo de datos que utiliza n
bits, los valores se codifican así:
Los bits n-1
menos significativos almacenan un número integral positivo x
en representación integral. El valor más significativo almacena un poco con el valor s
. El valor representado por esos bits es
x - s * 2 n-1
es decir, si el bit más significativo es 1, entonces un valor que es solo 1 mayor que el número que podría representar con los otros bits ( 2 n-2 + 2 n-3 + ... + 2 1 + 2 0 = 2 n-1 - 1
) se resta permitiendo una representación binaria única para cada valor de - 2 n-1 (s = 1; x = 0) a 2 n-1 - 1 (s = 0; x = 2 n-1 - 1).
Esto también tiene el efecto secundario agradable, que puede agregar las representaciones binarias como si fueran números binarios positivos:
v1 = x1 - s1 * 2n-1 v2 = x2 - s2 * 2n-1
s1 | s2 | x1 + x2 desbordamiento | resultado adicional |
---|---|---|---|
0 | 0 | No | x1 + x2 = v1 + v2 |
0 | 0 | Sí | demasiado grande para ser representada con el tipo de datos (desbordamiento) |
0 | 1 | No | x1 + x2 - 2n-1 = x1 + x2 - s2 * 2n-1 |
0 | 1 | Sí | (x1 + x2) mod 2n-1 = x1 + x2 - 2n-1 |
1 | 0 | * | ver arriba (intercambiar sumas) |
1 | 1 | No | demasiado pequeño para ser representado con el tipo de datos (x1 + x2 - 2 n <-2 n-1 ; subflujo) |
1 | 1 | Sí | (x1 + x2) mod 2n-1 - 2n-1 = (x1 + x2 - 2n-1) - 2n-1 |
Tenga en cuenta que este hecho hace que sea fácil encontrar la representación binaria del inverso aditivo (es decir, el valor negativo):
Observe que agregar el complemento bit a bit al número resulta en que todos los bits son 1. Ahora agregue 1 para hacer que el valor se desborde y obtendrá el elemento neutral 0 (todos los bits 0).
Por lo que el valor negativo de un número i
se puede calcular utilizando (ignorando posible promoción a int
aquí)
(~i) + 1
Ejemplo: tomando el valor negativo de 0 ( byte
):
El resultado de negar 0
, es 11111111
. Al sumar 1 se obtiene un valor de 100000000
(9 bits). Debido a que un byte
solo puede almacenar 8 bits, el valor situado más a la izquierda se trunca y el resultado es 00000000
Original | Proceso | Resultado |
---|---|---|
0 (00000000) | Negar | -0 (11111111) |
11111111 | Agrega 1 al binario | 100000000 |
100000000 | Truncar a 8 bits | 00000000 (-0 es igual a 0) |
Consumo de memoria de primitivas vs. primitivas en caja
Primitivo | Tipo de caja | Tamaño de memoria de primitivo / en caja |
---|---|---|
booleano | Booleano | 1 byte / 16 bytes |
byte | Byte | 1 byte / 16 bytes |
corto | Corto | 2 bytes / 16 bytes |
carbonizarse | Carbonizarse | 2 bytes / 16 bytes |
En t | Entero | 4 bytes / 16 bytes |
largo | Largo | 8 bytes / 16 bytes |
flotador | Flotador | 4 bytes / 16 bytes |
doble | Doble | 8 bytes / 16 bytes |
Los objetos en caja siempre requieren 8 bytes para la administración de tipo y memoria, y como el tamaño de los objetos es siempre un múltiplo de 8, todos los tipos en caja requieren un total de 16 bytes . Además , cada uso de un objeto en caja implica almacenar una referencia que representa otros 4 u 8 bytes, según las opciones de JVM y JVM.
En las operaciones de uso intensivo de datos, el consumo de memoria puede tener un gran impacto en el rendimiento. El consumo de memoria aumenta aún más cuando se usan matrices: una matriz float[5]
solo requerirá 32 bytes; mientras que un Float[5]
almacena 5 valores distintos de valores nulos requerirá un total de 112 bytes (en 64 bits sin punteros comprimidos, esto aumenta a 152 bytes).
Cachés de valor en caja
Las sobrecargas de espacio de los tipos encajonados se pueden mitigar hasta cierto punto por los cachés de valores encajonados. Algunos de los tipos en caja implementan un caché de instancias. Por ejemplo, de forma predeterminada, la clase Integer
almacenará en caché las instancias para representar números en el rango de -128
a +127
. Sin embargo, esto no reduce el costo adicional derivado de la indirección de memoria adicional.
Si crea una instancia de un tipo encuadrado ya sea mediante autofijación o llamando al método static valueOf(primitive)
, el sistema de tiempo de ejecución intentará utilizar un valor almacenado en caché. Si su aplicación utiliza muchos valores en el rango que se almacena en la memoria caché, esto puede reducir sustancialmente la penalización de memoria al usar tipos en caja. Ciertamente, si está creando instancias de valor en caja "a mano", es mejor usar valueOf
lugar de new
. (La new
operación siempre crea una nueva instancia). Sin embargo, si la mayoría de sus valores no están en el rango almacenado en la memoria caché, puede ser más rápido llamar new
y guardar la búsqueda de caché.
Primitivas de conversión
En Java, podemos convertir entre valores enteros y valores de punto flotante. Además, dado que cada carácter corresponde a un número en la codificación Unicode, char
tipos se pueden convertir a y desde los tipos de enteros y de coma flotante. boolean
es el único tipo de datos primitivo que no se puede convertir ao desde cualquier otro tipo de datos primitivos.
Hay dos tipos de conversiones: ampliar la conversión y reducir la conversión .
Una conversión de ampliación se produce cuando un valor de un tipo de datos se convierte en un valor de otro tipo de datos que ocupa más bits que el anterior. No hay problema de pérdida de datos en este caso.
En consecuencia, una conversión de reducción se produce cuando un valor de un tipo de datos se convierte en un valor de otro tipo de datos que ocupa menos bits que el anterior. La pérdida de datos puede ocurrir en este caso.
Java realiza ampliaciones de conversiones automáticamente. Pero si desea realizar una conversión de restricción (si está seguro de que no se produzcan pérdidas de datos), entonces se puede forzar Java para realizar la conversión usando una construcción del lenguaje conocido como un cast
.
Ampliación de la conversión:
int a = 1;
double d = a; // valid conversion to double, no cast needed (widening)
Reducción de la conversión:
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
Tipos primitivos Cheatsheet
Tabla que muestra el rango de tamaño y valores de todos los tipos primitivos:
tipo de datos | representación numérica | rango de valores | valor por defecto |
---|---|---|---|
booleano | n / A | falso y verdadero | falso |
byte | Firmado de 8 bits | -2 7 a 2 7 - 1 | 0 |
-128 a +127 | |||
corto | Firmado de 16 bits | -2 15 a 2 15 - 1 | 0 |
-32,768 a +32,767 | |||
En t | 32 bits firmado | -2 31 a 2 31 - 1 | 0 |
-2,147,483,648 a +2,147,483,647 | |||
largo | Firmado de 64 bits | -2 63 a 2 63 - 1 | 0L |
-9,223,372,036,854,775,808 a 9,223,372,036,854,775,807 | |||
flotador | Punto flotante de 32 bits | 1.401298464e-45 a 3.402823466e + 38 (positivo o negativo) | 0.0F |
doble | Punto flotante de 64 bits | 4.94065645841246544e-324d a 1.79769313486231570e + 308d (positivo o negativo) | 0.0D |
carbonizarse | 16 bits sin firmar | 0 a 2 16 - 1 | 0 |
0 a 65,535 |
Notas:
- Los mandatos de la Especificación del lenguaje Java que los tipos integrales firmados (
byte
along
) usan una representación binaria de complemento a dos, y los tipos de punto flotante usan representaciones binarias estándar de punto flotante IEE 754. - Java 8 y versiones posteriores proporcionan métodos para realizar operaciones aritméticas no firmadas en
int
ylong
. Si bien estos métodos permiten que un programa trate los valores de los tipos respectivos como no firmados, los tipos siguen siendo tipos con signo. - El punto flotante más pequeño que se muestra arriba es subnormal ; Es decir, tienen menos precisión que un valor normal . Los números normales más pequeños son 1.175494351e − 38 y 2.2250738585072014e − 308
- Un
char
representa convencionalmente una unidad de código Unicode / UTF-16. - Aunque un valor
boolean
contiene solo un bit de información, su tamaño en memoria varía según la implementación de la Máquina Virtual Java (vea el tipo booleano ).