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
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();