2013-08-14 13 views
20

Warum haben in einer Klasse deklarierte Variablen Standardwerte, aber die in Methoden deklarierten Variablen, die als "lokale Variablen" bezeichnet werden, haben keine Standardwerte in Java?Warum haben Instanzvariablen Standardwerte in Java?

Zum Beispiel

class abc 
{ 
    int a; 

    public static void main(String ss[]) 
    { 
     int b; 

      abc aa=new abc(); 
      System.out.println(aa.a); 
      System.out.println(b); 
    } 
} 

In diesem obigen Beispiel variable a hat Standardwert von 0, aber variable b gibt Fehler, dass es vielleicht nicht initialisiert wurde.

+14

'int a' tatsächlich hat einen Standardwert von' 0 '. – Vulcan

+1

Der gesamte Speicherblock des Objekts ist immer mit Nullen gefüllt, deshalb sind alle Variablen in einem Objekt standardmäßig auf 0 gesetzt, "b" ist eine lokale Variable und wird einfach nicht in diesem Teil initialisiert. Es wird initialisiert, wenn ein Wert – x4rf41

+1

zugewiesen wird, aber y b Variable hat keinen Standardwert? –

Antwort

12

Alle Membervariablen müssen in den Heap geladen werden, damit sie beim Erstellen einer Klasseninstanz mit Standardwerten initialisiert werden müssen. Im Falle von lokalen Variablen werden sie nicht in den Heap geladen, sondern im Stack gespeichert, bis sie vor Java 7 verwendet werden. Daher müssen wir sie explizit initialisieren. Nun führt der "Java Hotspot Server Compiler" eine "Escape-Analyse" durch und entscheidet sich dafür, einige Variablen auf dem Stack anstatt auf dem Heap zuzuordnen.

+0

Lokale Variablen in Heap geladen? Hast du bemerkt, dass das OP von einem * int * spricht, was ein primitiver Typ ist? o.O –

+0

Er nimmt 'int' nur als Beispiel. – Ashwani

+0

Wenn Sie jedoch eine lokale Variable 'Object o' haben, lebt die * Referenz * immer noch im Stapel, nicht im Heap. Wenn Sie "o" nicht initialisieren, ist es ein Fehler, es zu verwenden - das Problem besteht darin, die * Referenz * ohne Initialisierung zu verwenden. Wenn Sie einfach 'o = null' verwenden, können Sie es verwenden: Sie haben die Referenz initialisiert, die wiederum im Stapel (nicht im Heap) liegt und nach dieser Initialisierung nichts "in den Heap geladen" wird. Wenn Sie 'o = new Object()' verwenden, dann haben Sie den Heap berührt, aber das allein hat nichts damit zu tun, dass Sie nicht initialisierte lokale Variablen nicht verwenden können. –

2

Lokale Variablen Initialisierung

Variablen in Methoden und in den Blöcken deklariert werden lokale Variablen genannt. Lokale Variablen werden nicht initialisiert, wenn sie beim Methodenaufruf erstellt werden. Daher muss eine lokale Variable explizit vor der Verwendung initialisiert werden. Andernfalls wird der Compiler es als Fehler melden, wenn die Methode oder der Block ausgeführt wird.

Beispiel:

public class SomeClassName{ 

public static void main(String args[]){ 
int total; 
System.out.println("The incremented total is " + total + 3); //(1) 
} 
} 

Der Compiler beklagt, dass die lokale Variable total in println Anweisung verwendet bei (1) kann nicht initialisiert werden. den lokalen Variable Gesamt vor der Verwendung Initialisierung löst das Problem:

public class SomeClassName{ 

public static void main(String args[]){ 
int total = 45; //Local variable initialized with value 45 System.out.println("The incremented total is " + total+ 3); //(1) 
} 
} 

Felder Initialisierung

Wenn keine Initialisierung für eine Instanz oder statische Variable zur Verfügung gestellt wird, wenn entweder erklärt oder in einem Initialisierungsblocks, dann ist es implizit initialisiert mit dem Standardwert seines Typs. Eine Instanzvariable wird jedes Mal, wenn die Klasse instanziiert wird, mit dem Standardwert ihres Typs initialisiert (), dh für jedes Objekt, das aus der Klasse erstellt wird. Eine statische Variable wird mit dem Standardwert ihres Typs initialisiert, wenn die Klasse das erste Mal geladen wird.

+2

Aber die Frage bleibt immer noch unbeantwortet.Selbst wenn lokale Variablen im Stack gespeichert werden, werden ihnen keine Standardwerte zugewiesen. –

+2

Siehe Java-Sprachspezifikation: http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.5 Zitat: "Eine lokale Variable (§14.4, §14.14) muss explizit einen Wert erhalten, bevor es verwendet wird, entweder durch Initialisierung (§14.4) oder Zuweisung (§15.26), in einer Weise, die mit den Regeln für die eindeutige Zuweisung (§16) verifiziert werden kann. " –

+0

@Ankur Sehen Sie sich den letzten Teil --- Felder Initialisierung – Dileep

0

tl; dr: Es war mehr oder weniger eine willkürliche Auswahl

Wenn Sie mich fragen, war es ein Fehler, dass die Java-Standardwerte für die Instanzvariablen hat. Der Compiler hätte den Programmierer zwingen sollen, ihn vorher zu initialisieren, wie es bei lokalen Variablen der Fall ist.

Das Grundprinzip hinter den Standardwerten ist Sicherheit. Wenn ein Objekt instanziiert wird, wird ein Stück Speicher für das Objekt zugewiesen, das enthält, wo die Instanzvariablen auf usw. zeigen. Die Java-Entwickler entschieden, dass es eine gute Idee wäre, diesen Teil des Speichers mit Nullen und Nullen zu löschen. Auf diese Weise werden Sie niemals Müll lesen, der vor der Zuweisung des Objekts vorhanden war. Sie hätten die Initialisierung erzwingen können; Es gibt nichts Grundlegendes an der Wahl.Es hat wahrscheinlich die Implementierung vereinfacht und den Entwicklern von Java einen Sinn gegeben.

Im Fall von lokalen Variablen haben die Entwickler entschieden, die Initialisierung zu erzwingen (oder genauer gesagt, dass sie keine Initialisierung durchführen, wenn eine lokale Variable nur deklariert wird und somit das logischste Verhalten des Compilers ist) war die Initialisierung der Variablen vor der Verwendung zu erzwingen).

+0

Es wäre für den Compiler unmöglich zu wissen, wann ein Instanzelement vor der Zuweisung verwendet wurde. Der Compiler weiß nicht, welche Methode der Klasse zuerst aufgerufen wird. Die gleiche Analyse einer Methode auf der anderen Seite ist sicherlich möglich, da es nur einen Einstiegspunkt gibt. – EJP

+0

@EJP Kotlin scheint einen ziemlich guten Job zu machen, obwohl ... –

+0

Java muss nicht so intelligent sein. – weakish

1

Da lokale Variablen im Stack zugewiesen werden, wird der Speicherbereich für eine lokale Variable zugewiesen, wenn ihm ein Wert zugewiesen wird.

Nehmen einfaches Beispiel

class Abc { 
    int i = -111; 
    int e; 

    int doSomething() { 
     int a = 10; 
     int b = a + i;  
     int c = b + 100; 

     Abc d = new Abc(); 

     e = b + c + d.a; 

     return e + 1000; 
    } 
} 

und den Bytecode von javap -c Abc

Compiled from "Abc.java" 
class Abc { 
    int i; 
    int e; 

    Abc(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: aload_0 
     5: bipush  -111 
     7: putfield  #2     // Field i:I 
     10: return 

    int doSomething(); 
    Code: 
     0: bipush  10 
     2: istore_1 
     3: iload_1 
     4: aload_0 
     5: getfield  #2     // Field i:I 
     8: iadd 
     9: istore_2 
     10: iload_2 
     11: bipush  100 
     13: iadd 
     14: istore_3 
     15: new   #3     // class Abc 
     18: dup 
     19: invokespecial #4     // Method "<init>":()V 
     22: astore  4 
     24: aload_0 
     25: iload_2 
     26: iload_3 
     27: iadd 
     28: aload   4 
     30: getfield  #2     // Field i:I 
     33: iadd 
     34: putfield  #5     // Field e:I 
     37: aload_0 
     38: getfield  #5     // Field e:I 
     41: sipush  1000 
     44: iadd 
     45: ireturn 
} 

Wenn eine Methode einen Speicherplatz in dem aktuellen Frame genannt Stack inovked wird

zugeordnet ist

Wenn Sie genau hinschauen selbst Zuordnung geschieht in einer impliziten Init-Funktion Abc()!

 int a = -111; 

     5: bipush  -111 
     7: putfield  #2     // Field a:I 

Als Feldvariable e einen beliebigen Wert nicht zugeordnet ist, wird es 0, wenn primitive oder null sein, wenn ein Objektverweis

Und wenn Sie doSomething()

sehen
 int a = 10; 
     0: bipush  10 

für eine lokale zu sein verwendet der Anfangswert muss in diesem Fall 10 in den Stapel geschoben werden. Ohne diesen 'push' [Initialisierung] ist der Wert 'a' für nachfolgende Anweisungen nicht zugänglich (da der Wert nicht auf dem Stapel liegt). Sobald der Wert auf den Stack geschoben wurde, werden andere Operationen wie iadd ddore usw. auf dem Stapel ausgeführt

unter Anweisung erstellt tatsächlich ein Objekt auf dem Heap-Speicher und ruft init-Methode auf. Dies ist, wo un initialisierten Variablen wie ‚e‘ Standardwerte bekommt

 15: new   #3     // class Abc 
     18: dup 

ich weiter Bytecode Vergleich bis zu Ihnen verlassen;) aber ich hoffe, es ist klar,

+0

Entscheiden Sie sich. Entweder wird der 'Speicher-Chunk' für eine lokale Variable zugewiesen, wenn ihm ein Wert '*' zugewiesen wird, oder er wird zugewiesen, wenn die Methode eingegeben wird. Nicht beide gleichzeitig. Die 'ipush'-Anweisung drückt den Wert 10, den der unmittelbar folgende 'istore'-Befehl in den Stapelschlitz für' a 'speichert. Der Push erzeugt kein "a". – EJP

Verwandte Themen