Java é uma linguagem orientada a objetos. Isso significa que tudo em Java consiste em classes e seus objetos, e obedece aos paradigmas da OOP (programação orientada a objetos). Um desses paradigmas é a herança, um mecanismo em Java pelo qual uma classe pode herdar os recursos (campos e métodos) de outra classe. Simplificando, em Java, herança significa criar novas classes baseadas nas existentes.
Principais atores da herança em Java
- Herança é o conceito de que uma classe pode repetir parcial ou completamente as propriedades e métodos de seu pai (a classe da qual ela herda).
- Uma classe filha, ou subclasse, ou classe estendida, ou classe derivada é uma classe que herda de outra classe.
- Uma classe pai, superclasse ou classe base é uma classe que possui várias funções e essas funções podem ser passadas (herdadas) por outra classe (classe filha).
- A substituição de método está alterando o comportamento de um método de classe derivado. Geralmente, esse é um comportamento mais específico e refinado. Se você substituir um método no herdeiro que já está na classe pai, ele substituirá o método pai.
- Uma classe pode ter apenas uma classe ancestral, mas cada classe pode ter muitos “filhos”.
Como funciona
A cadeia de herança é direcionada da classe mais abstrata para a mais concreta. Ou seja, a superclasse é a mais abstrata da cadeia de classes. Freqüentemente, é denotado como abstrato (classe base que não requer implementação). Todas as outras classes são mais específicas. Por exemplo, existe uma classe chamada “Gadget”. Ele pode ter um campo (ou estado) de “peso”, capacidade da bateria de campo, nível de carga de campo e métodos (ou comportamento) de “trabalho” e carregamento. Nesse caso, os métodos podem ser abstratos, ou seja, não possuem uma implementação específica. Embora não possamos dizer que tipo de gadget é, é absolutamente qualquer gadget recarregável. Vamos criar uma subclasse Phone da classe Gadget. Ele não precisa mais redefinir peso e bateria, simplesmente os herda do gadget abstrato. Mas o comportamento da obra precisará ser esclarecido. Você também pode adicionar outros campos “tela diagonal”, conectores e assim por diante. Você pode adicionar um novo método “Atualizar sistema operacional”. A seguir, podemos criar mais duas classes e ambas serão herdadas de Phone, Android e iPhone. Ambas as classes herdam todos os campos e métodos do Gadget e do Smartphone, e os métodos podem ser substituídos. A primeira classe necessita do campo “Nome da marca”, enquanto o iPhone não necessita desse campo, pois apenas uma empresa produz esses smartphones.
class Gadget {
…
}
}
//subclass of Gadget class
class Phone extends Gadget {
…
}
//subclass of Phone class
class IPhone extends Phone {
…
}
//subclass of Phone class
class AndroidPhone extends Phone {
…
}
Uma classe filha herda todos os membros públicos e protegidos da classe pai. Não importa em qual pacote a subclasse está. Se a classe filha estiver no mesmo pacote que a classe pai, ela também herdará os membros package-private do pai. Você pode usar membros herdados como estão, substituí-los, ocultá-los ou adicionar novos membros:
- Você pode usar campos herdados diretamente, como qualquer outro campo.
- Você pode declarar um campo na classe filha que tenha o mesmo nome da classe pai. Está escondendo (então é melhor não fazer isso).
- Você pode declarar novos campos na classe filha (aqueles que a classe pai não possui).
- Os métodos herdados podem ser usados diretamente, sem substituição na classe derivada.
- Além disso, você pode escrever um novo método de instância em uma subclasse que tenha a mesma assinatura de um método na classe pai. Este procedimento o substitui.
- Você pode declarar novos métodos na classe filha que não foram declarados na classe Pai.
- Você pode escrever um construtor de subclasse que chame o construtor da superclasse implicitamente ou com a palavra-chave super.
Exemplo
Vamos criar uma classe base MusicalInstrument com campos de peso e marca registrada, bem como um método work() . Também definimos um construtor.
public class MusicalInstrument {
int weight;
String tradeMark;
public MusicalInstrument(int weight, String tradeMark) {
this.weight = weight;
this.tradeMark = tradeMark;
}
public void work() {
System.out.println("the instrument is playing...");
}
}
Não está completamente claro que tipo de instrumento musical é e como tocá-lo. Vamos criar um instrumento mais específico, o violino. Terá os mesmos campos do Instrumento Musical (eles serão chamados no construtor usando a palavra-chave super. Também podemos substituir o método de trabalho e criar um método para definir o violino corda por corda.
public class Violin extends MusicalInstrument {
String master;
String owner;
int age;
boolean isTuned;
public Violin(int weight, String tradeMark, String master, String owner, int age, boolean isTuned) {
super(weight, tradeMark);
this.master = master;
this.owner = owner;
this.age = age;
this.isTuned = isTuned;
}
@Override
public void work() {
System.out.println("THe violin's playing");
}
public void violinTuning () {
System.out.println("I'm tuning 1st string...");
System.out.println("I'm tuning 2nd string...");
System.out.println("I'm tuning 3rd string...");
System.out.println("I'm tuning 4th string...");
}
}
Vamos criar uma classe Demo para testar a classe Violin e ver exatamente como funciona a herança.
public class InheritDemo {
public static void main(String[] args) {
Violin violin = new Violin(1, null, "Amati", "Kremer", 285, false);
violin.violinTuning();
violin.work();
}
}
Neste caso, a saída do programa será a seguinte:
Estou afinando a 1ª corda... Estou afinando a 2ª corda... Estou afinando a 3ª corda... Estou afinando a 4ª corda... O violino está tocando
Ou seja, se houver um método substituído na classe filha, o método ancestral não será mais chamado. E se não estiver lá? Ou seja, a aula de Violino fica assim:
public class Violin extends MusicalInstrument {
String master;
String owner;
int age;
boolean isTuned;
public Violin(int weight, String tradeMark, String master, String owner, int age, boolean isTuned) {
super(weight, tradeMark);
this.master = master;
this.owner = owner;
this.age = age;
this.isTuned = isTuned;
}
// @Override
// }
public void violinTuning () {
System.out.println("I'm tuning 1st string...");
System.out.println("I'm tuning 2nd string...");
System.out.println("I'm tuning 3rd string...");
System.out.println("I'm tuning 4th string...");
}
}
A saída é:
Estou afinando a 1ª corda... Estou afinando a 2ª corda... Estou afinando a 3ª corda... Estou afinando a 4ª corda... o instrumento está tocando...
Ou seja, o método ancestral será chamado automaticamente. A propósito, a classe filha pode ser definida através do ancestral, ou seja, para realizar upcasting:
Parent parent = new Child()
Esta inicialização é usada para acessar apenas os membros presentes na classe pai e os métodos substituídos. No nosso exemplo seria:
public class InheritDemo {
public static void main(String[] args) {
MusicalInstrument violin = new Violin(1, null, "Amati", "Kremer", 285, false);
//violin.violinTuning();
violin.work();
}
}
Nesse caso, não podemos configurar o método violino. Porém, ao mesmo tempo, o método work() da classe descendente será chamado, se existir.
A hierarquia de classes da plataforma Java
Em Java tudo é feito de classes e elas estão subordinadas a uma hierarquia. Surge a pergunta: existe uma classe da qual todas as outras são herdadas? A resposta é sim, de fato tal classe existe. E é chamado simplesmente Object . A classe Object do pacote java.lang define e implementa comportamento comum a todas as classes, incluindo aquelas que você cria. Na plataforma Java, muitas classes derivam diretamente de Object , outras classes derivam de algumas dessas classes e assim por diante, formando uma hierarquia de classes.Tipos de herança em Java
Vamos destacar alguns tipos de herança em Java. 1. Herança única Este tipo é exatamente como em nosso exemplo acima, as subclasses herdam os recursos de uma superclasse. Na imagem abaixo, a classe A serve como classe base para a classe derivada B. 2. Herança multinível Esta é apenas uma cadeia de herança, ou seja, existe uma classe base A, a classe B é herdada dela e a classe C é herdado da classe B. Em Java, uma classe não pode acessar diretamente os membros dos avós. 3. Herança Hierárquica Na Herança Hierárquica, uma classe serve como superclasse (classe base) para mais de uma subclasse. Acima, demos um exemplo da classe Phone, que pode ter dois “filhos” — AndroidPhone e IPhone.
class A {
public void printA() {
System.out.println("A");
}
}
class B extends A {
public void printB() {
System.out.println(" B"); }
}
class C extends A {
public void printC() {
System.out.println("C");
}
}
class D extends A {
public void printD() {
System.out.println("D");
}
}
public class Demo {
public static void main(String[] args)
{
B objB = new B();
objB.printA();
objB.printB();
C objC = new C();
objC.printA();
objC.printC();
D objD = new D();
objD.printA();
objD.printD();
}
}
A saída é:
A B A C A D
4. Herança múltipla, ou seja, a presença de vários ancestrais... mas espere, a herança múltipla clássica não é suportada em Java. Até certo ponto, pode ser implementado não usando classes, mas interfaces.
interface A {
public void printA();
}
interface B {
public void printB();
}
interface C extends A, B {
public void print();
}
class InheritDemo implements C {
@Override
public void print()
{
System.out.println("Print something");
}
@Override
public void printA() {
}
@Override
public void printB() {
}
}
GO TO FULL VERSION