Métodos static e herança

Bom, estou estudando para a prova de certificação e já está bem claro que métodos estáticos não são herdados.

Mas, para mim não está tão claro assim. Se os métodos estáticos não são herdados, por que o código abaixo não compila?

public class Animal{
	static void comer(){
		System.out.println("come");
	}
}

class Cachorro extends Animal{
	static void comer() throws Exception{
		System.out.println("racao");
	}
	
}

class Principal{
	static public void main(String[] args){
		Animal a = new Animal();
		Cachorro c = new Cachorro();
		
		Animal.comer();
		Cachorro.comer();
		
	}
}

Se são 2 métodos diferentes, eu deveria conseguir lançar essa exceção.

Obrigado!

Os métodos estáticos são herdados sim. Faz um teste, exclui o método comer() da classe Cachorro que você vai ver que quando executar a classe Principal, será impresso na tela duas vezes a palavra “come”.
Método estático não podem ser sobrescrito, ele será redefinido, e dai você não pode declarar um exceção mais específica no método redefino do que o método da superclasse, bem como acontece com métodos sobrescritos.

Qual a diferença entre subscrever um método e redefinir um método?

No comentário anterior eu disse que métodos estáticos são herdáveis, mas na verdade me equivoquei ao responder muito rápido, eles são apenas acessíveis as classes filhas.

Então métodos estáticos não são herdáveis nem sobrescritos, por isso você não pode chamar o método estático deste modo: super.metodoEstatico(). E também não pode acesso-los através de polimorfismo (Animal a = new Cachorro; ). Nesse caso se você fizer isso: a.comer(); terá impresso na tela “come” e não “racao” e se fosse um método herdado, você teria impresso na tela o conteúdo do método da classe filha, no caso “racao”.

Os métodos estáticos são acessíveis pelas classes filhas, do mesmo modo que qualquer outro outro artefato não private ou final. Mas isso não tem haver com herança e sim com acessibilidade e polimorfismo estático.

Se uma classe filha redefine um método estático da classe pai, ele na verdade está escondendo o acesso ao método da classe pai, isto se chama sobreamento (Shadowing). Sendo assim, a redefinição só acontece para métodos estáticos e as sobrescrita para métodos herdados.

1 curtida

Curioso, deveria ser possível fazer uma declaração assim.
Mas pelo visto os projetistas do Java decidiram incluir a mesma restrição para métodos estáticos, como se eles fossem herdados.
Provavelmente fizeram isso para facilitar a construção do compilador, ou para evitar equívocos.

De qualquer forma, declarar um método estático num filho com o mesmo nome de um método estático no pai é uma má prática.

Bom, é verdade que quem procura sempre acha.

Métodos estáticos realmente não são herdados, segundo nosso amigo sergiotaborda.

http://www.guj.com.br/java/64524-metodos-static

Obrigado a todos e até a próxima.

1 curtida

[quote=PedroAJunior]Bom, é verdade que quem procura sempre acha.

Métodos estáticos realmente não são herdados, segundo nosso amigo sergiotaborda.

http://www.guj.com.br/java/64524-metodos-static

Obrigado a todos e até a próxima.
[/quote]

Hum, eu estava achando extremamente estranho mesmo. Pois temos um modelo que pertence a classe e não a uma instância. Enfim, a explicação do Sergio foi excelente.

Ainda não entendi essa nhaca!

No outro post citado acima o Sergiotaborda diz o seguinte

Intonci por que o código abaixo não dá erro?

class A {
	static void method() {
		System.out.print("It's me A . ");
	}
}

class B extends A {
	static void method() {
		System.out.print("It's me B . ");
	}
	void outro(){
		super.method();
	}
}

class Test {
	public static void main(String[] args) {
		A.method();
		B.method();
		B b = new B();
		b.outro();
	}
}

Obrigado!

Fala, Pedro!

De fato é possível acessar super.metodo() quando este método é estático na classe mãe. Mas isso é possível porque o compilador infere que você está querendo fazer A.method(), no seu exemplo.

O código compilado da chamada super.method() é 0 invokestatic A.method() : void [30]

Percebe que ele substituiu o super por A.

Isso porque o compilador vai escolher o método chamado pelo tipo da variável onde ele é chamado. Um exemplo interessante é esse:

class Animal {
	static void fazBarulho() {
		System.out.println("Grrr");
	}
}

class Cachorro extends Animal {
	
	static void fazBarulho() {
		System.out.println("Au au");
	}
}

class TestaCachorro {
	public static void main(String[] args) {
		Cachorro c = new Cachorro();
		c.fazBarulho(); // Au au
		
		Animal a = new Cachorro();
		a.fazBarulho(); // Grrr
	}
}

O objeto cachorro que está referenciado como “Animal” deixou de latir. Percebe que não houve a sobrescrita do método fazBarulho(). Como o tipo da referência onde foi chamado o método fazBarulho() é “Animal” o comportamento vai ser o definido na classe “Animal”, embora o objeto “Cachorro” devesse ter o comportamento específico de fazer “Au au”.

Só pra ilustrar, o código compilado vai ser:

invokestatic Cachorro.fazBarulho()

e depois

invokestatic Animal.fazBarulho()

Espero ter ilustrado um pouco o porque de não considerarmos sobrescrita do método.

Valeu!

PS - Só agora percebi que refiz o 1o exemplo da thread :smiley: . Mals.