1. Introdução
Na linguagem Java existem duas famílias diferentes de dados. A primeira — os tipos primitivos: int, char, double, boolean e outros. Eles são simples e rápidos: o valor é armazenado diretamente na célula de memória. A segunda família — os tipos por referência, isto é, objetos: a variável armazena uma referência ao local em que o objeto está na memória.
Às vezes é preciso usar um primitivo como objeto. Mas primitivos não são objetos por natureza. Nesses casos, ajudam as classes wrapper.
Tipos wrapper são classes que armazenam internamente o valor de um primitivo e permitem tratá-lo como objeto. Por exemplo, para int — a classe Integer, para double — Double, para char — Character, para boolean — Boolean. Essas classes fornecem métodos: Integer.parseInt(), Double.isInfinite(), Character.isLetter(), Boolean.parseBoolean() e outros.
Exemplo de obtenção de um objeto Integer a partir de um primitivo int:
// Primitivo
int a = 10;
// Objeto wrapper
Integer b = Integer.valueOf(10);
Na variável a está armazenado o próprio número 10. Já a variável b armazena uma referência a um objeto que, internamente, contém 10.
2. Para que servem os wrappers
Um primitivo é sempre um valor concreto; não é possível atribuí-lo a null. Um objeto pode não existir e armazenar um valor vazio — isso é útil quando é preciso indicar “desconhecido” ou “ausente”.
Primitivos não têm métodos. Não dá para chamar em um número algo como x.toString(). O wrapper oferece essas possibilidades: Integer.parseInt("123") transforma uma string em número, e um número pode ser transformado em string com toString().
Em resumo: wrappers são necessários onde se exige um objeto — possibilidade de armazenar null, chamar métodos, passar valores para APIs que aceitam apenas objetos (por exemplo, coleções do tipo List<Integer>).
Lista completa de tipos wrapper
| Tipo primitivo | Classe wrapper |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3. Empacotamento e desempacotamento
Quando você cria manualmente um objeto wrapper, você pega o primitivo e o “empacota” dentro de um objeto:
int primitive = 42;
Integer wrapper = Integer.valueOf(primitive); // empacotamento
Para obter de volta o valor primitivo — “desempacotar” — usa-se, por exemplo, intValue():
Integer wrapper = Integer.valueOf(42);
int primitive = wrapper.intValue(); // desempacotamento
Autoboxing (autoempacotamento)
O compilador adiciona automaticamente a chamada a valueOf(), quando você atribui um primitivo a uma variável wrapper:
int a = 10;
Integer b = a; // autoboxing (Integer.valueOf(a))
Unboxing (desempacotamento automático)
A situação inversa — quando um objeto wrapper é usado onde se espera um primitivo:
Integer c = 20;
int d = c; // unboxing (c.intValue())
int a = 10; // primitivo
Integer b = a; // autoboxing
Integer c = Integer.valueOf(20);
int d = c; // unboxing
4. Armadilhas
Comparação de wrappers. O operador == para objetos compara referências, não valores:
Integer m = 200;
Integer n = 200;
System.out.println(m == n); // false, porque são objetos diferentes
O Java faz cache de wrappers numéricos no intervalo de -128 a 127, por isso às vezes == retornará true e às vezes — false. Para comparar valores, use sempre equals():
Integer x = 100;
Integer y = 100;
System.out.println(x == y); // true, no cache
System.out.println(x.equals(y)); // true, comparação por valor
NullPointerException ao fazer unboxing. Se o wrapper é null e você tenta desempacotá-lo — você obterá uma exceção:
Integer value = null;
int primitive = value; // Erro! NullPointerException
Desempenho e memória. Wrappers são mais lentos que primitivos e ocupam mais memória. Em trechos quentes (hot paths) do código e ao trabalhar com grandes arrays de números, prefira primitivos.
5. Exemplos
Exemplos com Integer e Double
Conversão de string para número:
String text = "123";
int number = Integer.parseInt(text);
System.out.println(number); // 123
Verificando valores especiais de ponto flutuante:
double d = 1.0 / 0;
System.out.println(Double.isInfinite(d)); // true
double nan = 0.0 / 0.0;
System.out.println(Double.isNaN(nan)); // true
Exemplos com Character
char armazena um único caractere; o wrapper Character fornece verificações práticas:
char ch = 'A';
Character wrapper = ch; // autoboxing
System.out.println(Character.isLetter(ch)); // true
System.out.println(Character.isDigit(ch)); // false
System.out.println(Character.toLowerCase(ch)); // 'a'
Exemplos com Boolean
O primitivo boolean é apenas true/false. O wrapper Boolean permite armazenar também null:
Boolean flag = null; // permitido
flag = Boolean.TRUE; // constante especial
System.out.println(flag); // true
Conversão de strings em valores lógicos:
String s1 = "true";
String s2 = "false";
boolean b1 = Boolean.parseBoolean(s1);
boolean b2 = Boolean.parseBoolean(s2);
System.out.println(b1); // true
System.out.println(b2); // false
GO TO FULL VERSION