Herança

Aula
Estado
  • Uma classe que não especifica uma classe a estender, implicitamente estende a classe Object
 
// iguais public class Product {...} public class Product extends Object {...}
 
  • A classe Object provê as outras classes que a estendem os métodos toString, equals, hashCode, clone, wait, notify e notifyAll(as três últimas são controladores de threads)
  • Quando uma variável recebe é do tipo Produto e recebe uma instância de Vinho (que estende Produto), essa variável terá acesso apenas aos métodos de Produto, mas os dados exclusivos de vinho ainda existiram na área de memória heap. Isso quer dizer que fazendo um cast para Vinho do conteúdo da váriavel será possível acessar esses dados exclusivos novamente
  • Um método de interface default apenas é considerado se a classe que a implemente não tem nenhum método com mesmo contrato, considerando também métodos que venham de uma classe mãe
  • Um método default de uma interface filha tem prioridade sobre um método de mesmo contrato de interface-mãe
public class Produto { public int getId() { return 0; } } public class Vinho extends Produto { public int getNome() { return "Vinho"; } } Produto produto = new Vinho(); produto.getId(); // okay produto.getNome() // compiler error Vinho vinho = (Vinho) produto; produto.getId(); produto.getNome(); // funciona pois continua na mesma instância em heap
  • Com instanceof é possível verificar o tipo de uma instância, evitando causar um erro ao executar um cast de tipo genérico para um tipo específico; retorna false se for null
  • A palavra reservada super retorna uma referência para a classe estendida — por padrão, a Object
  • O construtor da superclasse sempre é a primeira coisa feita pelo construtor da subclasse. Implicitamente o construtor sem parâmetros é invocado, porém, se a superclasse não possuí um construtor sem parâmetros, o compilador gera um erro e o construtor deve ser chamado explicitamente
notion image
  • Não é possível aumentar a privacidade de um método de uma superclasse, apenas diminuí-la
public class Product { private BigDecimal getPrice() {...} public String getName() {...} } public class Wine extends Product { /* opcional, mas recomendada; pois garante que exista um método com a mesma assinatura na superclasse, evitando que um erro de digitação cause um problema */ @Override public BigDecimal getPrice() {...} // funciona @Override private String getName() {...} // não funciona }
  • É possível impedir uma classe de ser estendida através da palavra reservada final
public final class Food extends Product {...} public class Potato extends Food {...}
  • Um método marcado com a palavra reservada final não é substituível através de herança
public class Product { ... public final void calculatePrice(int qty, double tax) {...} ... } public class Food extends Product { ... // não é possível, resultará em erro de compilação public void calculatePrice(int qty, double tax) {...} ... }
  • Uma variável array de tipo Product, que é inicializado com new Food[10](onde Food extends Product) não pode ter um de seus itens de um tipo irmão de Food
public class Food extends Product {...} public class Drink extends Product {...} // isso tá "errado", mas o compilador não lança um erro por arrays serem covariants Product[] products = new Food[10]; // a tipagem Product agora não significa nada e a atribuição abaixo irá lançar um erro proucts[0] = new Drink();