Dúvida ao chamar super.metodo(). [RESOLVIDO]

Boa noite.

Surgiu uma dúvida nesse código ai:

[code]class Veiculo{
int x = 10;

public void metodo() {
	System.out.println("Valor de x em Veiculo: " + x); //Imprime 10 - OK
}

}

class Carro extends Veiculo{

public void metodo(){
	x = 11; // variável herdada, não altera a variável de instância de Veiculo

	System.out.println("Valor de x em Carro: " + x); // Imprime 11 - OK

	super.metodo(); //Estranhamente imprime 11 ao invés de 10, pq??
	
    new Veiculo().metodo(); //Aqui imprime 10 corretamente
}

}
[/code]

A dúvida é com relação a variável de instância x herdada.
Qual o motivo de a chamada super.metodo() imprimir 11, já que ela chama o método da super classe?

Grato.

Quando vc fez x=10 na classe pai vc criou um atributo de visibilidade ‘padrão’.
A classe filha alterou o valor do atributo herdado da classe pai. Quando vc executou super.metodo vc invocou o codigo original. O que o codigo original faz? acessa this.x que, nesse objeto, vale 11.

Quer ver prevalecer o valor da classe pai? Faça x= 10 ser private.

Acho que vc esta confundindo com o contexto estatico também. Vc não esta acessando um estado na classe pai pois este estado não existe mais :wink:

Quando vc fez a atribuição x = 11 na classe Carro, a variável alterada foi na verdade a da classe Veículo (pois a classe carro não possui uma variável x). Logo após, quando vc faz super.metodo() vc está chamando o método da classe veículo que usa a mesma variável x que vc acabou de alterar.

Na linha de baixo ( new Veiculo().metodo(); ) vc está criando um novo objeto. E esse novo objeto possui o valor de x = 10 normal (vc não alterou ele). Por isso que ao chamar o método “metodo()” dele ele imprime 10.

O fato de uma classe A herdar uma variável de instância da classe B não implica que a classe A irá ter uma cópia da variável. Ela ira usar a mesma variável da classe B.

O termo correto seriam atributos. Gosto de pensar em variaveis como algo que eu crio no escopo de um método (ou bloco de codigo) que ira desaparecer com o termino do mesmo. Pensar em variaveis nesse caso é pensar que podem existir contextos globais como em outras linguagens.

Mas variáveis de instância não é a mesma coisa que atributos?

[quote=peczenyj]Quando vc fez x=10 na classe pai vc criou um atributo de visibilidade ‘padrão’.
A classe filha alterou o valor do atributo herdado da classe pai. Quando vc executou super.metodo vc invocou o codigo original. O que o codigo original faz? acessa this.x que, nesse objeto, vale 11.

Quer ver prevalecer o valor da classe pai? Faça x= 10 ser private.

Acho que vc esta confundindo com o contexto estatico também. Vc não esta acessando um estado na classe pai pois este estado não existe mais ;-)[/quote]

Então o fato de imprimir 11 é simplesmente devido a chamada this.x no método padrão, e this neste contexto se refere ao objeto da classe Carro, é isso?

Tiago, eu discordo.
A variável x é defaul então ela é herdada sim pela subclasse e a variável alterada em Carro é a que essa classe herdou.

[quote=TiagoTC]Na linha de baixo ( new Veiculo().metodo(); ) vc está criando um novo objeto. E esse novo objeto possui o valor de x = 10 normal (vc não alterou ele). Por isso que ao chamar o método “metodo()” dele ele imprime 10.
[/quote]
Concordo, eu vacilei aqui… rsrsrrs

[quote=TiagoTC]
O fato de uma classe A herdar uma variável de instância da classe B não implica que a classe A irá ter uma cópia da variável. Ela ira usar a mesma variável da classe B.[/quote]
Discordo também, se ela foi herdada, é como se ela tivesse sido declarada como atributo da classe Carro.

cara vc esta alterando valor de uma variavel herdada ou seja no objeto que vc esta usando pra chamar o método vc esta realmente alterando o valor dela em Veiculo sim faça o teste com this.x que fica mais facil de enchergar:

[code] public void metodo(){

	this.x = 11;

//aqui seria o equivalente a: c.x = 11; ok?
System.out.println("Valor de x em Carro: " + x);

    super.metodo();
	           
    new Veiculo().metodo(); 

}

public static void main(String[] args) {
	
	Car c = new Car();

	c.metodo();
}[/code]

para resolver o problema vc pode simplesmente declarar um “int x” na classe Car:

[code] public void metodo(){

int x = 100; // ou qualquer outro numero que vc quiser

    System.out.println("Valor de x em Carro: " + x); 
	   
    super.metodo();
	           
    new Veiculo().metodo(); 

}

public static void main(String[] args) {
	
	Car c = new Car();

	c.metodo();
}[/code]

[quote=TiagoTC]
O fato de uma classe A herdar uma variável de instância da classe B não implica que a classe A irá ter uma cópia da variável. Ela ira usar a mesma variável da classe B.[/quote]
Discordo também, se ela foi herdada, é como se ela tivesse sido declarada como atributo da classe Carro.[/quote]

Como assim rmalati? Não existe isso de “redeclaração implícita”. A única forma de a classe Carro ter um atributo próprio é declarando ela explicitamente com int x (colocando o tipo antes, conforme o everton explicou). O que acontece é o seguinte: o método “metodo()” da classe Carro possui a atribuição x = 11. Primeiro ele vai procurar no escopo daquele método a variável x. Como não tem nenhuma declaração, ele vai para o escopo da classe Carro. Como também não tem nenhum atributo x declarado na classe Carro, ele então vai procurar nos atributos da classe que Carro herdou (no caso Veículo). Como Veículo possui x declarado, ele vai usar esse. Mas ele não copia o valor de x ou algo parecido. Ele vai usar exatamente esse x da classe Veículo.

Pouts… num acredito…
agora finalmente eu entendi isso…

Estava enganado mesmo, mas agora clareou.
Eu tinha entendido que se uma classe um membro é como se esta classe tivesse declarado ela mesma.
Herda mesmo, mas existe somente uma variável, a que foi declarada na super classe.

[code]
public class Sobrescricaoteste3 {
public static void main(String [] args){
new Sub().teste();
}
}

class Super{
int x = 222;
public void teste(){
System.out.println("Valor de x em Super = " + this.x);
}
}

class Sub extends Super{
int x = 22;
public void teste(){
this.x = 444;
System.out.println("Valor de x em Sub = " + this.x); // 444
super.teste(); //222 considerando que Sub declara x, se não declarar imprimirá 444 mesmo.
}
}[/code]

Obrigado pessoal, isso ajuda a explicar algumas questões perdidas nos mocks.

É Tiago eu achava que era uma redeclaração implícita mesmo, valeu pela ajuda ai.