quarta-feira, 9 de setembro de 2009

Construtores e Herança em java

A construção de objetos é feita subindo-se a hierarquia da Classe:

Passo a passo para construção de um objeto em Runtime:

1 - Memória é alocada para o objeto
2 - Variaveis de Instancia recebem valor Default
3 - Verifica-se se Parametros e argumentos tem mesmo tipo,ordem,quantidade
4 - Tem this explicito? Se tiver executa this, isso se this for chamada a outro construtor
5 - Chamar super(), implicito ou explicito(De qualquer modo ele sempre é chamado)
6 - Executa-se os inicializados das variáveis de instancia(Explicitos)
7 - Executa - se o bloco_de_codigo do construtor

Considerações:
- O passo 1 e passo 2 somente são feitos uma vez
- O passo 4 só é considerado se tiver uma CHAMADA this sozinha a outro construtor.
- O passo 5 sempre é feito, independente se explicitamente ou implicitamente, só não é feito em java.lang.Object porque ele ja é TOPO da hierarquia.
- O passo 6 é considerado SOMENTE quando você inicializa a variavel quando declara
Exemplo:


public int variable = 20;

Se a inicialização for feita dentro do construtor é considerado passo 7:

public int variable;

public Classe(){
variable = 20;

}

Oque acontece se houver uma chamada a this?

Se houver uma chamada explicita a this para outro construtor, entra outro construtor e incia-se do numero 3 em diante.

Oque é aload_0?
aload_0 é o this, ou seja uma referência a Constant Pool, que depois será Runtime Constant Pool e consequentemente com dynamic Linking a Heap


Posso ter this e super no mesmo construtor?

Sabemos que this ou super devem esta na primeira linha do construtor, logo se temos this não temos super e se temos super não temos this, Pois ambos tem que estar na primeira linha do construtor.



Vejamos um exemplo:




public class Pessoa{

private String name;
private String endereco;
private int numeroCasa;


public Pessoa(String name,String endereco,int numeroCasa){
this.name= name;
this.endereco = endereco;
this.numeroCasa = numeroCasa;


}

public Pessoa(String name,String endereco){
this(name,endereco,0);

}



public static void main(String array[ ]){

Pessoa maria = new Pessoa("Maria","Rua das flores");


}

}

Em Sintaxe bytecode temos:


Compiled from "Pessoa.java"
public class Pessoa extends java.lang.Object{
public Pessoa(java.lang.String, java.lang.String, int);
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."init>:()V
4: aload_0
5: aload_1
6: putfield #2; //Field name:Ljava/lang/String;
9: aload_0
10: aload_2
11: putfield #3; //Field endereco:Ljava/lang/String;
14: aload_0
15: iload_3
16: putfield #4; //Field numeroCasa:I
19: return

public Pessoa(java.lang.String, java.lang.String);
Code:
0: aload_0
1: aload_1
2: aload_2
3: iconst_0
4: invokespecial #5; //Method "":(Ljava/lang/String;Ljava/lang/String;I)V
7: return

public static void main(java.lang.String[]);
Code:
0: new #6; //class Pessoa
3: dup
4: ldc #7; //String Maria
6: ldc #8; //String Rua das flores
8: invokespecial #9; //Method "":(Ljava/lang/String;Ljava/lang/String;)V
11: astore_1
12: return

}





No frame main, podemos verificar alguns passos:


Code:
0: new #6; //class Pessoa
3: dup
4: ldc #7; //String Maria
6: ldc #8; //String Rua das flores
8: invokespecial #9; //Method "init>":(Ljava/lang/String;Ljava/lang/String;)V
11: astore_1
12: return


Passo a passo:


1 - Memória é alocada para o objeto
2 - Variaveis de Instancia recebem valor Default

Podemos considerar instruções iguais em:
0: new #6; //class Pessoa
3: dup


Code:
0: new #6; //class Pessoa
3: dup
4: ldc #7; //String Maria
6: ldc #8; //String Rua das flores
8: invokespecial #9; //Method "init>":(Ljava/lang/String;Ljava/lang/String;)V

Na instrução 8, ele invoca o construtor da propria Classe e passa como parametros oque esta na Operand stack logo estamos no Construtor da classe.
Isso indica que é da própria classe: porque antes de não tem especificação de classe nenhuma //Method "init>": Na verdade o init seria com <>...init estaria entre os <>...é que o blog da problemas com isso.

Vamos para o passo 3 do passo a passo:

3 - Verifica-se se Parametros e argumentos tem mesmo tipo,ordem,quantidade

Logo após feita e confirma o passo 3, estamos dentro do construtor da classe Pessoa

public Pessoa(java.lang.String, java.lang.String);
Code:
0: aload_0
1: aload_1
2: aload_2
3: iconst_0
4: invokespecial #5; //Method "init>":(Ljava/lang/String;Ljava/lang/String;I)V
7: return

Nesse construtor na instrução:
4: invokespecial #5; //Method "init>":(Ljava/lang/String;Ljava/lang/String;I)V

Percebemos que estamos no passo 4 do passo a passo
4 - Tem this explicito? Se tiver executa this, isso se this for chamada a outro construtor
Aqui tem this explicito, logo vamos pra o outro construtor da classe:(Perceba que o construtor invocou esse outro construtor, veja que eles tem Argumentos diferentes)

public Pessoa(java.lang.String, java.lang.String, int);
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: aload_0
5: aload_1
6: putfield #2; //Field name:Ljava/lang/String;
9: aload_0
10: aload_2
11: putfield #3; //Field endereco:Ljava/lang/String;
14: aload_0
15: iload_3
16: putfield #4; //Field numeroCasa:I
19: return



Repete-se o processo:

3 - Verifica-se se Parametros e argumentos tem mesmo tipo,ordem,quantidade
4 - Tem this explicito? Se tiver executa this, isso se this for chamada a outro construtor - Nesse caso não tem chamada a this dentro do construtor

5 - Chamar super(), implicito ou explicito(De qualquer modo ele sempre é chamado), Podemos ver isso na instrução:
1: invokespecial #1; //Method java/lang/Object.init>:()V
nessa linha de codigo, nota-se que tem uma invocação na classe:

java/lang/Object
e é o construtor indicado pelo: "
init>":()V
Ou seja invoca-se o construtor da classe java.lang.Object, A superClasse de toda classe em java.Na verdade a instrução
init> esta faltando um <....é que o blog da problema pois trabalha como edição em html também...mais na verdade seria algo assim...< ....init> com o <>



Na classe java.lang.Object temos o teste novamente:

3 - Verifica-se se Parametros e argumentos tem mesmo tipo,ordem,quantidade(Não Tem, pois o construtor não tem argumentos e logo não passamos parametros!!!)
4 - Tem this explicito? Se tiver executa this, isso se this for chamada a outro construtor(Não Tem!!!)
5 - Chamar super(), implicito ou explicito(De qualquer modo ele sempre é chamado)(java.lang.Object é root da hierarquia logo , não temos SuperClass)
6 - Executa-se os inicializados das variáveis de instancia(Explicitos)(Não Tem!!!)
7 - Executa - se o bloco_de_codigo do construtor(Não Tem!!!)



Então voltamos para o construtor da classe Pessoa:

6 - Executa-se os inicializados das variáveis de instancia(Explicitos)
Nesse caso não temos, pois as variaveis de instancia forão declaradas somente e não inicializadas ao declarar

7 - Executa - se o bloco_de_codigo do construtor
this.name= name;
this.endereco = endereco;
this.numeroCasa = numeroCasa;
Terminou-se o bloco de codigo.


Clique na imagem para ampliar



É bom lembrar, que se tivermos "n" classes antes de chegar em java.lang.Object o processo é feito em cada uma das SuperClasses até root,

Vejamos o exemplo:





Clique na imagem para ampliar

Nesse caso se instanciarmos um objeto do tipo Chefe, o passo 1 e 2 só são feitos uma vez e o resto dos passos é feito a cada hierarquia ate java.lang.Object...

Exemplo:


new Chefe();

1 - Memória é alocada para o objeto
2 - Variaveis de Instancia recebem valor Default
3 - Verifica-se se Parametros e argumentos tem mesmo tipo,ordem,quantidade
4 - Tem this explicito? Se tiver executa this, isso se this for chamada a outro construtor - Supondo que não temos this explicito
5 - Chamar super(), implicito ou explicito(De qualquer modo ele sempre é chamado)


Construtor da classe Encarregado pois é super de Chefe:

3 - Verifica-se se Parametros e argumentos tem mesmo tipo,ordem,quantidade
4 - Tem this explicito? Se tiver executa this, isso se this for chamada a outro construtor - Supondo que não temos this explicito
5 - Chamar super(), implicito ou explicito(De qualquer modo ele sempre é chamado)

Construtor da classe Funcionario pois é super de Encarregado:

3 - Verifica-se se Parametros e argumentos tem mesmo tipo,ordem,quantidade
4 - Tem this explicito? Se tiver executa this, isso se this for chamada a outro construtor - Supondo que não temos this explicito
5 - Chamar super(), implicito ou explicito(De qualquer modo ele sempre é chamado)


Construtor da classe java.lang.Object pois é super de Funcionario:

3 - Verifica-se se Parametros e argumentos tem mesmo tipo,ordem,quantidade(Não Tem, Construtor da classe java.lang.Object não requer parametros pois não tem argumentos!!!)
4 - Tem this explicito? Se tiver executa this, isso se this for chamada a outro construtor(Não Tem!!!)
5 - Chamar super(), implicito ou explicito(De qualquer modo ele sempre é chamado)(java.lang.Object é root da hierarquia logo , não temos SuperClass)
6 - Executa-se os inicializados das variáveis de instancia(Explicitos)(Não Tem!!!)
7 - Executa - se o bloco_de_codigo do construtor(Não Tem!!!)

Então agora voltamos para a classe Funcionario:

6 - Executa-se os inicializados das variáveis de instancia(Explicitos)
7 - Executa - se o bloco_de_codigo do construtor

Agora vamos para a classe Encarregado:
6 - Executa-se os inicializados das variáveis de instancia(Explicitos)
7 - Executa - se o bloco_de_codigo do construtor

Agora a classe Chefe:
6 - Executa-se os inicializados das variáveis de instancia(Explicitos)
7 - Executa - se o bloco_de_codigo do construtor



Provando que o passo 5 sempre é executado:

public class Test{



}

Em sintax bytecode temos:

Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."init>":()V
4: return

}

Veja que o construtor da classe é acrescentado pelo compilador, e o mesmo faz uma chamada ao construtor da classe Object:
1: invokespecial #1; //Method java/lang/Object."init>":()V

Bom é isso!!!
Basicamente o construtor vai trabalhando com hierarquia de classes,
CYA DUDES!!!

Um comentário: