Olá! Em palestras anteriores, já encontramos brevemente o conceito de herança várias vezes. Hoje também abordaremos esse assunto, mas também não muito profundamente. Haverá uma palestra detalhada sobre isso mais tarde, mas hoje veremos apenas exemplos práticos e conheceremos um operador interessante em Java.
Herança Java
Então, o que exatamente é herança? Herança é um mecanismo de programação, incluindo Java, que permite descrever uma nova classe com base em uma existente. A classe descendente então obtém acesso aos campos e métodos da classe pai. Por que isso pode ser necessário? Bom, por exemplo, imagine que você precisa criar diversas classes de carros no programa: Caminhão, Corrida, Sedan, Pickup, etc. Mesmo sem começar a escrever código, você sabe com certeza que essas classes têm muito em comum: todos os carros têm nome de modelo, ano de fabricação, tamanho do motor, velocidade máxima, etc. (sem falar que todos possuem rodas e outras peças). Em tal situação, você pode:- Crie esses campos em cada classe e adicione-os às novas classes de carros quando elas forem criadas
- Mova os campos comuns a todas as máquinas para a classe pai
Car
e todas as classes de tipos específicos de máquinas herdarãoCar
o uso da palavra extends .
public class Car {
private String model;
private int maxSpeed;
private int yearOfManufacture;
public Car(String model, int maxSpeed, int yearOfManufacture) {
this.model = model;
this.maxSpeed = maxSpeed;
this.yearOfManufacture = yearOfManufacture;
}
}
public class Truck extends Car {
public Truck(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
public class Sedan extends Car {
public Sedan(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
No mínimo, evitamos a duplicação desnecessária de código, e isso é algo que devemos sempre buscar ao escrever programas. Além disso, temos uma estrutura de classes simples e compreensível: os campos comuns a todas as máquinas são colocados em uma classe. Se, por exemplo, caminhões possuem alguns campos específicos que outros carros não possuem, eles podem ser declarados na classe Truck
. O mesmo vale para métodos. Todos os carros têm algum comportamento comum que pode ser descrito: ligar o carro, acelerar/frear, etc. Esses métodos gerais podem ser colocados em uma classe geral Car
e o comportamento específico de cada tipo específico pode ser descrito em classes descendentes.
public class Car {
public void gas() {
//...gas
}
public void brake() {
//...brake
}
}
public class F1Car extends Car {
public void pitStop() {
//...only racing cars make pit stops
}
public static void main(String[] args) {
F1Car formula1Car = new F1Car();
formula1Car.gas();
formula1Car.pitStop();
formula1Car.brake();
}
}
Movemos os métodos comuns de todos os carros para a classe Car
. Mas na classe sucessora F1Car
, que descreve os carros de corrida de Fórmula 1 - pit stops (paradas para manutenção urgente do carro), que são feitas apenas em corridas e se diferenciam por um comportamento específico.
Operador Java instanceof
Para verificar se um objeto foi criado com base em uma classe, existe um operador especial em Java -instanceof
. Ele retorna o valor true
se o teste for verdadeiro ou false
se o resultado for falso. Vamos ver como funciona usando nossas classes de carros como exemplo:
public class Truck extends Car {
public static void main(String[] args) {
Truck truck = new Truck();
System.out.println(truck instanceof Car);
}
}
Saída: true A verificação usando o operador instanceof
retornou true
, pois temos um objeto da classe Truck
e todos os caminhões são carros. A classe Truck
é descendente da classe Car
, portanto, todos os caminhões são criados com base em um pai comum - um carro. Preste atenção no operador instanceof
: ele é escrito sem ponto, pois é um operador e não um método (“objeto instância de classe”). Vamos tentar de forma diferente:
public static void main(String[] args) {
Car car = new Car();
System.out.println(car instanceof Truck);
}
Saída: false A classe Car
e, consequentemente, seu objeto não derivam da classe Truck
. Todos os caminhões são carros, mas nem todos os carros são caminhões. Os objetos Car
não são criados com base na classe Truck
. Mais um exemplo:
public static void main(String[] args) {
Car car = new Car();
Truck truck = new Truck();
System.out.println(car instanceof Object && truck instanceof Object);
}
Saída: True A lógica aqui também é simples: todas as classes em Java, incluindo aquelas que você criou, vêm de uma classe Object
(embora você não escreva extends Object nelas - esse mecanismo está implícito nelas). Por que isso pode ser útil e em que circunstâncias? O uso mais comum do operador instanceof
é como substituição de método equals()
. Por exemplo, aqui está como o método é implementado equals
na classe String
:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Antes de comparar a string com o objeto passado, o método verifica: o objeto passado é realmente uma string? E só então ele começa a comparar as propriedades de dois objetos. Sem essa verificação, você poderia passar qualquer objeto que possua campos de valor e comprimento para o método e compará-lo com uma string, o que, obviamente, seria errado.
GO TO FULL VERSION