Você pode definir métodos na classe filha da forma que quiser, você apenas não poderá involcá-los a partir de uma variável cujo tipo é o da classe pai.
Considere as seguintes classes:
class Animal {
void print() {
System.out.println("Animal");
}
}
class Gato extends Animal {
void print() {
System.out.println("Gato");
}
void coisaQueSoGatoFaz() {
System.out.println("Apenas gato sabe fazer...");
}
}
class Cachorro extends Animal {
void print() {
System.out.println("Cachorro");
}
void coisaQueSoCachorroFaz() {
System.out.println("Apenas cachorro sabe fazer...");
}
}
public class Teste {
public static void main(String[] args) {
fazAlgumaCoisaComQualquerAnimal( new Animal() );
fazAlgumaCoisaComQualquerAnimal( new Gato() );
fazAlgumaCoisaComQualquerAnimal( new Cachorro() );
}
public static void fazAlgumaCoisaComQualquerAnimal(Animal animal) {
animal.print();
}
}
O método fazAlgumaCoisaComQualquerAnimal
espera receber um Animal como argumento. Java conhece Animal e sabe que ele tem um método print que pode ser invocado e sabe também que o tipo Animal pode conter qualquer outra classe que possa extendê-la.
Logo, Java não permite que você invoque coisaQueSoGatoFaz
a partir de uma variável do tipo Animal, pois esta variável poderia conter qualquer subclasse de Animal e não há como assegurar que cada uma dessas classes possuem um método com a mesma assinatura (nome, lista de parametros e tipo de retorno).
Imagine isso:
void meuMaravilhosMetodo(Animal animal) {
animal.coisaQueSoGatoFaz();
}
Alguém (ou você mesmo) poderia invocar o método acima assim:
meuMaravilhosMetodo( new Gato() );
… e estaria OK, mas este alguém tem toda a liberdade pra fazer isso:
meuMaravilhosMetodo( new Cachorro() );
/* ou */
meuMaravilhosMetodo( new Bufalo() ); // considerando que Bufalo extenda Animal ^^
E se isso acontecer um erro vai ocorrer. Percebe como nem faz sentido tentar invocar coisaQueSoGatoFaz
ou coisaQueSoCachorroFaz
a partir de um tipo Animal?
Agora uma questão: Então como é que eu consigo invocar o método print e ele imprime a mensagem correta?
Java sabe qual tipo de objeto foi instanciado naquela variável e sabe que ele extende Animal, por isso ele tem absoluta certeza de que este objeto possui um método print, pois o herdou de sua super classe.
Por isso ele permite que invoquemos este método, pois é um método que ele pode garantir que existirá em qualquer subclasse de Animal.
Eu sei, repeti muito Animal e coisas assim, mas foi um jeito didático que encontrei para tentar explicar, espero que seja útil.