Oi! Vamos falar sobre classes abstratas em Java.Exemplos concretos de classes abstratas em Java - 1

Por que as classes são chamadas de "abstratas"?

Você provavelmente se lembra do que é abstração - discutimos isso antes :) Se você esqueceu, não se preocupe. Lembre-se, é um princípio OOP que diz que, ao projetar classes e criar objetos, você deve representar apenas as propriedades principais da entidade e descartar as secundárias. Por exemplo, se estivermos projetando uma SchoolTeacherclasse, a altura provavelmente não será uma propriedade necessária de um professor. Na verdade, essa característica não é importante para um professor. Mas se estivermos criando uma BasketballPlayerclasse, a altura será uma das características mais importantes. Bem, uma classe abstrataé a "peça de trabalho bruta" mais abstrata para um grupo de classes futuras. A peça de trabalho não pode ser usada diretamente - é muito "áspera". Mas define certo estado característico e comportamento que as classes futuras — os descendentes da classe abstrata — terão.

Exemplos de classes abstratas em Java

Considere um exemplo simples com carros:

public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;
  
   public abstract void gas();

   public abstract void brake();

   public String getModel() {
       return model;
   }

   public void setModel(String model) {
       this.model = model;
   }

   public String getColor() {
       return color;
   }

   public void setColor(String color) {
       this.color = color;
   }

   public int getMaxSpeed() {
       return maxSpeed;
   }

   public void setMaxSpeed(int maxSpeed) {
       this.maxSpeed = maxSpeed;
   }
}
É assim que a classe abstrata mais simples se parece. Como você pode ver, nada de especial :) Por que precisamos disso? Primeiro, fornece a descrição mais abstrata da entidade de que precisamos — um carro. A palavra-chave abstract significa algo aqui. No mundo real, não existe "apenas um carro". Há caminhões, carros de corrida, sedãs, cupês e SUVs. Nossa classe abstrata é simplesmente um "projeto" que usaremos posteriormente para criar classes específicas de carros.

public class Sedan extends Car {
  
   @Override
   public void gas() {
       System.out.println("The sedan is accelerating!");
   }

   @Override
   public void brake() {
       System.out.println("The sedan is slowing down!");
   }
  
}
De muitas maneiras, isso é semelhante ao que falamos nas lições sobre herança. Só que nesse caso tínhamos uma Carclasse cujos métodos não eram abstratos. Mas tal solução tem várias desvantagens que são corrigidas em classes abstratas. Em primeiro lugar, uma instância de uma classe abstrata não pode ser criada:

public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Error! The Car class is abstract!
   }
}
O criador do Java criou esse "recurso" de propósito. Mais uma vez, lembre-se: uma classe abstrata é apenas um modelo para futuras classes "regulares" . Você não precisa de cópias de um projeto, certo? Da mesma forma, não há necessidade de criar instâncias de uma classe abstrata :) E se a Carclasse não fosse abstrata, poderíamos facilmente criar instâncias dela:

public class Car {

   private String model;
   private String color;
   private int maxSpeed;
  
   public void go() {
       // ...some logic
   }

   public  void brake() {
       // ...some logic
   }
}


public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // This is okay. The car is created.
   }
}
Atualmente, nosso programa possui algum tipo de carro incompreensível. Não é um caminhão, nem um carro de corrida, nem um sedã, mas não está muito claro o que é. É o "só um carro" que não existe na realidade. O mesmo exemplo pode ser dado com os animais. Imagine se seu programa tivesse Animalobjetos (" apenas animais "). Não está claro de que tipo é, a que família pertence ou que características possui. Seria estranho ver um em um programa. Não existem "apenas animais" na natureza. Apenas cachorros, gatos, raposas, toupeiras, etc. As classes abstratas nos salvam de " apenas objetos ". Eles nos fornecem o estado e o comportamento da linha de base. Por exemplo, todos os carros devem ter modelo , cor e velocidade máxima, e eles também devem ser capazes de acelerar e frear . É isso. É um projeto abstrato geral que você usará mais tarde para projetar as classes de que precisa. Observação: os dois métodos na classe abstract também são abstract , o que significa que eles não têm nenhuma implementação. O motivo é o mesmo: classes abstratas não criam "comportamentos padrão" para "apenas carros". Eles apenas indicam o que todo carro deve ser capaz de fazer. Dito isso, se você precisar do comportamento padrão, poderá implementar métodos em uma classe abstrata. Java não proíbe isso:

public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       System.out.println("Accelerating!");
   }

   public abstract void brake();
  
   // Getters and setters
}


public class Sedan extends Car {

   @Override
   public void brake() {
       System.out.println("The sedan is slowing down!");
   }

}

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       sedan.gas();
   }
}
Saída do console:
Accelerating!
Como você pode ver, implementamos um método na classe abstrata, mas não o outro. Como resultado, o comportamento de nossa Sedanclasse é dividido em duas partes: se chamarmos seu gas()método, o comportamento é "puxado" da Carclasse pai abstrata e implementamos o brake()método na Sedanclasse. Isso é super conveniente e flexível. Mas nossa classe não é tão abstrata agora, é ? Afinal, ele realmente implementou metade dos métodos. O fato é — e esta é uma característica muito importante — uma classe é abstrata se pelo menos um de seus métodos for abstrato. Um método de dois ou um de mil — não importa. Poderíamos até implementar todos os métodos, sem deixar nenhum abstrato. O resultado seria uma classe abstrata sem nenhum método abstrato. Isso é possível em princípio — o compilador não gerará nenhum erro — mas é melhor não fazer isso, pois priva a palavra abstract de seu significado. Seus colegas programadores também ficarão muito surpresos ao ver isso :/ Dito isso, se um método for marcado como abstrato, cada classe descendente deve implementá-lo ou ser declarada como abstrata. Caso contrário, o compilador lançará um erro. Claro, cada classe só pode herdar uma classe abstrata, então não há diferença entre classes abstratas e regulares em termos de herança. Não importa se herdamos uma classe abstrata ou regular — só pode haver uma classe pai.

Por que Java não tem herança de classe múltipla

Já dissemos que não há herança múltipla em Java, mas não nos aprofundamos realmente no porquê. Vamos tentar fazer isso agora. O fato é que, se Java tivesse herança múltipla, as classes filhas não seriam capazes de decidir qual comportamento escolher. Digamos que temos duas classes: Toastere NuclearBomb:

public class Toaster {
  
  
 public void on() {

       System.out.println("The toaster is on. We're toasting!");
   }
  
   public void off() {

       System.out.println("The toaster is off!");
   }
}


public class NuclearBomb {

   public void on() {

       System.out.println("Boom!");
   }
}
Como você pode ver, ambas as classes têm um on()método. Para a torradeira, o método começa fazendo torradas, mas no caso da bomba nuclear, desencadeia uma explosão. Uh-oh :/ Agora imagine que você decidiu (não me pergunte por quê!) Criar algo intermediário. Aqui está sua classe: MysteriousDevice! Este código não funcionará, é claro. Nós o apresentamos simplesmente como um exemplo de "o que poderia ter sido":

public class MysteriousDevice extends Toster, NuclearBomb {

   public static void main(String[] args) {
      
       MysteriousDevice mysteriousDevice = new MysteriousDevice();
       mysteriousDevice.on(); // And what should happen here? Will we get toast or a nuclear apocalypse?
   }
}
Vamos ver o que temos. O misterioso dispositivo deriva de Toaster e NuclearBomb ao mesmo tempo. Ambos têm um on()método. Como resultado, não está claro qual implementação deve ser executada se chamarmos on()um MysteriousDeviceobjeto. O objeto não entenderá. E ainda por cima, o NuclearBomb não tem um off()método, então se não adivinharmos corretamente, será impossível desligar o dispositivo. Exemplos concretos de classes abstratas em Java - 2Esse "mal-entendido", quando não está claro qual comportamento deve ser executado, é justamente o motivo pelo qual os criadores do Java rejeitaram a herança múltipla. Dito isso, você aprenderá que as classes Java podem implementar muitas interfaces.