Considere o seguinte código:
class Animal {
void coisaQueQualquerAnimalFaz() { /* ... */ }
}
class Mamifero extends Animal {
void coisaQueSoMamiferoFaz() { /* ... */ }
}
class Cachorro extends Mamifero {
void coisaQueSoCachorroFaz() { /* ... */ }
}
class Programa {
public static void main(String... args) {
Animal x = new Cachorro();
x.coisaQueQualquerAnimalFaz();
x.coisaQueSoMamiferoFaz();
x.coisaQueSoCachorroFaz();
}
}
Logo, sim, posso acessar qualquer método ou atributo das super classes de Cachorro, sejam elas super classes diretas (que é o caso de Mamifero) ou indiretas (que é o caso de Animal), desde que não sejam privados.
Agora pode ser que fique uma questão: Qual a utilidade disso?
Imagine que você vai desenvolver um programa para gerenciar um pet shop. Uma das funções deste programa é cadastrar animais.
class Cachorro {
String nome;
int idade;
}
class PetShop {
void cadastrar(Cachorro x) { /* ... */ }
}
No trecho acima, seu pet shop só poderia cadastrar cachorros, mas e se aparecesse um cliente com um gato ou um passáro?
class Animal {
String nome;
int idade;
}
class Cachorro extends Animal { /* ... */ }
class Gato extends Animal { /* ... */ }
class Passaro extends Animal { /* ... */ }
class PetShop {
void cadastrar(Animal x) { /* ... */ }
}
Da forma como demonstrei acima, nosso pet shop agora é capaz de aceitar qualquer animal; poderiámos fazer isso:
PetShop meuPetShop = new PetShop();
Cachorro a = new Cachorro();
a.nome = "Rex";
a.idade = 2;
Gato b = new Gato();
b.nome = "Tom";
b.idade = 3;
// Para instanciar um Passaro, não preciso criar uma variável do tipo Passaro
// Posso usar o tipo Animal. Isto serve para qualquer sub classe de Animal
Animal c = new Passaro();
c.nome = "Piu Piu";
c.idade = 1;
meuPetShop.cadastrar( a );
meuPetShop.cadastrar( b );
meuPetShop.cadastrar( c );
Bons estudos!