JavaRush /Blogue Java /Random-PT /Autoboxing e unboxing em Java
Viacheslav
Nível 3

Autoboxing e unboxing em Java

Publicado no grupo Random-PT
<h2>Introdução</h2>Uma linguagem de programação, como a linguagem que as pessoas falam, vive e muda, novos fenômenos aparecem nela para tornar a linguagem mais conveniente de usar. E como sabemos, a linguagem deve expressar convenientemente os nossos pensamentos.
Autoboxing e unboxing em Java - 1
Assim, no Java SE 5, o mecanismo de boxing/unboxing foi introduzido. E um tutorial separado da Oracle é dedicado aos recursos desse meio de expressar pensamentos: Autoboxing e Unboxing . <h2>Boxing de empacotamento automático</h2>Vejamos um exemplo de boxe de empacotamento automático. Primeiro, vamos ver como funciona. Vamos utilizar o site compilejava.net e criar uma classe:
public class App {
    public static void main(String[] args) {
        Integer portNumber = 8080;
        if (args.length != 0) {
            portNumber = Integer.valueOf(args[0]);
        }
        System.out.println("Port number is: " + portNumber);
    }
}
Código simples. Podemos especificar o parâmetro de entrada e alterar o valor da porta. Como vemos, porque lemos o valor da porta Stringnos parâmetros e Integero obtemos passando por Integer.valueOf. Portanto, somos forçados a especificá-lo não como um tipo primitivo, mas como um tipo de objeto Integer. E aqui temos, por um lado, uma variável de objeto, e o valor padrão é um primitivo. E funciona. Mas não acreditamos em magia, não é? Vamos dar uma olhada “nos bastidores”, como dizem. Baixe o código fonte em compilejava.net clicando em “Baixar ZIP”. Depois disso, extraia o arquivo baixado em um diretório e acesse-o. Agora vamos fazer: javap -c -p App.classonde App.class é o arquivo de classe compilado para sua classe. Veremos conteúdos como este:
Autoboxing e unboxing em Java - 2
Este é o mesmo notório “bytecode”. Mas o que é importante para nós agora é o que vemos. Primeiro, a primitiva 8080 é colocada na pilha de execução do método e, em seguida, Integer.valueOf é executado . Esta é a “mágica” do boxe. E por dentro a magia fica assim:
Autoboxing e unboxing em Java - 3
Ou seja, em essência, um novo será obtido Integerou obtido Integerdo cache (o cache nada mais é do que apenas um array de números inteiros) dependendo do valor do número. Naturalmente, Integernão só um teve tanta sorte. Há uma lista completa de tipos primitivos relacionados e seus wrappers (classes que representam primitivos no mundo OOP). Esta lista é fornecida no final do Tutorial da Oracle: “ Autoboxing e Unboxing ”. É importante notar imediatamente que arrays feitos de primitivos não possuem um “wrapper” sem conectar nenhuma biblioteca de terceiros. Aqueles. Arrays.asListnão fará de int[]para nós Lista partir de Integer. <h2>Unboxing</h2>O processo inverso ao boxing é chamado de unboxing unboxing. Vejamos um exemplo de descompactação:
public class App {

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Please, enter params");
            return;
        }
      	int value = Math.abs(Integer.valueOf(args[0]));
        System.out.println("Absolute value is: " + value);
    }

}
Math.absaceita apenas primitivos. O que fazer? A classe wrapper possui um método especial para este caso que retorna um primitivo. Por exemplo, este é o Integermétodo intValue . Se olharmos para o bytecode, é assim:
Autoboxing e unboxing em Java - 4
Aparentemente, não há mágica. Tudo está dentro do Java. Simplesmente funciona “por si só”. Para nossa comodidade. <h2>Ancinho</h2>
Autoboxing e unboxing em Java - 5
Qualquer ferramenta, se usada incorretamente, torna-se uma arma formidável contra si mesma. E o mecanismo automático de boxe/unboxing em Java não é exceção. A primeira e óbvia comparação é através de ==. Acho que isso está claro, mas vamos analisar novamente:
public static void main(String[] args) {
    Integer inCacheValue = 127;
    Integer inCacheValue2 = 127;
    Integer notInCache = 128; // new Integer(129)
    Integer notInCache2 = 128; // new Integer(129)
    System.out.println(inCacheValue == inCacheValue2); //true
    System.out.println(notInCache == notInCache2); //false
}
No primeiro caso, o valor é retirado do Integercache de valores (veja a explicação do Boxing acima), e no segundo caso um novo objeto será criado a cada vez. Mas aqui vale a pena fazer uma reserva. Esse comportamento depende do limite superior do cache ( java.lang.Integer.IntegerCache.high ). Além disso, este limite pode mudar devido a outras configurações. Você pode ler a discussão sobre este tópico no stackoverflow: Qual é o tamanho do cache inteiro? Naturalmente, os objetos precisam ser comparados usando iguais: System.out.println(notInCache.equals(notInCache2)); O segundo problema associado ao mesmo mecanismo é o desempenho. Qualquer boxe em Java é equivalente à criação de um novo objeto. Se o número não estiver incluído nos valores do cache (ou seja, -128 a 127), um novo objeto será criado a cada vez. Se de repente o empacotamento (ou seja, encaixotamento) for realizado em loop, isso causará um grande aumento de objetos desnecessários e consumo de recursos para o trabalho do coletor de lixo. Portanto, não seja tão imprudente com isso. Um terceiro movimento, não menos doloroso, decorre do mesmo mecanismo:
public static void check(Integer value) {
    if (value <= 0) {
        throw new IllegalStateException("Value is too small");
    }
}
Neste código, a pessoa estava claramente tentando não superar o erro. Mas não há verificação para null. Se se tratar da entrada null, então, em vez de um erro compreensível, obteremos um erro incompreensível NullPointerException. Porque para efeito de comparação, o Java tentará executar value.intValuee travar, porque... valuevai null. <h2>Conclusão</h2>O mecanismo de boxing/unboxing permite que o programador escreva menos código e às vezes nem pense em converter de primitivos para objetos e vice-versa. Mas isso não significa que você deva esquecer como funciona. Caso contrário, você poderá cometer um erro que pode não aparecer imediatamente. Não devemos confiar em partes do sistema que não estejam completamente sob nosso controle (como o limite inteiro). Mas não se esqueça de todas as vantagens das classes wrapper (como Integer). Freqüentemente, essas classes wrapper possuem um conjunto de métodos estáticos adicionais que tornarão sua vida melhor e seu código mais expressivo. Aqui está um exemplo de atualização:
public static void main(String[] args) {
    int first = 1;
    int second = 5;
    System.out.println(Integer.max(first, second));
    System.out.println(Character.toLowerCase('S'));
}
A conclusão correta de tudo é que não existe mágica, existe algum tipo de realização. E nem tudo será sempre o que esperamos. Por exemplo, não há empacotamento: System.out.println("The number is " + 8); o exemplo acima será otimizado pelo compilador em uma linha. Ou seja, é como se você escrevesse “O número é 8”. E no exemplo abaixo também não haverá embalagem:
public static void main(String[] args) {
    System.out.println("The number is " + Math.abs(-2));
}
Como pode ser quando printlntomamos um objeto como entrada e precisamos conectar as linhas de alguma forma. Linhas... sim, é por isso que não existe embalagem propriamente dita. Existem Integermétodos estáticos, mas alguns deles são package. Ou seja, não podemos usá-los, mas no próprio Java eles podem ser usados ​​ativamente. Este é exatamente o caso aqui. O método getChars será chamado, o que cria um array de caracteres a partir do número. Novamente, sem mágica, apenas Java). Portanto, em qualquer situação pouco clara, basta observar a implementação e pelo menos algo se encaixará. #Viacheslav
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION