Buscar..


Introducción

Los 8 tipos de datos primitivos 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 y short usando instrucciones de la Máquina Virtual Java que extienden sus valores de signo a valores de tipo int en tiempo de compilación o tiempo de ejecución. Las cargas de valores literales de los tipos boolean y char se codifican utilizando instrucciones que extienden el literal literalmente a un valor de tipo int en tiempo de compilación o tiempo de ejecución. [..]. Por lo tanto, la mayoría de las operaciones en valores de tipos reales boolean , byte , char y short se realizan correctamente mediante instrucciones que operan en valores de tipo computacional int .

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 demasiado grande para ser representada con el tipo de datos (desbordamiento)
0 1 No
x1 + x2 - 2n-1 = x1 + x2 - s2 * 2n-1
= v1 + v2
0 1
(x1 + x2) mod 2n-1 = x1 + x2 - 2n-1
= v1 + v2
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
(x1 + x2) mod 2n-1 - 2n-1 = (x1 + x2 - 2n-1) - 2n-1
= (x1 - s1 * 2n-1) + (x2 - s2 * 2n-1)
= v1 + v2

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:

  1. Los mandatos de la Especificación del lenguaje Java que los tipos integrales firmados ( byte a long ) 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.
  2. Java 8 y versiones posteriores proporcionan métodos para realizar operaciones aritméticas no firmadas en int y long . 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.
  3. 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
  4. Un char representa convencionalmente una unidad de código Unicode / UTF-16.
  5. 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 ).


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow