Por que eu devo ler este artigo:Este artigo é útil a todo desenvolvedor que deseja aprender mais sobre a classe Object e seu papel na estrutura de classes do Java. Neste contexto, serão analisados também três de seus métodos: toString(), equals() e hashCode(). Você vai conhecer a implementação padrão de cada um deles, seus contratos e como as outras classes os utilizam. Além disso, apresentaremos algumas técnicas para que estes métodos sejam implementados com o máximo de eficiência e qualidade.

Ao iniciar no Java, você é apresentado a uma série de frameworks que procuram facilitar o desenvolvimento e aumentar a produtividade. Eles existem aos montes e são utilizados por projetos de todos os tamanhos.

Trabalhando com Java, certamente você irá se deparar com alguns deles em pouco tempo. O primeiro teste que fizer para conectar sua aplicação a um banco de dados já fará uso de um driver que contém a implementação para acessar e manipular um determinado banco de dados. Este drive é um exemplo de framework.

É natural ficar acostumado a estas facilidades e depender delas. Não há nada de errado com isso. Pessoas competentes e com muita experiência trabalharam por muito tempo nesses frameworks, planejando cuidadosamente os recursos disponibilizados e aperfeiçoando-os a cada versão, sempre atentos às necessidade de projetos de outros desenvolvedores.

Obviamente você pode utilizar frameworks sem ter conhecimento de como suas classes foram implementadas, mas você estaria perdendo uma ótima oportunidade de aprender mais sobre Java, programação e lógica em geral explorando o código fonte.

É surpreendente ver como algumas funcionalidades que parecem tão complexas às vezes são implementadas de formas tão simples. Tão impressionante quanto é ver como as classes se integram de forma a colaborarem com o trabalho uma das outras. Por exemplo, você sabia que dentro de um HashSet existe uma HashMap? E que os objetos que você insere no Set são registrados como chave no Map? Esse é o tipo de conhecimento que você obtém ao abrir ambas as classes para, por pura curiosidade, entender como elas funcionam.

A experiência que se adquire com este hábito é algo que nenhum professor, instituição ou artigo vai lhe oferecer. É um conhecimento que tem mais valor porque foi você quem buscou. Você perceberá como seus próximos projetos serão muito beneficiados com todas as novas informações e técnicas que você obteve em sua pesquisa.

Não importa quantos anos você tem ou quantos livros já leu, há sempre mais oportunidades para aprender e tornar-se um profissional melhor do que você foi ontem. E já que a ideia é aprender como as coisas funcionam, existe lugar melhor para começar do que a base?

A classe Object é a principal e mais básica classe do Java. Todas as outras a tem como origem, e, portanto, herdam seus métodos, dos quais três você vai conhecer a fundo neste artigo: toString(), equals() e hashCode(). Estes métodos são importantes, pois definem como seu objeto será identificado, logicamente e visualmente (em formato texto).

Você vai aprender sobre a implementação padrão de cada um deles, seus contratos e em quais situações outras classes os utilizam. E vai conhecer também técnicas para implementá-los com o máximo de eficiência, para que seu código tenha ainda mais qualidade.

O pacote java.lang

Ao começar a explorar uma classe, seja ela do próprio Java ou de algum framework, você perceberá que as classes base do Java, aquelas que integram o pacote java.lang, representam boa parte do código.

Você nunca vai ver o import de uma classe do java.lang, visto que elas são carregadas implicitamente em todas as classes. Mas pode ter certeza que você sempre verá uma String, um Exception ou algum método da classe Object sobrescrito, toString(), por exemplo.

O pacote java.lang é a base do Java. As classes deste pacote representam a fundação da linguagem, o ponto de partida de qualquer outra estrutura que venha a ser construída sobre ela. Isso não quer dizer que sejam simples ou mesmo que seja fácil dominar suas funcionalidades e contratos. Muito pelo contrário: é necessário bastante conhecimento e atenção para utilizar os elementos da base de forma eficiente e correta.

As classes base do Java foram criadas há muito tempo e vêm sendo aperfeiçoadas e refinadas desde então, sem causar qualquer impacto ao que já foi construído as utilizando.

Ao conhecer estas classes e estudá-las, você terá muitos benefícios e saberá exatamente quais ferramentas tem à disposição e como solucionar problemas, outrora misteriosos, mais facilmente.

É impressionante quantos problemas são causados pela ausência ou má implementação de métodos da classe Object. Uma sobrescrita ruim do método toString(), por exemplo, pode confundir muito os usuários de uma classe, assim como os objetos de outra classe podem não interagir como esperado com as coleções do Java devido a uma implementação equivocada dos métodos equals() e hashCode().

Pensando nisso, o foco deste artigo será a classe Object e três de seus métodos: toString(), equals() e hashCode().

A classe Object

Object é a raiz da hierarquia de classes do Java, a superclasse de todas as classes, direta ou indiretamente.

Sendo a base para todas as classes, Object define alguns comportamentos comuns que todos objetos devem ter, como a habilidade de serem comparados uns com os outros, utilizando equals(), poderem ser representados como texto, com o método toString(), e possuírem um número que identifica suas posições em coleções baseadas em hash, com o hashCode().

O método toString().

O método toString() deve retornar um texto conciso e informativo que represente os objetos da sua classe. Este texto deve ser composto pelas informações mais relevantes e únicas dela. Eis alguns exemplos da própria API do Java (veja também a Listagem 1):

  • A representação visual da classe String, é a sequência de caracteres contidos nela;
  • Para um ArrayList, ou qualquer outra subclasse de AbstractCollection, são os elementos presentes na lista separados por vírgula e espaço (“,”) envoltos por colchetes (“[]”);
  • Um objeto da classe Locale é representado pela sigla do idioma em minúsculo seguido pela sigla do país em maiúsculo, separados por underline (“_”).

Listagem 1. Exemplos de retorno de toString().


// String
"John Doe".toString() => John Doe

// ArrayList
vogais.toString() => [a, e, i, o, u]

// Locale
brasilLocale.toString() => pt_BR

Implementando toString()

A implementação original do método toString() encontra-se na classe Object. Ela é bastante simples e faz uso das poucas informações disponíveis em Object para retornar um texto que, embora seja pouco informativo, representa objetos de todas as classes que não sobrescreveram toString().

Ao executar toString() em uma classe Usuario que não sobrescreveu o método, você obterá algo mais ou menos assim: Usuario@0f4b10. A composição original do método toString() é, portanto, o nome da classe, um @ e a representação absoluta do hexadecimal do hash code do objeto da classe.

Podemos melhorar bastante essa implementação sobrescrevendo o método e adicionando informações que realmente auxiliem os usuários a visualizar este objeto como uma String. Considerando que a classe Usuario tenha um atributo email, poderíamos utilizá-lo, visto que é uma informação única. E pra deixar mais completo, podemos adicionar também o atributo nome, result ...

Quer ler esse conteúdo completo? Tenha acesso completo