Herança é um conceito importante na orientação a objetos. A herança é outra forma importante de melhorar a reutilização do código, além da composição. Vimos na composição que composição é a interface funcional de um objeto que é chamado repetidamente. Como veremos, a herança permite reutilizar definições de classe existentes.
Herança de classe
Quando definimos uma classe antes, começamos do zero e definimos cada membro da classe detalhadamente. Por exemplo, a seguinte classe Humana:
Copie o código do código da seguinte forma:
classeHumano
{
/**
*acessador
*/
público int getHeight()
{
retorne esta altura;
}
/**
* mutador
*/
public void growHeight(int h)
{
esta.altura = esta.altura + h;
}
/**
*respiração
*/
respiração do vazio público()
{
System.out.println("hu...hu...");
}
altura interna privada;
}
A partir da definição de classe acima, podemos entender todos os detalhes da classe: os membros de dados da classe, os métodos da classe e a interface da classe.
Agora precisamos definir uma nova classe, como a classe Woman, e assumir que a classe Woman é bastante semelhante à classe Human:
Humano e Mulher
Podemos começar do zero e definir completamente a classe Woman como antes:
Copie o código do código da seguinte forma:
classe Mulher
{
/**
*acessador
*/
público int getHeight()
{
retorne esta altura;
}
/**
* mutador
*/
public void growHeight(int h)
{
esta.altura = esta.altura + h;
}
/**
*respiração
*/
respiração do vazio público()
{
System.out.println("hu...hu...");
}
/**
* novo método
*/
público Humano giveBirth()
{
System.out.println("Dar à luz");
retorno (novo Humano(20));
}
altura interna privada;
}
Um programador terá muitos problemas ao escrever o programa acima. Muitas definições foram escritas na classe Human, mas precisamos digitá-las novamente. A classe Woman apenas adiciona um novo método giveBirth() (este método cria e retorna um novo objeto Human).
Usando herança, podemos evitar a duplicação acima. Deixe a classe Woman herdar da classe Human, e a classe Woman terá automaticamente as funções de todos os membros públicos da classe Human.
Usamos a palavra-chave extends para indicar herança:
Copie o código do código da seguinte forma:
classe Mulher estende Humano
{
/**
* novo método
*/
público Humano giveBirth()
{
System.out.println("Dar à luz");
retorno (novo Humano(20));
}
}
Dessa forma, economizamos muita digitação. Através da herança, criamos uma nova classe, chamada classe derivada. A classe herdada (Humana) é chamada de classe base (classe base). A classe derivada usa a classe base como base para sua própria definição e complementa o método giveBirth() que não está definido na classe base. A relação de herança pode ser expressa como:
Herança: a seta aponta para a classe base
Você pode usar a seguinte classe Test para testar:
Copie o código do código da seguinte forma:
Teste de classe pública
{
público estático void principal(String[] args)
{
Mulher aMulher = new Mulher();
aMulher.growHeight(120);
System.out.println(aWoman.getHeight());
}
}
Camada derivada
Através da herança, criamos a classe Woman. Todo o processo pode ser dividido em três níveis: definição de classe base, definição de classe derivada e uso externo.
O nível de definição da classe base é definir uma classe normalmente, como a definição da classe Humana acima.
Do ponto de vista dos usuários externos (como um objeto da classe Woman criado na classe Test), a classe derivada possui uma interface externa unificada:
Para usuários externos, a interface acima é suficiente. Apenas da perspectiva da interface, não há nada de especial nas classes derivadas.
No entanto, os programadores devem ter cuidado ao trabalhar no nível de definições de classes derivadas:
Primeiro, a interface é mista: os métodos getHeight() e growHeight() vêm da classe base, enquanto o método giveBirth() é definido dentro da classe derivada.
Existem outras complicações. Anteriormente, pudemos acessar livremente os membros da classe dentro da classe (usando isso para nos referirmos ao objeto). Porém, quando estamos dentro do escopo de definição da classe Woman, não podemos acessar os membros privados da classe base Human. Lembramos o significado de private: membros private são apenas para uso interno da classe. A classe Mulher é uma nova classe diferente da classe Humana, portanto está localizada fora da classe Humana. Em uma classe derivada, os membros privados da classe base não podem ser acessados.
Mas o interessante é que nossos métodos growHeight() e getHeight() ainda funcionam. Isso mostra que os membros privados da classe base existem, mas não podemos acessá-los diretamente.
Para esclarecer o conceito, precisamos entender o mecanismo de geração de objetos de classes derivadas. Quando criamos um objeto de uma classe derivada, Java na verdade cria primeiro um objeto de classe base (subobjeto) e adiciona Os outros membros definidos pela classe derivada constituem um objeto de classe derivada. O que os usuários externos podem ver são os membros públicos da classe base e das classes derivadas. Conforme mostrado abaixo:
Objetos de classe base e objetos de classe derivada
A cor amarela na imagem é o objeto da classe base. Os membros da camada base podem acessar uns aos outros (use isso na definição da classe Humana para se referir ao objeto da classe base).
A parte azul é o novo conteúdo do objeto derivado. Chamo essa parte de camada derivada. As partes azul e amarela juntas formam o objeto derivado. Os membros da camada derivada podem acessar uns aos outros (isso na definição de Mulher). Além disso, também podemos acessar os membros públicos da camada base. Por esse motivo, usamos a palavra-chave super para nos referirmos ao objeto da classe base e usamos super.member para representar os membros base (públicos).
Quando estamos na camada derivada (ou seja, ao definir a classe Woman), não podemos acessar os membros privados da base vermelha. Quando estamos fora, não podemos acessar nem os membros privados da camada derivada roxa nem os membros privados da camada base vermelha.
(Os membros privados da camada derivada têm restrições de acesso, portanto são marcados com uma barra. Os membros privados da camada base têm mais restrições de acesso, portanto são marcados com uma barra cruzada)
Super é semelhante a isso e também é um parâmetro implícito. Quando estamos em níveis diferentes de definição de classe, isso terá significados diferentes. Tenha cuidado com as palavras-chave this e super.
(Java não força o uso deste e super. Java pode identificar automaticamente a propriedade dos membros em muitos casos. Mas acho que esta é uma boa prática.)
protegido
Anteriormente, introduzimos duas palavras-chave relacionadas à permissão de acesso, privada e pública, que controlam a visibilidade externa dos membros. Agora, apresentamos uma nova palavra-chave de acesso: protegido.
Os membros marcados como protegidos são visíveis nesta classe e em suas classes derivadas. Este conceito é fácil de entender. Ou seja, os membros protegidos da classe base podem ser acessados pela camada derivada, mas não podem ser acessados externamente, conforme mostrado abaixo:
substituição de método
A interface externa do objeto de classe derivada é composta, em última análise, pelos membros públicos do objeto de classe base e pelos membros públicos da camada derivada. Se os membros públicos da classe base e os membros públicos da camada derivada tiverem o mesmo nome, qual deles será exibido na interface Java?
Já mencionamos em construtores e sobrecarga de métodos que Java usa o nome do método e a lista de parâmetros para determinar o método a ser chamado. Um método é determinado pelo nome do método e pela lista de parâmetros. No problema acima, se apenas os nomes dos métodos forem iguais, mas as listas de parâmetros forem diferentes, os dois métodos serão apresentados à interface ao mesmo tempo, o que não nos causará nenhum problema. Ao fazer uma chamada externa, Java decidirá qual método usar (sobrecarga de método) com base nos parâmetros fornecidos.
E se o nome do método e a lista de parâmetros forem iguais? Ao derivar a camada, também podemos usar super e this para determinar qual método é. Quando externo, apresentamos apenas uma interface unificada, portanto não podemos fornecer dois métodos ao mesmo tempo. Nesse caso, Java renderizará os métodos da camada derivada em vez dos métodos da camada base.
Este mecanismo é chamado de substituição de método. As substituições de método podem ser bem utilizadas para modificar métodos de membros da classe base. Por exemplo, na camada derivada, ou seja, ao definir Mulher, você pode modificar o método breath() fornecido pela classe base:
Copie o código do código da seguinte forma:
classe Mulher estende Humano
{/**
* novo método
*/
público Humano giveBirth()
{
System.out.println("Dar à luz");
retorno (novo Humano(20));
}
/**
* substituir Human.breath()
*/
respiração do vazio público()
{
super.respiração();
System.out.println("su...");
}
}
Observe que estamos na camada derivada neste momento e ainda podemos chamar o método breath() do objeto da classe base por meio de super. Quando chamamos a classe Woman externamente, devido à substituição do método, não podemos mais chamar o método do objeto da classe base.
A substituição de método mantém a interface do objeto da classe base e usa a implementação da camada derivada.
Construtor
Depois de compreender os conceitos de objetos de classe base e camadas derivadas, os métodos de construção de classes derivadas são mais fáceis de entender.
Precisamos definir um construtor com o mesmo nome da classe na definição da classe derivada. Neste construtor:
1. Como o objeto da classe base é criado e inicializado primeiro ao criar um objeto derivado, o construtor da classe base deve ser chamado primeiro. Podemos usar a instrução super(lista de argumentos) para chamar o construtor da classe base.
2. Após a criação do objeto da classe base, comece a construir a camada derivada (inicializando os membros da camada derivada). Este é o mesmo que o método de construção geral, consulte o método de construção e a sobrecarga do método
Por exemplo, no programa a seguir, a classe Human possui um construtor:
Copie o código do código da seguinte forma:
classeHumano
{
/**
* construtor
*/
humano público (int h)
{
esta.altura = h;
}
/**
*acessador
*/
público int getHeight()
{
retorne esta altura;
}
/**
* mutador
*/
public void growHeight(int h)
{
esta.altura = esta.altura + h;
}
/**
*respiração
*/
respiração do vazio público()
{
System.out.println("hu...hu...");
}
altura interna privada;
}
A definição da classe derivada da classe Woman e seu método de construção:
Copie o código do código da seguinte forma:
classe Mulher estende Humano
{
/**
* construtor
*/
Mulher pública (int h)
{
super(h); // construtor da classe base
System.out.println("Olá, Pandora!");
}
/**
* novo método
*/
público Humano giveBirth()
{
System.out.println("Dar à luz");
retorno (novo Humano(20));
}
/**
* substituir Human.breath()
*/
respiração do vazio público()
{
super.respiração();
System.out.println("su...");
}
}
Resumir
estende
substituição de método
protegido
super.membro, super()