Duas famílias: primitivos e referências
Todo valor em Java tem um tipo, e esse tipo pertence a uma de duas famílias. Os tipos primitivos guardam um valor bruto diretamente: um número, um único caractere ou um verdadeiro/falso. Os tipos de referência guardam uma referência (um ponteiro) para um objeto que vive em outro lugar na memória: String, arrays e toda classe que você ou as bibliotecas definem.
A distinção importa porque os primitivos são leves e copiados por valor, enquanto as variáveis de referência apontam para objetos compartilhados. Comece pelos oito primitivos: eles são a base sobre a qual tudo o mais é construído.
Os oito tipos primitivos
Java tem exatamente oito tipos primitivos embutidos. Seis são números, um é um caractere e um é um booleano:
Algumas coisas que vale notar de início: os sublinhados em 2_000_000 são apenas separadores visuais que o compilador ignora, os sufixos L e f são obrigatórios (mais sobre isso abaixo), e char usa aspas simples, enquanto uma String usaria aspas duplas.
Escolhendo um tipo numérico
Você quase nunca precisa de byte ou short - eles só economizam memória em arrays enormes. As decisões reais são entre int/long para inteiros e float/double para decimais.
| Tipo | Tamanho | Use quando |
|---|---|---|
int | 32 bits | O padrão para inteiros (até ~2,1 bilhões) |
long | 64 bits | Valores acima de ~2 bilhões: timestamps em milissegundos, tamanhos de arquivo |
double | 64 bits | O padrão para decimais - boa precisão |
float | 32 bits | Apenas quando a memória é escassa e a precisão pode sofrer |
A armadilha é o overflow. Um int dá a volta silenciosamente quando ultrapassa sua faixa - nenhum erro, apenas uma resposta errada:
maxInt + 1 estoura para -2147483648 porque ambos os operandos são int e o resultado continua sendo um int. Converter um dos lados para long primeiro faz a conta em 64 bits. Quando um valor pode ser grande - especialmente milissegundos desde 1970 - recorra a long.
Literais e seus sufixos
Um literal numérico simples tem um tipo padrão, e isso prega peças nas pessoas. 100 é um int; 3.14 é um double. Para escrever um literal long ou float, você precisa adicionar um sufixo:
Tire o L de 8_000_000_000L e o código não compilará, porque o literal excede a faixa de int antes mesmo de chegar à variável long. Tire o f de 0.5f e o Java reclama que um double não pode ser atribuído a um float sem uma conversão. O sufixo não diferencia maiúsculas de minúsculas, mas use o L maiúsculo - um l minúsculo parece exatamente o dígito 1.
char é um número disfarçado
Um char armazena uma unidade de código Unicode de 16 bits, o que significa que ele também funciona como um pequeno inteiro sem sinal. Você pode fazer aritmética com ele e convertê-lo de um lado para o outro com uma conversão (cast):
Isso é ocasionalmente útil para deslocar letras, mas não conte com isso para texto - é para isso que existe a String. Note que char usa aspas simples ('A'); aspas duplas ("A") criam uma String de um único caractere, que é um tipo completamente diferente.
Valores padrão (e a pegadinha das variáveis locais)
Campos e elementos de arrays que você não inicializa recebem um valor padrão sensato. Mas isso só se aplica a campos e posições de arrays: variáveis locais não recebem nenhum valor padrão, e usar uma antes de atribuir um valor é um erro de compilação, não uma surpresa em tempo de execução.
Se, em vez disso, você escrevesse int x; System.out.println(x); dentro de main, o compilador o rejeitaria com "variable x might not have been initialized". Esse rigor é uma vantagem: impede que você leia lixo. Os valores padrão a lembrar: tipos numéricos 0, boolean false, char ' ' e todo tipo de referência null.
A seguir: Strings
String é o tipo de referência que você mais vai usar: texto, valores concatenados, entrada do usuário. Ele se comporta de forma diferente dos primitivos vistos aqui: é um objeto, é imutável e comparar strings tem suas próprias armadilhas. A próxima página aborda isso.
Perguntas frequentes
Quantos tipos de dados existem em Java?
Java tem oito tipos primitivos: byte, short, int, long, float, double, char e boolean. Todo o resto - String, arrays e qualquer objeto - é um tipo de referência. Portanto, a quantidade de primitivos embutidos é fixa em oito, enquanto os tipos de referência são ilimitados, porque você (e as bibliotecas) define novas classes.
Qual é a diferença entre int e long em Java?
Ambos guardam números inteiros, mas int tem 32 bits (faixa de cerca de ±2,1 bilhões) e long tem 64 bits (faixa de cerca de ±9,2 quintilhões). Use int por padrão; mude para long quando um valor puder ultrapassar dois bilhões: timestamps em milissegundos, tamanhos de arquivo, contadores grandes. Um literal long precisa do sufixo L, por exemplo long big = 10000000000L;.
Qual é o valor padrão de um int em Java?
Um campo do tipo int tem como valor padrão 0 - mas apenas campos e elementos de arrays recebem valores padrão. Um long assume 0L, um double 0.0, um boolean false, um char '\u0000' e qualquer tipo de referência null. Variáveis locais não recebem nenhum valor padrão - você precisa atribuir um antes de usá-las, ou o código não vai compilar.