Conversões de Tipos Primitivos em Java
Em Java, cada tipo primitivo possui um tamanho fixo em bytes, o que determina a quantidade de memória ocupada por valores desse tipo. Isso impõe limitações quando diferentes tipos participam de uma mesma operação. Observe o exemplo:
int a = 4;
byte b = a; // Erro de compilação
Embora int
e byte
representem números inteiros e o valor 4
esteja dentro do intervalo de byte
(de -128 a 127), ocorre um erro. Isso se deve ao fato de que int
ocupa 4 bytes e byte
, apenas 1. O compilador não permite essa atribuição diretamente, pois existe risco de perda de dados, mesmo que o valor pareça seguro.
Quando esse tipo de conversão é necessário, é possível recorrer à conversão explícita:
int a = 4;
byte b = (byte) a;
System.out.println(b); // 4
Ao aplicar (byte)
antes da variável, o compilador entende que a conversão é intencional e realiza a transformação de int
para byte
. O valor convertido é atribuído normalmente à variável b
.
Conversões implícitas e explícitas
Quando diferentes tipos participam de uma mesma operação, nem sempre é necessário declarar a conversão. Dependendo da situação, ela ocorre de forma automática (implícita) ou requer indicação explícita por parte do desenvolvedor.
As setas na imagem indicam quais conversões de tipo podem ser realizadas automaticamente. As setas tracejadas indicam conversões automáticas com perda de precisão.
Conversões implícitas (automáticas)
Conversões implícitas ocorrem quando o tipo de destino pode representar todos os valores possíveis do tipo de origem, sem risco de perda de dados. Esse tipo de conversão é chamado de widening conversion (conversão ampliada).
byte b = 7;
int d = b;
System.out.println(d); // 7
Aqui, o valor de b
é automaticamente convertido para int
, que possui maior capacidade de armazenamento. Como não há risco de truncamento ou perda de precisão, o compilador permite a operação sem exigir conversão explícita.
As principais sequências seguras de promoção entre tipos incluem:
- byte -> short -> int -> long
- int -> double
- short -> float -> double
- char -> int.
Conversões implícitas com possível perda de precisão
Algumas conversões também podem ocorrer de forma automática, mesmo quando existe a possibilidade de perda de dados. Isso acontece, por exemplo, ao converter valores inteiros para ponto flutuante:
int a = 2147483647;
float b = a;
System.out.println(b); // 2.14748365E9
Apesar de válidas, essas conversões podem comprometer a precisão dos valores representados. Isso ocorre com:
int
parafloat
long
parafloat
long
paradouble
Conversões explícitas
Sempre que se tenta converter um tipo de maior capacidade para outro com menor capacidade, Java exige a conversão explícita, conhecida como narrowing conversion (conversão por redução):
long a = 4;
int b = (int) a;
System.out.println(b); // 4
Essas conversões devem ser feitas com cautela, pois há risco de perda de dados.
Perda de dados durante conversões
Ao realizar uma conversão explícita, o valor resultante pode não corresponder ao original, caso este ultrapasse o intervalo do tipo de destino:
int a = 5;
byte b = (byte) a;
System.out.println(b); // 5
Nesse caso, 5
está dentro do intervalo de byte
, portanto a conversão ocorre sem prejuízo.
Mas ao converter um valor fora do intervalo:
int a = 258;
byte b = (byte) a;
System.out.println(b); // 2
O resultado é 2
. Isso ocorre porque o valor 258
, em binário, ocupa mais de 8 bits. O tipo byte
armazena apenas os 8 bits menos significativos. A parte excedente é descartada, e o valor final corresponde apenas aos bits restantes: 00000010
, que equivale a 2
.
Conversão de valores com ponto flutuante para inteiros
Quando se converte um número com parte decimal para um tipo inteiro, a fração é descartada:
double a = 56.9898;
int b = (int) a;
System.out.println(b); // 56
Mesmo que 56.9898
esteja mais próximo de 57
, o valor final de b
será 56
. Para evitar esse comportamento, é possível aplicar o arredondamento explícito com Math.round()
:
double a = 56.9898;
int b = (int) Math.round(a);
System.out.println(b); // 57
Conversões em operações aritméticas
Quando diferentes tipos participam de uma operação, Java aplica regras específicas para garantir compatibilidade:
- Se um dos operandos for
double
, o outro será promovido adouble
. - Caso não haja
double
, mas um dos operandos forfloat
, o outro será promovido afloat
. - Se não houver
double
nemfloat
, mas houverlong
, o outro será promovido along
. - Caso nenhum dos anteriores se aplique, todos os operandos serão promovidos a
int
.
Exemplo com double
:
int a = 3;
double b = 4.6;
double c = a + b;
System.out.println(c); // 7.6
A variável a
é promovida a double
, e o resultado da soma c
também será desse tipo.
Outro exemplo:
byte a = 3;
short b = 4;
byte c = (byte)(a + b);
System.out.println(c); // 7
Embora a
e b
sejam tipos numéricos menores que int
, a linguagem Java converte ambos automaticamente para int
ao realizar a operação a + b
. Isso ocorre porque, por padrão, todas as expressões aritméticas envolvendo tipos menores que int
são promovidas para int
.
Como o resultado da soma é do tipo int
, não é possível atribuí-lo diretamente a uma variável do tipo byte
sem conversão. Por isso, é necessário realizar a conversão explícita para byte
com (byte)
antes da expressão.
Valores do tipo char
também são tratados como números inteiros durante operações aritméticas. Por exemplo:
int d = 'a' + 5;
System.out.println(d); // 102
O caractere 'a'
é convertido para seu valor inteiro correspondente, que é 97
, e a soma resulta em 102
.
📝 Exercícios
Tarefa 1
Quais das seguintes conversões de tipo não são realizadas automaticamente? (pode haver mais de uma alternativa)
- De
short
paraint
- De
int
parashort
- De
boolean
paraint
- De
byte
parafloat
Resposta
int
para short
boolean
para int
short
para int
é automática, pois envolve ampliação de tipo.int
para short
, há risco de perda de dados, portanto exige casting explícito.byte
para float
é automática, mesmo com possível perda de precisão.
Tarefa 2
O que será exibido no console ao executar o código abaixo, e por quê?
public class Program {
public static void main(String[] args) {
short shortNum = 257;
byte byteNum = (byte) shortNum;
System.out.println(byteNum);
}
}
Resposta
1
.
257
é armazenado como short
, que ocupa 16 bits. Sua representação binária é:
00000001 00000001
byte
, que possui apenas 8 bits, os 8 bits mais à esquerda são descartados, restando apenas:
00000001
1
na base decimal. Por isso, System.out.println(byteNum);
imprime 1
.
Tarefa 3
Qual será o tipo do resultado da expressão a + b
no código abaixo, e por quê?
byte a = 10;
byte b = 20;
var result = a + b;
Resposta
result
será int
.
a
e b
sejam do tipo byte
, a operação aritmética entre eles promove automaticamente os dois operandos para o tipo int
, conforme as regras da linguagem Java. Portanto, a variável result
(declarada com var
) será inferida como int
.