2012-09-06 10 views
7

Quando doees la variabile di istanza viene inizializzata? È dopo il blocco del costruttore è fatto o prima?Quando vengono inizializzate le variabili di istanza e vengono assegnati i valori?

Considerate questo esempio:

public abstract class Parent { 

public Parent(){ 
    System.out.println("Parent Constructor"); 
    init(); 
} 

public void init(){ 
    System.out.println("parent Init()"); 
} 
} 

public class Child extends Parent { 

private Integer attribute1; 
private Integer attribute2 = null; 

public Child(){ 
    super(); 
    System.out.println("Child Constructor"); 
} 

public void init(){ 
    System.out.println("Child init()"); 
    super.init(); 
    attribute1 = new Integer(100); 
    attribute2 = new Integer(200); 
} 

public void print(){ 
    System.out.println("attribute 1 : " +attribute1); 
    System.out.println("attribute 2 : " +attribute2); 
} 
} 

public class Tester { 

public static void main(String[] args) { 
    Parent c = new Child(); 
    ((Child)c).print(); 

} 
} 

USCITA:

Parent Constructor

Child init()

genitore Init()

Bambino Costruttore

attributo 1: 100

attributo 2: null


  1. Quando la memoria per l'attributo 1 & 2 sono allocati nell'heap?

  2. Curioso di sapere perché l'attributo 2 è NULL?

  3. Ci sono difetti di progettazione?

+0

BTW la terminologia Java per la variabile di istanza è "campo". –

risposta

10

Quando la memoria per l'atribute 1 & 2 sono allocati nel mucchio?

La memoria per l'intero oggetto viene allocato quando l'operatore new viene richiamato, prima di inserire il costruttore java.lang.Object. La memoria viene allocata per le singole istanze Integer in init, ma non c'è alcun punto in cui la memoria viene allocata per le singole proprietà, solo interi oggetti.

Curioso di sapere perché l'attributo 2 è NULL?

Il metodo init viene chiamato nel costruttore super, così attribute2 è assegnato new Integer(200), e quindi il costruttore sottoclasse viene richiamato applicabile inizializzatori di proprietà nell'ordine in cui appaiono nel codice sorgente. Questa linea

private Integer attribute2 = null; 

sovrascrive il valore assegnato dal init() a null.

Se si aggiunge una chiamata a

System.out.println("attribute 2 : " +attribute2); 

subito dopo la chiamata a super(); allora questo diventerà evidente.

Ci sono difetti di progettazione?

Chiamare i metodi della sottoclasse prima che la classe base abbia terminato l'inizializzazione è pericoloso. La sottoclasse potrebbe fare affidamento sugli invarianti della sua classe base per proteggere i propri invarianti, e se il costruttore della classe base non è stato completato, allora i suoi invarianti potrebbero non reggere.

È probabile inoltre che confonda i programmatori C++ e simili che si aspetterebbero una chiamata a init dalla classe base per richiamare la versione della classe base poiché C++ riscrive il puntatore vtable man mano che i costruttori vengono immessi.

Vedere The Java Language Specification per tutti i dettagli sanguinosi.

+0

Grazie Mike, Design: intendevo che è una buona pratica eseguire init() da bambino prima del proprio costruttore. Perché qui sconfigge il mio scopo di child init(). qual è il tuo pensiero su questo? – AKh

+0

Inoltre, è buona norma avere le vostre variabili di istanza inizializzate su null o no? – AKh

+0

@AKh In genere è una pratica scorretta chiamare i metodi all'interno del costruttore che possono essere sovrascritti dalle sottoclassi. Non vuoi che le tue sottoclassi siano in grado di rompere la tua classe. –

1

Dopo aver consumato le risposte e link forniti qui è la mia osservazione digerire:


Ecco il flusso:

  1. Enter costruttore della classe del bambino. Child() {...}

  2. Richiamare esplicitamente super() [invocando il costruttore della classe Parent].

  3. Inserisci Parent() {...} costruttore della classe

  4. Invoke implicita super() [invocando classe Object constructor]

  5. Inserisci Object() {} (Nessuna chiamata super-costruttore)

  6. Chiamata ricorsiva per il costruttore di super classe qui.

  7. ritorni per classe Object constructor

  8. Ora in classe Parent costruttore ... inizializzatori istanza e l'istanza inizializzatori variabili della classe padre Viene eseguito.

  9. Resto del costruttore della classe genitore viene eseguito e restituisce

  10. Ora, nel costruttore della classe del bambino. Inizializzatori di istanze e inizializzatori di variabili di istanza della classe Child vengono eseguiti.

  11. Quindi il resto del costruttore della classe Child viene eseguito e termina il processo di inizializzazione dell'oggetto.


La ragione attributo2 era NULL perché

  1. attributo2 viene assegnato un valore di 200 @ passo 9.
  2. Ma sovrascritto su NULL nel passaggio 10

Ci sono difetti di progettazione?

Come menziona Fabian Barney ::::: In genere è una pratica scorretta chiamare i metodi all'interno del costruttore che possono essere sovrascritti dalle sottoclassi.

Quando la memoria per l'attributo 1 & 2 è allocata nell'heap? Ancora in vista. Apprezzo qualsiasi suggerimento.

Grazie per Mike e Fabian

Problemi correlati