Conversiones primitivas de Java

1. Introducción

Java es un lenguaje escrito, lo que significa que utiliza el concepto de tipos. Hay dos grupos de tipos distintos:

  1. tipos de datos primitivos
  2. tipos de datos abstractos.

En este artículo, nos centraremos en las conversiones de tipos primitivos.

2. Descripción general de los primitivos

Lo primero que tenemos que saber es qué tipo de valores se pueden usar con tipos primitivos. Hay ocho tipos primitivos que son:

  • byte - 8 bits y firmado

  • corto - 16 bits y firmado

  • char - 16 bits y sin firmar, para que pueda representar caracteres Unicode

  • int - 32 bits y firmado

  • largo - 64 bits y firmado

  • flotante - 32 bits y firmado

  • doble - 64 bits y firmado

  • booleano : no es numérico, solo puede tenervalores verdaderos o falsos

Esto no pretende ser una discusión extensa sobre primitivas y hablaremos un poco más sobre sus detalles según sea necesario durante las conversiones.

3. Ampliación de las conversiones primitivas

Cuando necesitamos convertir de una primitiva que es más simple o más pequeña que el tipo de destino, no tenemos que usar ninguna notación especial para eso:

int myInt = 127; long myLong = myInt;

Durante la conversión de ampliación, el valor primitivo más pequeño se coloca sobre un contenedor más grande, lo que significa que todo el espacio adicional, a la izquierda del valor, se llena con ceros. Esto también se puede usar para ir del grupo de enteros al punto flotante:

float myFloat = myLong; double myDouble = myLong;

Esto es posible porque el cambio a una primitiva más amplia no pierde información.

4. Reducción de la conversión primitiva

A veces necesitamos ajustar un valor que sea más grande que el tipo usado en la declaración de la variable. Esto puede resultar en la pérdida de información ya que algunos bytes deberán descartarse.

En este caso, tenemos que expresar explícitamente que somos conscientes de la situación y estamos de acuerdo con eso, utilizando un elenco:

int myInt = (int) myDouble; byte myByte = (byte) myInt;

5. Ampliación y reducción de la conversión primitiva

Esta situación ocurre en un caso muy específico cuando queremos convertir de un byte a un carácter . La primera conversión es la ampliación del byte a int y luego del int se reduce a char .

Un ejemplo aclarará este punto:

byte myLargeValueByte = (byte) 130; //0b10000010 -126

La representación binaria de 130 es la misma para -126, la diferencia es la interpretación del bit de señal. Ahora convierta de byte a char :

char myLargeValueChar = (char) myLargeValueByte; //0b11111111 10000010 unsigned value int myLargeValueInt = myLargeValueChar; //0b11111111 10000010 65410

El carbón representación es un valor Unicode, pero la conversión a un int nos mostró un valor muy grande que tiene los 8 bits inferiores exactamente igual que -126.

Si lo convertimos de nuevo a byte obtenemos:

byte myOtherByte = (byte) myLargeValueInt; //0b10000010 -126

El valor original que usamos. Si todo el código comenzaba con un carácter, los valores serán diferentes:

char myLargeValueChar2 = 130; //This is an int not a byte! //0b 00000000 10000010 unsigned value int myLargeValueInt2 = myLargeValueChar2; //0b00000000 10000010 130 byte myOtherByte2 = (byte) myLargeValueInt2; //0b10000010 -126

Aunque el byte de representación es la misma, lo cual es -126, el carbón representación nos da dos caracteres diferentes.

6. Conversión boxeo / unboxing

En Java, tenemos una clase Wrapper para cada tipo primitivo, esta es una forma inteligente de proporcionar a los programadores métodos de procesamiento útiles, sin la sobrecarga de tener todo como referencia de objeto pesado. Desde Java 1.5, se incluyó la capacidad de convertir automáticamente a / de una primitiva a un objeto y viceversa y se logró mediante una simple atribución:

Integer myIntegerReference = myInt; int myOtherInt = myIntegerReference;

7. Conversiones de cadenas

Todos los tipos primitivos se pueden convertir a String a través de sus clases Wrapper, que anulan el método toString () :

String myString = myIntegerReference.toString();

Si necesitamos volver a un tipo primitivo, necesitamos usar un método de análisis definido por la Clase Wrapper correspondiente:

byte myNewByte = Byte.parseByte(myString); short myNewShort = Short.parseShort(myString); int myNewInt = Integer.parseInt(myString); long myNewLong = Long.parseLong(myString); float myNewFloat = Float.parseFloat(myString); double myNewDouble = Double.parseDouble(myString); 
boolean myNewBoolean = Boolean.parseBoolean(myString);

The only exception here is the Character Class because a String is made of chars anyway, this way, considering that probably the String is made of a single char, we can use the charAt() method of the String class:

char myNewChar = myString.charAt(0);

8. Numeric Promotions

To execute a binary operation, it is necessary that both operands are compatible in terms of size.

There is a set of simple rules that apply:

  1. If one of the operands is a double, the other is promoted to double
  2. Otherwise, if one of the operands is a float, the other is promoted to float
  3. De lo contrario, si uno de los operandos es largo , el otro se promociona a largo.
  4. De lo contrario, ambos se consideran int

Veamos un ejemplo:

byte op1 = 4; byte op2 = 5; byte myResultingByte = (byte) (op1 + op2);

Ambos operandos se promovieron a int y el resultado se debe reducir a byte nuevamente.

9. Conclusión

La conversión entre tipos es una tarea muy común en las actividades diarias de programación. Existe un conjunto de reglas que gobiernan las formas en que los lenguajes de tipado estático operan esas conversiones. Conocer estas reglas puede ahorrar mucho tiempo al intentar averiguar por qué cierto código se está compilando o no.

El código utilizado en este artículo se puede encontrar en GitHub.