CodeGym/Blogue Java/Random-PT/Ampliação e estreitamento de tipos primitivos
John Squirrels
Nível 41
San Francisco

Ampliação e estreitamento de tipos primitivos

Publicado no grupo Random-PT
Oi! À medida que progrediu no CodeGym, você encontrou tipos primitivos muitas vezes. Aqui está uma pequena lista do que sabemos sobre eles:
  1. Eles não são objetos e representam um valor armazenado na memória
  2. Existem vários tipos
    • Números inteiros: byte , short , int , long
    • Números de ponto flutuante (fracionários): float e double
    • Valores lógicos: booleano
    • Valores simbólicos (para representar letras e números): char
  3. Cada tipo tem seu próprio intervalo de valores:

tipo primitivo Tamanho na memória Faixa de valor
byte 8 bits -128 a 127
curto 16 bits -32768 a 32767
Caracteres 16 bits 0 a 65536
int 32 bits -2147483648 a 2147483647
longo 64 bits -9223372036854775808 a 9223372036854775807
flutuador 32 bits (2 elevado a -149) para ((2 - (2 elevado a -23)) * 2 elevado a 127)
dobro 64 bits (-2 elevado a 63) para ((2 elevado a 63) - 1)
boleano 8 (quando usado em arrays), 32 (se não for usado em arrays) verdadeiro ou falso
Mas, além de terem valores diferentes, diferem também no espaço que ocupam na memória. Um int leva mais de um byte. E um longo é maior que um curto. A quantidade de memória ocupada por primitivos pode ser comparada a bonecas russas: Alargamento e estreitamento de tipos primitivos - 2 cada boneca tem espaço disponível dentro. Quanto maior a boneca de nidificação, mais espaço haverá. Uma boneca de nidificação grande ( comprida ) acomodará facilmente um int menor . Cabe facilmente e você não precisa fazer mais nada. Em Java, ao trabalhar com primitivos, isso é chamado de conversão implícita. Ou, em outras palavras, é chamado de alargamento.

Alargamento em Java

Aqui está um exemplo simples de uma conversão de ampliação:
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       byte littleNumber = 16;

       bigNumber = littleNumber;
       System.out.println(bigNumber);
   }
}
Aqui, atribuímos um valor de byte a uma variável int . A atribuição é bem-sucedida sem problemas: o valor armazenado em um byte ocupa menos memória do que um int pode acomodar. O pequeno boneco de aninhamento (valor do byte) cabe facilmente dentro do grande boneco de aninhamento ( variável int ). É uma questão diferente se você tentar fazer o oposto, ou seja, colocar um valor grande em uma variável cujo intervalo não pode acomodar esse tipo de big data. Com bonecos de nidificação reais, o número simplesmente não caberia. Com Java, pode, mas com nuances. Vamos tentar colocar um int em uma variável curta :
public static void main(String[] args) {

   int bigNumber = 10000000;

   short littleNumber = 1000;

   littleNumber = bigNumber;// Error!
   System.out.println(bigNumber);
}
Erro! O compilador entende que você está tentando fazer algo anormal ao colocar um grande boneco de aninhamento ( int ) dentro de um pequeno ( short ). Nesse caso, o erro de compilação é um aviso do compilador: "Ei, você tem certeza absoluta de que deseja fazer isso?" Se você tiver certeza, diga ao compilador: "Está tudo bem. Eu sei o que estou fazendo!" Esse processo é chamado de conversão de tipo explícito ou restrição.

Estreitando em Java

Para realizar uma conversão de restrição, você precisa indicar explicitamente o tipo para o qual deseja converter seu valor. Em outras palavras, você precisa responder à pergunta do compilador: "Bem, em qual dessas pequenas bonecas você deseja colocar esta grande boneca?" No nosso caso, fica assim:
public static void main(String[] args) {

   int bigNumber = 10000000;

   short littleNumber = 1000;

   littleNumber = (short) bigNumber;
   System.out.println(littleNumber);
}
Indicamos explicitamente que queremos colocar um int em uma variável curta e que assumiremos a responsabilidade. Vendo que um tipo mais restrito foi explicitamente indicado, o compilador executa a conversão. Qual é o resultado? Saída do console: -27008 Isso foi um pouco inesperado. Por que exatamente conseguimos isso? Na verdade, é tudo muito simples. Originalmente, o valor era 10000000. Foi armazenado em uma variável int , que ocupa 32 bits. Esta é sua representação binária:
Alargamento e estreitamento de tipos primitivos - 3
Escrevemos esse valor em uma variável curta , que pode armazenar apenas 16 bits! Assim, apenas os primeiros 16 bits do nosso número serão movidos para lá. O restante será descartado. Como resultado, a variável curta recebe o seguinte valor
Alargamento e estreitamento de tipos primitivos - 4
que na forma decimal é igual a -27008 É por isso que o compilador pede para você "confirmar" indicando uma conversão de restrição explícita para um tipo específico. Primeiro, isso mostra que você está assumindo a responsabilidade pelo resultado. Em segundo lugar, informa ao compilador quanto espaço alocar quando a conversão ocorrer. Afinal, no último exemplo, se atribuíssemos um valor int a uma variável byte em vez de short , teríamos apenas 8 bits à nossa disposição, não 16, e o resultado seria diferente. Os tipos fracionários ( float e double ) têm seu próprio processo para restringir as conversões. Se você tentar converter um número fracional para um tipo inteiro, a parte fracionária será descartada.
public static void main(String[] args) {

   double d = 2.7;

   long x = (int) d;
   System.out.println(x);
}
Saída do console: 2

Caracteres

Você já sabe que char é usado para exibir caracteres individuais.
public static void main(String[] args) {

   char c = '!';
   char z = 'z';
   char i = '8';

}
Mas esse tipo de dados tem vários recursos que é importante entender. Vejamos novamente a tabela de faixas de valores:
tipo primitivo Tamanho na memória Faixa de valor
byte 8 bits -128 a 127
curto 16 bits -32768 a 32767
Caracteres 16 bits 0 a 65536
int 32 bits -2147483648 a 2147483647
longo 64 bits -9223372036854775808 a 9223372036854775807
flutuador 32 bits (2 elevado a -149) para ((2 - (2 elevado a -23)) * 2 elevado a 127)
dobro 64 bits (-2 elevado a 63) para ((2 elevado a 63) - 1)
boleano 8 (quando usado em arrays), 32 (se não for usado em arrays) verdadeiro ou falso
O intervalo de 0 a 65536 é indicado para o tipo de char . Mas o que isso significa? Afinal, um caractere não representa apenas números, mas também letras, sinais de pontuação… O problema é que em Java os valores de caracteres são armazenados no formato Unicode. Já encontramos o Unicode em uma das lições anteriores. Você provavelmente se lembra que o Unicode é um padrão de codificação de caracteres que inclui os símbolos de quase todas as línguas escritas do mundo. Em outras palavras, é uma lista de códigos especiais que representam quase todos os caracteres de qualquer idioma. Toda a tabela Unicode é muito grande e, claro, não há necessidade de decorá-la. Aqui está uma pequena parte dele: Alargamento e estreitamento de tipos primitivos - 5 O principal é entender como os caracteres são armazenados e lembrar que, se você souber o código de um determinado caractere, sempre poderá produzir esse caractere em seu programa. Vamos tentar com algum número aleatório:
public static void main(String[] args) {

   int x = 32816;

   char c = (char) x ;
   System.out.println(c);
}
Saída do console: 耰 Este é o formato usado para armazenar char s em Java. Cada símbolo corresponde a um número: um código numérico de 16 bits (dois bytes). Em Unicode, 32816 corresponde ao caractere chinês 耰. Anote o seguinte ponto. Neste exemplo, usamos uma variável int . Ele ocupa 32 bits de memória, enquanto um char ocupa 16. Aqui escolhemos um int , pois nosso número (32816) não caberia em um short . Embora o tamanho de um char (assim como um short ) seja de 16 bits, não há números negativos no intervalo de char , então a parte "positiva" do charintervalo é duas vezes maior (65536 em vez de 32767 para o tipo curto ). Podemos usar um int desde que nosso código fique abaixo de 65536. Mas se você criar um valor int maior que 65536, ele ocupará mais de 16 bits. E isso resultará em uma conversão estreita
char c = (char) x;
os bits extras serão descartados (como discutido acima) e o resultado será bastante inesperado.

Recursos especiais de adição de caracteres e números inteiros

Vejamos um exemplo inusitado:
public class Main {

   public static void main(String[] args) {

      char c = '1';

      int i = 1;

       System.out.println(i + c);
   }
}
Saída do console: 50 O_О Como isso faz sentido? 1+1. De onde vieram os 50?! Você já sabe que charos valores são armazenados na memória como números no intervalo de 0 a 65536 e que esses números são uma representação Unicode de um caractere. Alargamento e estreitamento de tipos primitivos - 6 Quando adicionamos um caractere e algum tipo de número inteiro, o caractere é convertido no número Unicode correspondente. Em nosso código, quando adicionamos 1 e '1', o símbolo '1' foi convertido em seu próprio código, que é 49 (você pode verificar isso na tabela acima). Portanto, o resultado é 50. Vamos mais uma vez pegar nosso velho amigo 耰 como exemplo e tentar adicioná-lo a algum número.
public static void main(String[] args) {

   char c = '耰';
   int x = 200;

   System.out.println(c + x);
}
Saída do console: 33016 Já descobrimos que 耰 corresponde a 32816. E quando somamos esse número e 200, obtemos nosso resultado: 33016. :) Como você pode ver, o algoritmo aqui é bastante simples, mas você não deve esquecê-lo .
Comentários
  • Populares
  • Novas
  • Antigas
Você precisa acessar para deixar um comentário
Esta página ainda não tem nenhum comentário