Ordem de prioridades entre método e variavel quando feito extends

Olá tenho uma dúvida que contraria tudo que aprendi até agora, e ainda não encontrei referência bibliográfica pra responder.

Tenho a classe A com uma String i e método conteudo:

package teste;

public class A {
	public String i = "Valor em A";
	
	public void conteudo(){
		System.out.println("Método de A");
	}
}

Logo em seguida crio uma classe B, com uma String i e um método conteudo, com B extendendo a classe A:

package teste;

public class B extends A{
	public String i = "Valor em B";
	
	public void conteudo(){
		System.out.println("Método de B");
	}
}

Então crio um objeto de tipo A com uma estância de B, e então exibo a variavel i, e chamo o método conteudo do meu objeto:

package teste;

public class Exe {

	public static void main(String[] args) {

		A obj = new B();

		System.out.println(obj.i);
		
		obj.conteudo();
	}

}

Resultado:

Valor em A
Método de B

Só que me retorna o valor de i declarado em A, mas o método chama o de B, quando pelo que sabia até hoje, deveria buscar tanto variável, quanto método de B. :shock:

Alguem tem um resposta do porque isso acontece??

Atributos sempre se referem ao tipo declarado.

Métodos sempre se referem ao tipo instanciado.

isto se chama Polimorfismo!!!

oq eh polimorfismo?
http://www.guj.com.br/posts/list/44507.java

ai entra sobscrição…

vc esta sobrescrevendo o metodo conteudo na sua subclasse…
variaveis não são sobrescritas…
depois entra algumas regrinhas de Static… mais ai vai complicar td… vamos deixar assim

// aqui vc tem um Objeto B... em uma variavel de referencia A
A obj = new B();  

// aqui ele esta usando a referencia A e como ele não sobrescreve variaveis ele usa "A.i"
System.out.println(obj.i);  

// aqui ele usa polimorfismo... ele sobrescreve conteudo()... então ele faz assim "B.conteudo()"
obj.conteudo();  

isso e meio confusso no começo… mais demostra o poder que o java tem em relação a Orientação a Objetos…

isso e so o começo…

se vc pretende tirar certificação java (SCJP) vc tem q saber isso do pé ate a cabeça…

espero ter esclarecido alguma coisa ^^

Esta é uma das razões pelas quais acessamos o estado do objeto através de metodos e não de atributos publicos (com raras situações aonde vc lê dados, como algumas constantes e quando vc trabalha com classes final, onde não haverá ambiguidade).

Outro cuidado que vc deve ter:

[code]class A{
private int i=-1;
public int getI() { return this.i; }
public int getI2() { return this.i; }
}

class B extends A{
private int i=666;
public int getI() { return this.i; }
}

// dentro de um main qualquer…
A a = new A();
B b = new B();

// Veja o que aparece nesses acasos!
a.getI();
b.getI2();
a.getI();
b.getI2();[/code]

De modo geral, para lembrar melhor das pegadinhas:

  • Métodos normais (não estáticos) - depende da classe do objeto em si
    Por exemplo, se um método “comer” for declarado na classe Animal e ele for redefinido (overriden) na classe Cachorro, se usarmos algo como:
Animal an = new Cachorro();
an.comer();

será chamado o método “comer” redefinido na classe Cachorro, porque o método depende da classe do objeto, não da variável.

  • Métodos estáticos e variáveis de instância - depende do tipo da variável que referencia o objeto.
    Por exemplo, se uma variável de instância “idade” for declarado na classe Animal e for redefinido (hidden) na classe Cachorro, haverá na verdade duas variáveis de instância com o mesmo nome: Animal.idade e Cachorro.idade. Então se usarmos algo como:
Animal an = new Cachorro();
System.out.println (an.idade);

iremos pegar a variável de instância Animal.idade, não a Cachorro.idade.

[quote=Jeferson_Manetti]isto se chama Polimorfismo!!!

ai entra sobscrição…

vc esta sobrescrevendo o metodo conteudo na sua subclasse…
variaveis não são sobrescritas…
depois entra algumas regrinhas de Static… mais ai vai complicar td… vamos deixar assim

[/quote]

Vlw pelo help pessoal, mas não entendi a questão de variáveis não serem sobrescristas, geralmente não encontramos isso em livros ou textos… Alguem tem alguma referencia pra explicar issto melhor??

Vlw…

Você deve ter bem definido a visibilidade dos métodos e atributos, esse é um dos grandes poderes da orintação a objetos e do java, o Encapsulamento, portanto:

Os atributos devem ser declarados como private e você deve criar métodos public get e set para eles, sendo assim se você usar herança os atributos private não serão herdados.
Então para acessar os valores de um atributo da superclasse com o mesmo nome de atributo da subclasse você usa a palavra super seguida do ponto e do nome do método get - super.getNome()
Caso você não use a palavra super você vai acessar os valores do atributo da subclasse.

Acho que isso deve ajudar.

Bem brothers,

Encontrei referência bibliográfica pra questão:
Livro: A linguagem de programação Java - 4ed.
Autores: Ken Arnold, James Gosling, David Holmes
Capítulo: 3, página 101, Tópico 3.3.3, Acessar Membros Herdaos.

E a questão real é como vocês disseram mesmo: " o tipo de referência, e não a classe real do objeto, determina o campo de qual classe será acessado."

E discutindo com o professor thiago dieb (X25 Brasília), alunos da turma e outras pessoas da área chegamos à seguinte explicação:

Partirmos do princípio onde temos duas classes:

Pessoa

Nome = " Juvenal"
Idade = 67

falar
gritar

Funcionario extends Pessoa

Nome = “Hortencio”
Idade = 34

falar
gritar
trabalhar

Neste momento nós temos alguns conceitos aplicados a esse exemplo, como, herança e o polimorfismo override (sobrescrita).

Quando crio um objeto da Classe Funcionario ele terá 2 atributos e 3 métodos.(obs: ao criar um objeto funcionario ele criar também um objeto pessoa, pois existe um pai).
Funcionario obj = new Funcionario ();

Quando eu criou um objeto da Classe Pessoa ele se comportará com 2 atributos e 2 métodos.
Pessoa obj2 = new Pessoa();

Mas quando eu crio um objeto funcionario dentro de uma variável do tipo pessoa esse processo se modifica.
Pessoa obj3 = new Funcionario();

Primeiro nos podemos fazer isso, porque, funcionario é filha de pessoa assim há uma conexão entre as duas.

Quando geramos um objeto dessa forma como o último exemplos o objeto funcionario se comportará como uma pessoa assimilando o atributo e os métodos da classe pessoa, porém atributos não são sobrescritos enquanto os métodos sim.

O objeto OBJ3 foi criado como funcionario mas será usado como o objeto pessoa, pegando os atributos de pessoa, com relação os métodos houve o nosso conhecido override, assim o temos os atributos de pessoa e os mesmo métodos de pessoa porém agora sobrescritos.

OBS: não podemos mais chamar o método trabalhar, pois, pessoa não contém esse método.

Funcionario agora é tratado como pessoa.

Obrigado pela ajuda de todos!