Dúvida sobre herança e método sobrescrito

7 respostas
antonioedirane

Me deparei com esta questão no TestKiller e não consegui entender o que aconteceu pra dar o valor 3.
Given

public class Foo {
	public int a;

	public Foo() {
		a = 3;
	}

	public void addFive() {
		a += 5;
	}
}

and

public class Bar extends Foo {
	public int a;

	public Bar() {
		a = 8;
	}

	public void addFive() {
		a += 5;
	}
}

invoked with:

Foo foo = new Bar();
		foo.addFive();
		System.out.println("Value: " + foo.a);

What is the result?
A. Value: 3 (Correta)
B. Value: 8
C. Value: 13
D. Compilation fails.

Não entendi o que ocorreu.

Quanto a sequencia de ordem dos construtores eu entendi.

primeiro executa o construtor de Foo e depois de bar ( Pois é dado new Bar() ).

E em cada um é feito uma atribuição. a=3 e a = 8;

Porque  após dar o new o valor de foo.bar é 3  ?(antes mesmo de chamar addFive )

É porque estou referenciando ele como um Foo em Foo foo = new Bar();   ???

Fiquei mais em dúvida ainda após chamar addFive(), pois o valor continua 3 ??
Porque não adicionou 5, o que será que aconteceu, Escopo de variável Local ? sombreanento de variáveis ?
Me perdi nesta parte, se alguem puder me explicar passo a passo o que ocorreu, me ajudaria bastante .

7 Respostas

GabrielCardelli

Quando você tem uma referencia da Super Classe
As variaveis de instância utilizadas são as da referência , e os métodos do objeto

Ex:

Class a

{

int x = 10;

}
Class b exteds a {

int x = 3;

}

Se eu chamar

a newObj = new b();

newObj.x <~~ Imprime 10

Agora se fosse com métodos era bem ao contrário!!
Cuidado que no polimorfismo tambem se passa pela referência!


Na questão do testkiller
Ele chama o metodo da sub…

Depois a varivel chamada e a da superclasse…
Então… sem complicação 3!

a da sub = 13;
a da super = 3;

O que vale é a referência então 3^^

To repetindo varias vezes pra tu não esquecer^^!

Abraço mano!! Ta sumido do msn hein!

ebortolatto

Nesse caso o “a” da superclasse não é alterado na segunda chamada, pois o addFive da segunda chamada é da referência a Bar, logo o “a” de Foo permanece 3 pois foi inicializado no construtor :wink:

ViniGodoy

O que acontece é que esse problema não se refere nem a herança e nem ao método sobrescrito, mas no hiding. A questão é que é perniciosa, e leva a crer o contrário.

Quando você declara public int a, na subclasse, você está escondendo o atributo de mesmo nome, declarado da mesma forma, na superclasse. Lembre-se que a herança somente ocorre em métodos e que os métodos da superclasse referem-se a variável a da superclasse, enquanto o da subclasse refere-se a variável a da subclasse.

Portanto, a variável a do tipo Foo e Bar é, efetivamente, diferente. Vamos analiza o código linha a linha:

//Cria uma nova instância, ok. Foo foo = new Bar(); //Chama o método addFive() da subclasse. Em método há polimorfismo. Ele adiciona 5 ao a da própria classe Bar. foo.addFive(); //Imprime o atributo a da superclasse, no caso, o a declarado na classe foo. System.out.println("Value: " + foo.a);

Para ser a resposta esperada, você deveria fazer:

Ou então, não fazer hiding e usar um atributo só, afinal de contas, isso é uma grande gambiarra. Ah sim, isso também mostra pq é uma boa deixar o atributo privado. Polimorfismo funciona para getters/setters, mas não para atributos.

B

ViniGodoy:
O que acontece é que esse problema não se refere nem a herança e nem ao método sobrescrito, mas no hiding. A questão é que é perniciosa, e leva a crer o contrário.

Quando você declara public int a, na subclasse, você está escondendo o atributo de mesmo nome, declarado da mesma forma, na superclasse. Lembre-se que a herança somente ocorre em métodos e que os métodos da superclasse referem-se a variável a da superclasse, enquanto o da subclasse refere-se a variável a da subclasse.

Portanto, a variável a do tipo Foo e Bar é, efetivamente, diferente. Vamos analiza o código linha a linha:

//Cria uma nova instância, ok. Foo foo = new Bar(); //Chama o método addFive() da subclasse. Em método há polimorfismo. Ele adiciona 5 ao a da própria classe Bar. foo.addFive(); //Imprime o atributo a da superclasse, no caso, o a declarado na classe foo. System.out.println("Value: " + foo.a);

Para ser a resposta esperada, você deveria fazer:

Ou então, não fazer hiding e usar um atributo só, afinal de contas, isso é uma grande gambiarra. Ah sim, isso também mostra pq é uma boa deixar o atributo privado. Polimorfismo funciona para getters/setters, mas não para atributos.

Exatamente. Isso mostra a importância do encapsulamento como um dos mecanismos de padrões de desenvolvimento.

B

Ola a todos.

Fiquei em duvida com a explicacao do ViniGodoy.
Nao testei o codigo mas apenas olhando a duvida é a seguinte:

Se antes da linha 6 colocarmos um System.out.println(foo) seria impresso o objeto Bar correto?
Em tempo de compilação entendo perfeitamente que a variavel ‘a’ seria de Foo, afinal de contas, o compilador olha o tipo da referência.
Mas em tempo de execucao ‘foo’ seria uma instancia de Bar, logo, a variavel ‘a’ seria referente ao objeto Bar.

Gostaria de saber onde, no meu raciocinio descrito acima, estou errado.

T+

B

Seria impresso o objeto “Bar” somente por causa do método toString() da classe Object.

Em tempo de compilação entendo perfeitamente que a variavel ‘a’ seria de Foo, afinal de contas, o compilador olha o tipo da referência.
Mas em tempo de execucao ‘foo’ seria uma instancia de Bar, logo, a variavel ‘a’ seria referente ao objeto Bar.

Sempre o que valerá será a referência da variável, exceto para membos sobrescritos onde os da instância é que prevalecerão, portanto, como as regras de sobrescrição não se aplicam às variáveis, vai sempre ficar valendo as da referência.

B

Ola brrodo…

Entendi perfeitamente…

valeu!

T+

Criado 10 de junho de 2009
Ultima resposta 14 de jun. de 2009
Respostas 7
Participantes 6