1. Datilografia

Typecasting em Java

Variáveis ​​de tipos primitivos (com exceção do booleantipo) são usadas para armazenar vários tipos de números. Embora os tipos de variáveis ​​nunca tenham mudado, há um lugar onde você pode converter de um tipo para outro. E esse lugar é atribuição .

Variáveis ​​de tipos diferentes podem ser atribuídas umas às outras. Ao fazer isso, o valor de uma variável de um tipo é convertido em um valor de outro tipo e atribuído à segunda variável. Nesse sentido, podemos identificar dois tipos de conversão de tipo: alargamento e estreitamento.

Ampliar é como mover um valor de uma cesta pequena para uma grande: esta operação é contínua e indolor. O estreitamento acontece quando você move um valor de uma cesta grande para uma pequena: pode não haver espaço suficiente e você terá que jogar algo fora.

Aqui estão os tipos, classificados por tamanho da cesta:

Typecast em Java 2


2. Ampliando as conversões de tipo

Geralmente é necessário atribuir uma variável de um tipo numérico a uma variável de outro tipo numérico. Como você faz isso?

Java tem 4 tipos inteiros:

Tipo Tamanho
byte 1 byte
short 2 bytes
int 4 bytes
long 8 bytes

Variáveis ​​armazenadas em cestas menores sempre podem ser atribuídas a variáveis ​​armazenadas em cestas maiores.

int, shorte bytevariáveis ​​podem ser facilmente atribuídas a longvariáveis. shorte bytevariáveis ​​podem ser atribuídas a intvariáveis. E bytevariáveis ​​podem ser atribuídas a shortvariáveis.

Exemplos:

Código Descrição
byte a = 5;
short b = a;
int c = a + b;
long d = c * c;
Este código irá compilar perfeitamente.

Essa conversão, de um tipo menor para um maior, é chamada de conversão de tipo de ampliação .

E os números reais?

Com eles, tudo é igual — o tamanho importa:

Tipo Tamanho
float 4 bytes
double 8 bytes

floatvariáveis ​​podem ser atribuídas a doublevariáveis ​​sem nenhum problema. Mas as coisas são mais interessantes com os tipos inteiros.

Você pode atribuir qualquer variável inteira a uma floatvariável. Até mesmo o longtipo, que tem 8 bytes de comprimento. E você pode atribuir o que quiser — qualquer variável inteira ou floatvariável — a uma doublevariável:

Código Observação
long a = 1234567890;
float b = a;
double c = a;

b == 1.23456794E9
c == 1.23456789E9

Observe que a conversão para um tipo real pode resultar em perda de precisão devido à falta de dígitos significativos suficientes.

Ao converter de números inteiros para números de ponto flutuante, as partes de ordem inferior dos números podem ser descartadas. Mas como os números fracionários são entendidos como armazenando valores aproximados, tais operações de atribuição são permitidas.


3. Limitando as conversões de tipo

E as outras possibilidades? E se você precisar atribuir um longvalor a uma intvariável?

Imagine uma variável como uma cesta. Temos cestos de vários tamanhos: 1, 2, 4 e 8 bytes. Não é um problema transferir as maçãs de uma cesta menor para uma maior. Mas ao mudar de uma cesta maior para uma menor, algumas maçãs podem ser perdidas.

Essa transformação — de um tipo maior para um tipo menor — é chamada de conversão de tipo de restrição . Ao executar uma operação de atribuição como esta, parte de um número pode simplesmente não caber na nova variável e, portanto, pode ser descartada.

Ao restringir um tipo, devemos dizer explicitamente ao compilador que não estamos cometendo um erro, que estamos descartando deliberadamente parte do número. O operador typecast é usado para isso. É um nome de tipo entre parênteses .

Em tais situações, o compilador Java requer que o programador especifique o operador typecast. Em geral, parece com isso:

(type) expression

Exemplos:

Código Descrição
long a = 1;
int b = (int) a;
short c = (short) b;
byte d = (byte) c;
Cada vez que o operador typecast deve ser indicado explicitamente

Aqui aé igual a 1, e talvez o operador typecast pareça um exagero. Mas e se afossem maiores?

Código Descrição
long a = 1000000;
int b = (int) a;
short c = (short) b;
byte d = (byte) c;
a == 1000000
b == 1000000
c == 16960
d == 64

Um milhão se encaixa perfeitamente em um longe em um int. Mas ao atribuir um milhão a uma shortvariável, os dois primeiros bytes são descartados e apenas os dois últimos bytes são retidos. E ao atribuir a um byte, a única coisa que resta é o último byte.

Como os números são organizados na memória:

Tipo Notação binária Notação decimal
int 0b 00000000 00001111 01000010 01000000 1000000
short 0b 01000010 01000000 16.960
byte 0b 01000000 64

chartipo

A char, como a short, ocupa dois bytes, mas para converter um em outro, você sempre precisa usar um operador typecast. O problema aqui é que o shorttipo é assinado e pode conter valores de -32,768a +32,767, mas o chartipo não é assinado e pode conter valores de 0a 65,535.

Números negativos não podem ser armazenados em a char, mas podem ser armazenados em a short. E a shortnão pode armazenar números maiores que 32,767, mas esses números podem ser armazenados em a char.


4. Tipo de expressão

E se variáveis ​​de tipos diferentes forem usadas na mesma expressão? Logicamente, entendemos que primeiro eles precisam ser convertidos para um tipo comum. Mas qual deles?

Para o maior, é claro.

Java sempre converte para o tipo maior. Grosso modo, primeiro é ampliado um do tipo e só então é realizada a operação com valores do mesmo tipo.

Se an inte a longestiverem envolvidos em uma expressão, o valor de the intserá convertido para a longe só então a operação prosseguirá:

Código Descrição
int a = 1;
long b = 2;
long c = a + b;
aserá ampliado para a longe então a adição ocorrerá.

Números de ponto flutuante

Se um inteiro e um número de ponto flutuante ( floatou double) estiverem envolvidos em uma expressão, o inteiro será convertido em um número de ponto flutuante ( floatou double) e somente então a operação será executada.

Se a operação envolver a floate a double, o floatserá convertido em a double. O que é realmente esperado.

Surpresa

Os tipos byte, shorte charsão sempre convertidos em intquando interagem entre si. Há uma boa razão pela qual o inttipo é considerado o tipo inteiro padrão.

Se você multiplicar a bytepor a short, obterá um int. Se você multiplicar a bytepor a byte, obterá um int. Mesmo se você adicionar a bytee a byte, obterá um int.

Há várias razões para isso. Exemplos:

Código Descrição
byte a = 110;
byte b = 120;
byte c = a * b;  // Error
110 * 120é 13,200, que é um pouco maior que o valor máximo do bytetipo:127
byte a = 110;
byte b = 120;
byte c = a + b; // Error
110 + 120is 230, que também é um pouco maior que o valor máximo do bytetipo:127

Em geral, ao multiplicar um número de 8 bits (1 byte) por um número de 8 bits (1 byte), obtemos um número que ocupa bits de 16 bits (2 bytes)

Como resultado, todas as operações com tipos inteiros menores que intsão sempre imediatamente convertidas em ints. E isso significa que, se você quiser armazenar o resultado do cálculo em uma variável de um tipo menor que um int, sempre precisará especificar explicitamente o operador typecast.

Exemplos:

Código Descrição
byte a = 110;
byte b = 120;
byte c = (byte) (a * b);
A byte * byteexpressão será umaint
byte a = 110;
byte b = 120;
byte c = (byte) (a + b);
A byte + byteexpressão será umaint
byte a = 1;
byte b = (byte) (a + 1);
A byte + intexpressão será um int
O literal é um int.

5. Uma nuance importante

O operador typecast tem uma prioridade bastante alta.

Isso significa que se uma expressão contiver, por exemplo, adição e um operador typecast, o typecast será executado antes da adição.

Exemplo:

Código Descrição
byte a = 1;
byte b = 2;
byte c = (byte) a * b;
O operador typecast será aplicado apenas à avariável, que já é um byte. Este código não irá compilar.
byte a = 1;
byte b = 2;
byte c = (byte) (a * b);
Esta é a maneira correta.

Se você deseja converter a expressão inteira em um tipo específico, e não apenas um componente da expressão, coloque a expressão inteira entre parênteses e coloque o operador typecast na frente.