A biblioteca de classes padrão do Java consiste em milhares de classes e outros tipos de referência. Apesar das diferenças em suas capacidades, cada um desses tipos estende direta ou indiretamente o Object
aula. Juntos, eles formam uma enorme hierarquia de herança.
A primeira metade deste tutorial introduziu os fundamentos da herança em Java. Você aprendeu como usar Java extends
e super
palavras-chave para derivar uma classe filha de uma classe pai, invocar construtores e métodos de classe pai, substituir métodos e muito mais. Agora, voltaremos nosso foco para a nave-mãe da hierarquia de herança de classes Java, java.lang.Object
.
Estudo Object
e seus métodos lhe darão uma compreensão mais funcional da herança Java e como ela funciona em seus programas.
O que você aprenderá neste tutorial Java
- Tudo sobre Object: a superclasse do Java
- Como estender o objeto: um exemplo
- O que o método getClass() do Java faz
- O que o método clone() do Java faz
- O que o método equals() do Java faz
- O que o método finalize() do Java faz
- O que o método hashCode() do Java faz
- O que o método toString() do Java faz
- O que os métodos wait() e notify() do Java fazem
Baixe o código-fonte de aplicativos de exemplo neste tutorial. Criado por Jeff Friesen.
Tudo sobre Object: a superclasse do Java
Object
é a classe raiz, ou superclasse final, de todas as outras classes Java. Armazenado no java.lang
pacote, Object
declara os seguintes métodos, que todas as outras classes herdam:
protected Object clone()
boolean equals(Object obj)
protected void finalize()
Class> getClass()
int hashCode()
void notify()
void notifyAll()
String toString()
void wait()
void wait(long timeout)
void wait(long timeout, int nanos)
Uma classe Java herda esses métodos e pode substituir qualquer método que não esteja declarado final
. Por exemplo, o não-final
toString()
método pode ser substituído, enquanto o método final
wait()
métodos não podem.
Veremos cada um desses métodos e como você pode usá-los para executar tarefas especiais no contexto de suas classes Java. Primeiro, vamos considerar as regras e mecanismos básicos para Object
herança.
Como estender o objeto: um exemplo
Uma classe pode estender explicitamente Object
conforme demonstrado na Listagem 1.
Listagem 1. Estendendo explicitamente o objeto
public class Employee extends Object
{
private String name;
public Employee(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public static void main(String() args)
{
Employee emp = new Employee("John Doe");
System.out.println(emp.getName());
}
}
Como você pode estender no máximo uma outra classe (lembre-se da Parte 1 que Java não suporta herança múltipla baseada em classe), você não é forçado a estender explicitamente Object
; caso contrário, você não poderia estender nenhuma outra classe. Portanto, você estenderia Object
implicitamente, conforme demonstrado na Listagem 2.
Listagem 2. Estendendo Objeto Implicitamente
public class Employee
{
private String name;
public Employee(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public static void main(String() args)
{
Employee emp = new Employee("John Doe");
System.out.println(emp.getName());
}
}
Compile a Listagem 1 ou Listagem 2 da seguinte maneira:
javac Employee.java
Execute o aplicativo resultante:
java Employee
Você deve observar a seguinte saída:
John Doe
O que getClass() do Java faz
O getClass()
O método retorna a classe de tempo de execução de qualquer objeto no qual ele é chamado. O classe de tempo de execução é representado por um Class
objeto, que se encontra no java.lang
pacote. Class
também é o ponto de entrada para a API Java Reflection, que um aplicativo Java usa para aprender sobre sua própria estrutura.
O que o método clone() do Java faz
O clone()
O método cria e retorna uma cópia do objeto no qual é chamado. Porque clone()
O tipo de retorno de é Object
a referência do objeto que clone()
os retornos devem ser convertidos para o tipo real do objeto antes de atribuir essa referência a uma variável do tipo do objeto. O código na Listagem 3 demonstra a clonagem.
Listagem 3. Clonando um objeto
class CloneDemo implements Cloneable
{
int x;
public static void main(String() args) throws CloneNotSupportedException
{
CloneDemo cd = new CloneDemo();
cd.x = 5;
System.out.println("cd.x = " + cd.x);
CloneDemo cd2 = (CloneDemo) cd.clone();
System.out.println("cd2.x = " + cd2.x);
}
}
Listagem 3 CloneDemo
classe implementa o Cloneable
interface, que se encontra no java.lang
pacote. Cloneable
é implementado pela classe (através do implements
palavra-chave) para evitar Object
de clone()
método de lançar uma instância do CloneNotSupportedException
classe (também encontrada em java.lang
).
CloneDemo
declara um único int
campo de instância baseado em nome nomeado x
e um main()
método que exercita esta classe. main()
é declarado com um throws
cláusula que passa CloneNotSupportedException
aumentar a pilha de chamadas de método.
main()
primeiras instanciações CloneDemo
e inicializa a cópia da instância resultante de x
para 5
. Em seguida, ele gera a instância x
valor e chamadas clone()
nesta instância, lançando o objeto retornado para CloneDemo
antes de armazenar sua referência. Finalmente, ele gera o clone x
valor do campo.
Compilar Listagem 3 (javac CloneDemo.java
) e execute o aplicativo (java CloneDemo
). Você deve observar a seguinte saída:
cd.x = 5
cd2.x = 5
Substituindo clone()
Não precisamos substituir clone()
no exemplo anterior porque o código que chama clone()
está localizado na classe que está sendo clonada (CloneDemo
). Se a chamada para clone()
estavam localizados em uma classe diferente, então você precisaria substituir clone()
.
Porque clone()
é declarado protected
você receberá um “clone protegeu o acesso no objeto” mensagem se você não a substituiu antes de compilar a classe. A Listagem 4 é uma versão refatorada da Listagem 3 que demonstra a substituição clone()
.
Listagem 4. Clonando um objeto de outra classe
class Data implements Cloneable
{
int x;
@Override
public Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
class CloneDemo
{
public static void main(String() args) throws CloneNotSupportedException
{
Data data = new Data();
data.x = 5;
System.out.println("data.x = " + data.x);
Data data2 = (Data) data.clone();
System.out.println("data2.x = " + data2.x);
}
}
A Listagem 4 declara um Data
classe cujas instâncias devem ser clonadas. Data
implementa o Cloneable
interface para evitar CloneNotSupportedException
de ser jogado quando o clone()
método é chamado. Em seguida, declara int
campo de instância baseado em x
e substitui o clone()
método. O clone()
método executa super.clone()
para chamar sua superclasse (ou seja, Object
de) clone()
método. A substituição clone()
método identifica CloneNotSupportedException
em seu throws
cláusula.
A Listagem 4 também declara um CloneDemo
classe que: instancia Data
inicializa seu campo de instância, gera o valor do campo de instância, clona o Data
objeto e gera seu valor de campo de instância.
Compilar a listagem 4 (javac CloneDemo.java
) e execute o aplicativo (java CloneDemo
). Você deve observar a seguinte saída:
data.x = 5
data2.x = 5
Clonagem superficial
Clonagem superficial (também conhecida como cópia superficial) refere-se à duplicação dos campos de um objeto sem duplicar quaisquer objetos referenciados nos campos de referência desse objeto (se houver algum campo de referência). As listagens 3 e 4 demonstraram, na verdade, clonagem superficial. Cada um dos cd
-, cd2
-, data
-, e data2
-campos referenciados identifica um objeto que possui sua própria cópia do int
-baseado x
campo.
A clonagem superficial funciona bem quando todos os campos são do tipo primitivo e (em muitos casos) quando qualquer campo de referência se refere a imutável objetos (inalteráveis). No entanto, se algum objeto referenciado for mutável, as alterações feitas em qualquer um desses objetos poderão ser vistas pelo objeto original e seu(s) clone(s). A Listagem 5 demonstra.