Se você já trabalhou com Java, mesmo que por pouco tempo já deve ter trabalhado alguma vez com Wrappers e nem percebeu. Este artigo tem como principal objetivo mostrar a importância dos Wrappers e principalmente o que eles são.

Wrappers vem do verbo inglês “wrap” que significa envolver. Eles são um nome adicional ao padrão de projeto Decorator. Tem como principal função “envolver coisas” adicionando funcionalidades à ela.

O Java conta com diversos Wrappers que adicionam funcionalidades a outras classes ou tipos primitivos, um exemplo dele é o Integer, que é o Wrapper do tipo primitivo int. Que tipo de funcionalidade você pode executar tendo apenas uma variável definida como “int”? Nenhuma, a não ser atribuir valores, pois int é um tipo primitivo e não possuí métodos.

Com o Wrapper Integer envolvendo o tipo primitivo int você consegue executar métodos como é o caso do: parseInt, valueOf e assim por diante.

Abaixo, na figura 1, você confere uma lista de Wrappers muito comuns no Java.

Wrappers de Tipos primitivos

Figura 1: Wrappers de Tipos primitivos

Então se temos Wrappers porque usar os tipos primitivos? Simples, eles são mais rápidos e consomem menos memória, afinal não tem implementação de métodos ou qualquer outro algoritmo complexo que venha a consumir mais tempo da JVM.

Atente também que tipos primitivos não podem ser utilizados em Collections, só objetos. Sendo assim, a solução é usar Wrappers. E já que estamos no assunto de Wrappers, não poderíamos falar da novidade trazida pelo Java 5, o Autoboxing que será explicado na próxima seção.

Autoboxing com Wrappers

Você já deve ter se imagine que como Wrapper é um Objeto você deve sempre passar um tipo primitivo para criar um Wrapper especifico daquele tipo primitivo, algo como mostrado na listagem 1.

Listagem 1: Criando um Wrapper


Integer soma = new Integer(10);

Ótimo, e se quisermos criar um Hashmap teríamos que fazer algo como mostrado na listagem 2.

Listagem 2: Criando uma lista sem Autoboxing


HashMap hashMap = new HashMap();
hashMap.put(new Integer(10), “Carlos”);
hashMap.put(new Integer(11), “Jose”);
hashMap.put(new Integer(12), “Pedro”);

Após o Java 5 surgiu a funcionalidade do Autoboxing onde o próprio Java já converte o tipo primitivo em Wrapper se este achar que é necessário. Veja a listagem 3 com Autoboxing funcionando.

Listagem 3: Criando uma lista com Autoboxing


HashMap hashMap = new HashMap();
hashMap.put(10, “Carlos”);
hashMap.put(11, “Jose”);
hashMap.put(12, “Pedro”);

Boxing Conversion

O Boxing é a conversão de tipos primitivos em seu respectivo Wrapper correspondente, ou seja, veja o exemplo na listagem 4.

Listagem 4: Boxing Conversion


Boolean meuBoolean = true; //a conversão é feita de forma automática para o boolean
Integer meuInteger = 1203; 
Double meuDouble = 10.20;

É óbvio que se você tentar realizar um Boxing Conversion de um tipo primitivo para um Wrapper errado você terá um erro de compilação.

Unboxing Conversion

O Unboxing Conversion é quando você deseja fazer o inverso feito na seção 2.1, ou seja, deseja converter um objeto para um tipo primitivo. Veja os exemplos na listagem 5.

Listagem 5: Exemplos de Unboxing Conversion


boolean a = new Boolean(“True”);
char c = new Character(‘c’);
byte b = new Byte(“1”);
float f = new Float(1.0f);
 

Comparando Wrappers

Possivelmente você já deve ter comparado Strings em Java, e deve saber que utilizar o operador “==” não funciona, é por isso que a implementação no método equals nos “Pojos” são muito importantes. Com os Wrappers você também deve utilizar o método equals para realizar estes tipos de comparações, não esqueça que Wrappers são objetos e não tipos primitivos.

Veja na listagem 6 uma comparação certa e outra errada.

Listagem 6: Comparando Wrappers da forma certa e da forma errada


Integer a = 10;
Integer b = 20;
a.equals(b); // Retorna TRUE
a == b; // Retorna FALSE

A diferença entre o equals e o operado ==, é que no operado == ele compara a referência do objeto, afinal você está literalmente “comparando” os objetos e mesmo que estes fossem idênticos (em todos os atributos) eles ocupam locais diferentes na memória e possuem identificação diferente na JVM, resumindo não são iguais. Utilizando o equals você compara o valor deles, igual como se tivesse comparando dois tipos primitivos.

O Problema encontrado

Quando falamos que você não deve utilizar o == para comparar Wrappers, é porque não deve mesmo e continuamos afirmando isso. Ainda afirmamos que quando você realizar esse tipo de comparação receberá FALSE, visto que ele compara a referência em memória do objeto. O problema é que se você fizer o teste da listagem 7 verá que ele retornará verdadeiro.

Listagem 7

: Comparando Wrappers com o operado ==


Integer x = 120;
Integer y = 120;
x==y; //Retorna TRUE

Porque então o exemplo da Listagem 7 retorna TRUE? Por causa do padrão de projeto Flyweigth. Ele tenta reduzir o consumo de memória mudando a referência dos objetos que são idênticos, ou seja, os objetos x e y apontam para um mesmo objeto com que tem as características ditando que o valor é 120, assim quando compararmos com ==, já que estamos comparando a referência do objeto e ela é a mesma com o Flyweigth o resultado será TRUE. Isso por padrão só é aplicado nos valores de -128 até 127, mas na dúvida use sempre o equals.

CONCLUSÃO

Possivelmente, como citamos no inicio do artigo, você já deve ter usado Wrapper em algum momento, mas nunca soube de fato o que era, na verdade isso acaba sendo tão automático que muitas das vezes você deve ter usado o Integer, Float ou Boolean Wrapper pensado que é um tipo primitivo, quando na verdade você está envolvido pela Orientação à Objetos.

A importância deste nem precisa ser descrita, já que são utilizados com freqüência e fazem a maior parte do trabalho quando precisamos. Além disso, existem mais Wrappers do que apenas de tipos primitivos, faça uma pesquisa sobre estes e encontrará um mundo de novos conceitos e aprendizados.