Hier ist mein Code:
class A {
static A obj = new A();
static int num1;
static int num2=0;
private A() {
num1++;
num2++;
}
public static A getInstance() {
return obj;
}
}
public class Main{
public static void main(String[] arg) {
A obj = A.getInstance();
System.out.println(obj.num1);
System.out.println(obj.num2);
}
}
Die Ausgabe ist 1 0
, aber ich kann nicht verstehen.
Kann es mir jemand erklären?
Antworten:
In Java finden zwei Phasen statt: 1. Identifizierung, 2. Ausführung
In der Identifikationsphase werden alle statischen Variablen erkannt und mit Standardwerten initialisiert.
Die Werte sind nun:
A obj=null
num1=0
num2=0
Die zweite Phase, die Ausführung , beginnt von oben nach unten. In Java beginnt die Ausführung mit den ersten statischen Elementen.
Hier ist Ihre erste statische Variable
static A obj = new A();
, also wird zuerst das Objekt dieser Variablen erstellt und der Konstruktor aufgerufen, daher der Wert vonnum1
undnum2
wird1
.Und dann
static int num2=0;
wird wieder ausgeführt, was machtnum2 = 0;
.Angenommen, Ihr Konstruktor sieht folgendermaßen aus:
Dies wird ein werfen,
NullPointerException
daobj
noch keine Referenz von hatclass A
.quelle
static A obj = new A();
untenstatic int num2=0;
und Sie sollten 1 und 1 bekommen.A obj = new A(); int num1; int num2 = 0;
Wird in dieser gedreht:A obj; int num1; int num2; obj = new A(); num2 = 0;
. Java tut dies so, dassnum1, num2
es durch den Zeitpunkt definiert wird, zu dem Sie dennew A()
Konstruktor erreichen.static
Wenn der Modifikator auf eine Variablendeklaration angewendet wird, bedeutet dies, dass die Variable eher eine Klassenvariable als eine Instanzvariable ist. Mit anderen Worten ... es gibt nur einenum1
Variable und nur einenum2
Variable.(Abgesehen: eine statische Variable ist wie . Eine globale Variable in einigen anderen Sprachen, mit der Ausnahme , dass sein Name nicht überall sichtbar ist , auch wenn es als deklariert wird
public static
, ist der unqualifizierte Name nur dann sichtbar , wenn es in der aktuellen Klasse oder eine übergeordneten Klasse deklariert wird oder wenn es mit einem statischen Import importiert wird. Das ist der Unterschied. Ein echtes globales ist ohne Qualifikation irgendwo sichtbar.)Wenn Sie sich also auf
obj.num1
und beziehen, beziehenobj.num2
Sie sich tatsächlich auf die statischen Variablen, deren tatsächliche BezeichnungenA.num1
und sindA.num2
. Und in ähnlicher Weise erhöht der Konstruktor, wenn er inkrementiertnum1
undnum2
, dieselben Variablen (jeweils).Die verwirrende Falte in Ihrem Beispiel liegt in der Klasseninitialisierung. Eine Klasse wird standardmäßig initialisiert, indem zunächst alle statischen Variablen initialisiert und dann die deklarierten statischen Initialisierer (und statischen Initialisiererblöcke) in der Reihenfolge ausgeführt werden, in der sie in der Klasse angezeigt werden . In diesem Fall haben Sie Folgendes:
Es passiert so:
Die Statik beginnt mit ihren Standardanfangswerten.
A.obj
istnull
undA.num1
/ oderA.num2
sind Null.Die erste Deklaration (
A.obj
) erstellt eine Instanz vonA()
und den Konstruktor fürA
InkrementeA.num1
undA.num2
. Wenn die Deklaration abgeschlossen istA.num1
undA.num2
beides1
ist undA.obj
sich auf die neu erstellteA
Instanz bezieht .Die zweite Deklaration (
A.num1
) hat keinen Initialisierer undA.num1
ändert sich daher nicht.Die dritte Deklaration (
A.num2
) hat einen Initialisierer, dem Null zugewiesen wirdA.num2
.Am Ende der Klasseninitialisierung
A.num1
ist1
undA.num2
ist also0
... und das zeigen Ihre Druckanweisungen.Dieses verwirrende Verhalten ist darauf zurückzuführen, dass Sie eine Instanz erstellen, bevor die statische Initialisierung abgeschlossen ist, und dass der von Ihnen verwendete Konstruktor von einer noch zu initialisierenden Statik abhängt und diese ändert . Dies sollten Sie in echtem Code vermeiden.
quelle
1,0 ist richtig.
Beim Laden der Klasse werden alle statischen Daten initialisiert oder deklariert. Standardmäßig ist int 0.
static int num1;
nichts tutstatic int num2=0;
dies schreibt 0 bis num2quelle
Dies liegt an der Reihenfolge der statischen Initialisierer. Statische Ausdrücke in Klassen werden von oben nach unten ausgewertet.
Die erste aufgerufen werden soll Konstruktor
A
, die Sätzenum1
undnum2
beide auf 1:static A obj = new A();
Dann,
wird aufgerufen und setzt erneut num2 = 0.
Deshalb ist
num1
1 undnum2
ist 0.Als Randnotiz sollte ein Konstruktor keine statischen Variablen ändern, das ist ein sehr schlechtes Design. Versuchen Sie stattdessen einen anderen Ansatz zur Implementierung eines Singleton in Java .
quelle
Ein Abschnitt in JLS ist zu finden: §12.4.2 .
Die drei statischen Variablen werden also einzeln in Textreihenfolge initialisiert.
So
Wenn ich die Reihenfolge ändere zu:
Das Ergebnis wird sein
1,1
.Beachten Sie, dass dies
static int num1;
kein variabler Initialisierer ist, weil ( §8.3.2 ):Und diese Klassenvariable wird beim Erstellen der Klasse initialisiert. Dies geschieht zuerst ( §4.12.5 ).
quelle
Vielleicht hilft es, so darüber nachzudenken.
Klassen sind Blaupausen für Objekte.
Objekte können Variablen haben, wenn sie instanziiert werden.
Klassen können auch Variablen haben. Diese werden als statisch deklariert. Sie werden also eher für die Klasse als für die Objektinstanzen festgelegt.
Sie können nur eine Klasse in einer Anwendung haben, so dass es sich um einen globalen Speicher handelt, der speziell für diese Klasse entwickelt wurde. Auf diese statischen Variablen kann natürlich von überall in Ihrer Anwendung zugegriffen und geändert werden (vorausgesetzt, sie sind öffentlich).
Hier ist ein Beispiel für eine "Dog" -Klasse, die statische Variablen verwendet, um die Anzahl der von ihr erstellten Instanzen zu verfolgen.
"Hund" -Klasse ist die Wolke, während die orangefarbenen Kästchen "Hund" -Instanzen sind.
Weiterlesen
Hoffe das hilft!
Wenn Sie Lust auf Kleinigkeiten haben, wurde diese Idee zuerst von Platon eingeführt
quelle
Das statische Schlüsselwort wird in Java hauptsächlich für die Speicherverwaltung verwendet. Wir können statische Schlüsselwörter mit Variablen, Methoden, Blöcken und verschachtelten Klassen anwenden. Das statische Schlüsselwort gehört zur Klasse als Instanz der Klasse. Für eine kurze Erläuterung des statischen Schlüsselworts:
http://www.javatpoint.com/static-keyword-in-java
quelle
Viele der obigen Antworten sind richtig. Aber um wirklich zu veranschaulichen, was passiert, habe ich unten einige kleine Änderungen vorgenommen.
Wie oben mehrfach erwähnt, wird eine Instanz der Klasse A erstellt, bevor die Klasse A vollständig geladen ist. Was also als normales "Verhalten" angesehen wird, wird nicht beobachtet. Dies ist nicht allzu unähnlich zum Aufrufen von Methoden aus einem Konstruktor, die überschrieben werden können. In diesem Fall befinden sich Instanzvariablen möglicherweise nicht in einem intuitiven Zustand. In diesem Beispiel befinden sich Klassenvariablen nicht in einem intuitiven Zustand.
Ausgabe ist
quelle
Java initialisiert den Wert eines statischen oder nicht statischen Datenelements erst, wenn es nicht aufgerufen wird, sondern erstellt wird.
so dass hier, wenn num1 und num2 in main aufgerufen werden, es mit Werten initialisiert wird
num1 = 0 + 1; und
num2 = 0;
quelle