2013-08-22 23 views
12
Classe

Base:Ereditarietà e oggetto di creazione

public class Inheritance { 
    int i; 
    Inheritance() { 
     System.out.println("I am in base class" + i); 
    } 
} 

classe derivata:

public class TestInheritance extends Inheritance { 

    TestInheritance() { 
     System.out.println("I am in derived class"); 
    } 

    public static void main(String[] args) { 
     TestInheritance obj = new TestInheritance();   
    } 
} 

Questo è quello che ho in mente per quanto riguarda ciò che sta accadendo sopra.

Quando si crea un oggetto della classe derivata per impostazione predefinita, viene chiamato super() e viene chiamato il costruttore della classe base e viene inizializzata la variabile i.

Ora, la mia domanda è: il costruttore in questo caso inizializza solo la variabile i e non crea un oggetto concreto di classe?

Da quello che ho letto finora c'è solo un oggetto creato - della classe derivata che contiene la variabile i.

Ma dal momento in cui viene chiamato il costruttore della classe base e il momento nel punto in cui il costruttore della classe derivata viene chiamato come/dove è memorizzato i?

E quale sarebbe il caso in cui la classe base è astratta.

Mi piacerebbe molto sapere se posso sapere cosa succede nella memoria in diversi punti del tempo.

Se ho detto qualcosa che è fondamentalmente scorretto, per favore fatemelo sapere. Voglio davvero sapere come funziona questa cosa.

+16

@Paniz Uh ... sì lo è? – asteri

+1

Penso che dipenda. Questa domanda è limitata ad un articolo specifico, ha un chiaro esempio per mostrare cosa significa l'OP, non si tratta solo di pescare informazioni generali. È forse qualcosa che è meglio apprendere nel bel mezzo di un mucchio di altre cose, ma finora, almeno, l'OP non ha chiesto un capitolo di un libro, o persino un libro bianco. – arcy

+3

+1 - Una domanda ben strutturata - precisa, ponendo domande specifiche. –

risposta

4

Fisicamente hai creato un singolo oggetto, ma concettualmente hai creato 2. È come quando, per esempio, nasce una bambina: fisicamente è solo una, ma concettualmente è nata una nuova femmina, anche un nuovo essere umano ha nato, un nuovo essere senziente è nato, un nuovo abitante del pianeta Terra è nato, ecc. Sì, esattamente. C'è anche una relazione di ereditarietà (sottotipo), e l'ho fatto apposta. Per evitare confusione, è probabilmente meglio dire che esiste un solo oggetto con diverse sfaccettature; un oggetto che è membro di diverse (super-) classi allo stesso tempo.

Ora, detto abbastanza sulla parte logica, esaminiamo la parte fisica. Il singolo oggetto (fisico) viene creata con la seguente struttura in memoria

+--------------------------+----------------------------+ 
|    B   |    C'   + 
+--------------------------+----------------------------+ 

la prima parte (B) contiene tutti i campi ereditati dalla superclasse B di C (se presente). La seconda parte (C ', e sto usando ' per "complemento") contiene tutti i campi che sono "proprietari" di C (cioè non vengono ereditati da B ma definiti in C stesso). È importante notare che l'oggetto creato non inizia su C ', ma su B. È la combinazione dei campi ereditati con i nuovi campi che costituiscono l'intero oggetto.

Ora, se B ha avuto la propria superclasse A, la struttura sarebbe stato come questo:

+--------+-----------------+----------------------------+ 
| A |  B'   |    C'   + 
+--------+-----------------+----------------------------+ 

Ciò che è importante da notare qui è che B == A + B'. In altre parole, C non ha bisogno di sapere di A. Tutto ciò che importa è la sua superclasse immediata B, che nasconde la sua struttura interna.

di rispondere alle domande specifiche:

Fa il costruttore in questo caso inizializzare solo la variabile i e non crea un oggetto concreto di classe?

Nello stesso modo in cui A, B e C sopra erano strutturalmente concatenati, sono anche concatenati durante l'inizializzazione. Se non fosse così, è come se la ragazza del mio esempio originale fosse nata senza essere una delle altre cose che noi conosciamo anche lei è per definizione. È impossibile. Una contraddizione completa. Quindi, viene effettuato il processo di costruzione di entrambe le classi fuori, che comprende: l'inizializzazione di campi in un valore "zero" (null per i riferimenti e false per boolean 's), e l'esecuzione di un costruttore (che può chiamare altri costruttori).

In questo caso particolare, campo i è inizializzato, un costruttore Inheritance viene eseguita, 'campi (se avesse avuto) sarebbe stato inizializzato s, e quindi un TestInheritance' TestInheritance costruttore s sarebbe stata eseguita. Come possiamo dire esattamente quali costruttori di ogni classe? Relativamente semplice. Ciò che ha avviato tutto è new TestInheritance(). Ciò indica chiaramente che il costruttore di TestInheritance non ha alcun parametro (che esiste, altrimenti ci sarebbe un errore di compilazione). Tuttavia, questo costruttore non richiama esplicitamente alcun costruttore della superclasse (tramite la parola chiave super(...)). Come abbiamo visto sopra, questo non può essere, e il compilatore inserisce automaticamente l'equivalente a super(), cioè una chiamata al costruttore della superclasse senza argomenti (Inheritance()). Ancora una volta, questo costruttore esiste, e tutto è buono. Uscita sarebbe stato:

I am in base class 0 
I am in derived class 

costruttori senza parametri sono chiamati "costruttori di default" per 3 motivi principali: - Di solito sono molto semplici in quanto non hanno parametri. - Sono chiamati automaticamente quando il costruttore di una sottoclasse non chiama esplicitamente alcun costruttore di supeclass. - Vengono forniti automaticamente per quelle classi senza alcun costrutto esplicito scritto dal programmatore. In questo caso il costruttore non fa nulla e ha luogo solo l'inizializzazione.

Da quello che ho letto finora c'è solo un oggetto creato - della classe derivata che ha variabile in esso.

Questo non è del tutto corretto. Fisicamente, è vero che è stato creato un solo oggetto, ma corrisponde alla classe utilizzata con new (TestInheritance), che in questo caso sembra non avere campi, ma questo è irrilevante. In effetti, entrambe le linee di output sono stampate. Concettualmente ... beh, ne abbiamo già parlato.

Ma dal momento in cui viene chiamato il costruttore della classe base e il punto nel tempo in cui il costruttore della classe derivata viene chiamato come/dove è archiviato in memoria?

Quando new TestInheritance() viene eseguito, la prima cosa che accade, prima costruttori sono chiamati anche prima che venga eseguita l'inizializzazione, è che la memoria viene allocata per il intero oggetto. - Di solito questa memoria è "sporca" ed è per questo che deve essere inizializzata. - C'è spazio per i campi di TestInheritance, i campi della sua superclasse e così via. Anche la posizione di ciascun campo all'interno dell'oggetto in memoria è nota in anticipo.

Quindi, anche prima che venga chiamato il costruttore della classe base, esiste già una memoria allocata per i e qualsiasi altro campo, solo che sono "sporchi" (non inizializzati).

E quale sarebbe il caso in cui la classe base è astratta.

Non c'è differenza. L'unico è che non è possibile creare oggetti di una classe astratta da soli. Li crei come parte di una sottoclasse (concreta). Questo è simile al fatto che un nuovo essere umano non può nascere da solo. È una bambina o un bambino.

Mi piacerebbe molto sapere se posso sapere cosa succede in memoria in diversi punti del tempo.

Spero di averlo fatto.

Se ho detto qualcosa che è fondamentalmente scorretto, per favore fatemelo sapere. Voglio davvero sapere come funziona questa cosa.

Niente di "fondamentalmente scorretto".

+0

Un paio di domande: come super() chiama il costruttore predefinito che cosa fa questo costruttore predefinito? E in voi la spiegazione dei campi che provengono dalla super classe B, che li sta inizializzando, il costruttore di C o il costruttore di B? Ed è anche corretto dire che l'oggetto di B è contenuto in C '? – Prateek

+0

Vorrei che ci fossero più modi per esprimere la mia gratitudine. Grazie!!! – Prateek

2

Penso che questa sia un'area comune di confusione sull'ereditarietà. Sembra che tu abbia colto che è stato creato un solo oggetto, è corretto.

Si consiglia di pensare alle variabili di istanza nella classe base come contenute in qualsiasi superclasse, proprio come qualsiasi metodo pubblico o protetto nella classe base è accessibile dalla superclasse.

Quando un oggetto viene istanziato, il runtime java fa ciò che deve fare per allocare lo spazio di archiviazione per tutte le cose per cui lo spazio di archiviazione è necessario - per lo più variabili di istanza. Quindi la variabile di istanza nella classe base può essere pensata come parte di un blocco di memoria che contiene tutte le variabili di istanza per l'oggetto, indipendentemente dal fatto che siano dichiarate nella sottoclasse o nella superclasse.

E una correzione di terminologia: nel codice, la variabile non è "inizializzata" esplicitamente - Penso che ciò che intendi chiedere sia "allocazione", cioè, a che punto la variabile ha il suo spazio nella memoria. "Inizializza" implica che alla variabile è stato assegnato un valore e, sebbene Java sia molto buono nell'assegnare valori predefiniti alle sue variabili, penso che in questo caso sia l'allocazione degli uomini.

+0

+1 buona spiegazione! – alfasin

+0

Concettualmente ho capito perfettamente il tuo punto. Ho qualche domanda però. Cosa succede quando la classe base è astratta? In tal caso, cosa fa super() nella classe derivata. – Prateek