Der Unterschied zwischen statischen Mitgliedsvariablen und nicht statischen Mitgliedsvariablen
Nehmen Sie das folgende Beispiel als Beispiel
package cn.galc.test;public class Cat { /** * Static member variable*/ private static int id = 0; private String name; } public void info() { System.out.println("Mein Name ist " + name + ",NO." + id); } public static void main(String[] args) { Cat.sid = 100; Cat mimi = new Cat("mimi"); Cat pipi = new Cat("pipi.info();Verstehen Sie den Ausführungsprozess des gesamten Programms, indem Sie Speicheranalysediagramme zeichnen
Beim Ausführen des ersten Satzes des Programms: Cat.sid = 100; ist die SID hier eine statische Mitgliedsvariable. Die statische Variable wird im Datenbereich (Datensegment) gespeichert. Weisen Sie daher zunächst einen kleinen Speicherplatz für die SID zu Nach der Ausführung des Satzes enthält die SID den Wert 100.
Das Speicherlayoutdiagramm sieht derzeit wie folgt aus:
Als nächstes führt das Programm Folgendes aus:
Cat mimi = neue Katze („mimi“);
Hier wird die Konstruktormethode Cat(String name) der Cat-Klasse aufgerufen. Die Konstruktormethode ist wie folgt definiert:
Cat (String name){ this.name = name; Ordnen Sie beim Aufruf zunächst einen kleinen Speicherbereich mm im Stapelspeicher zu, der die Adresse des Instanzobjekts der Cat-Klasse im Heapspeicher enthält. mm ist das Referenzobjekt des Cat-Klassenobjekts im Heapspeicher. Dieser Konstruktor deklariert eine formale Parametervariable vom Typ String, daher wird „mimi“ als tatsächlicher Parameter an den Konstruktor übergeben. Da die String-Konstante im Datenbereich zugewiesen und gespeichert wird, steht im Datenbereich ein besonders kleiner Teil des Speichers zur Verfügung . Wird zum Speichern der Zeichenfolge „mimi“ verwendet. Die Speicherverteilung zu diesem Zeitpunkt ist in der folgenden Abbildung dargestellt:
Wenn Sie den Konstruktor aufrufen, reservieren Sie zunächst einen kleinen Platz im Stapelspeicher für den formalen Parameternamen und übergeben Sie dann die Zeichenfolge „mimi“ als tatsächlichen Parameter an den Namen. Die Zeichenfolge ist ebenfalls ein Referenztyp, mit Ausnahme dieser vier und acht Grundlegende Datentypen, alle anderen sind Referenztypen, daher kann davon ausgegangen werden, dass eine Zeichenfolge auch ein Objekt ist. Dies entspricht also der Übergabe der Referenz des „mimi“-Objekts an name, sodass name nun auf „mimi“ verweist. Das Speicherlayout ist zu diesem Zeitpunkt also wie folgt:
Führen Sie als Nächstes den Code im Konstruktorkörper aus:
this.name=name;
Dies bezieht sich hier auf das aktuelle Objekt, das sich auf die Katze im Heapspeicher bezieht. Hier wird der im Namen im Stapel enthaltene Wert an das Namensattribut des Cat-Objekts im Heapspeicher übergeben, sodass der im Namen enthaltene Wert zu diesem Zeitpunkt auch im Zeichenfolgenobjekt „mimi“ im gefunden werden kann Zu diesem Zeitpunkt ist dieser Name auch ein Referenzobjekt des String-Objekts „mimi“. Über seinen Attributwert kann das im Datenbereich befindliche String-Objekt „mimi“ gefunden werden. Die Speicherverteilung zu diesem Zeitpunkt ist in der folgenden Abbildung dargestellt:
Führen Sie als Nächstes eine weitere Codezeile im Methodenkörper aus:
id=sid++;
Hier wird der Wert von sid an id übergeben, sodass der Wert von id 100 beträgt. Nachdem sid übergeben wurde, addieren Sie 1. Zu diesem Zeitpunkt wird sid zu 101. Das Speicherlayout zu diesem Zeitpunkt ist in der folgenden Abbildung dargestellt.
Zu diesem Zeitpunkt wird die Konstruktormethode aufgerufen und der gesamte von den dieser Konstruktormethode zugewiesenen lokalen Variablen belegte Speicherplatz verschwindet, sodass der im Stapelbereich befindliche Namensspeicher verschwindet. Der Verweis auf das String-Objekt „mimi“ im Datenbereich im Stapelspeicher verschwindet ebenfalls. Zu diesem Zeitpunkt bleibt nur der Verweis auf das String-Objekt „mimi“ im Heap-Speicher übrig. Das Speicherlayout ist zu diesem Zeitpunkt wie folgt:
Als nächstes ausführen:
Cat pipi = new Cat("pipi"); Hier ist der zweite Aufruf der Konstruktormethode Cat(). Der gesamte Aufrufvorgang ist derselbe wie beim ersten Mal. Nach Abschluss des Aufrufs ist das Speicherlayout zu diesem Zeitpunkt wie in der folgenden Abbildung dargestellt:
Die letzten beiden Codezeilen werden durch Aufrufen der info()-Methode gedruckt. Die Druckergebnisse sind wie folgt:
Durch dieses Programm können wir die Rolle dieser statischen Mitgliedsvariablen SID sehen, die gezählt werden kann. Wenn eine neue Katze herauskommt, geben Sie ihr eine Nummer. Lassen Sie es von selbst 1 hinzufügen.
Nachdem das Programm ausgeführt wurde, sieht das gesamte Layout im Speicher wie in der obigen Abbildung dargestellt aus. Wird bis zu dem Moment fortgesetzt, bevor der Hauptmethodenaufruf abgeschlossen ist.
Hier wird die Konstruktormethode Cat(String name) aufgerufen, um zwei Katzen zu erstellen. Zunächst werden zwei kleine Leerzeichen, mimi und pipi, im Stapelspeicher zugewiesen, die die Adressen enthalten, an denen die beiden Katzen gefunden werden können zu den Adressen im Heap-Speicher. Die Konstruktionsmethode deklariert hier eine Variable vom Typ String. Die String-Konstante wird im Datenbereich zugewiesen, sodass die übergebenen Strings mimi und pipi im Datenbereich gespeichert werden. Daher werden dem Datenbereich zwei kleine Speicherblöcke zum Speichern der Zeichenfolgen mimi und pipi zugewiesen, die neben den vier und acht Grunddatentypen auch die Zeichenfolgen „andere“ enthalten Alle Datentypen sind Referenztypen. Sie können sich einen String also als Objekt vorstellen.
Hier sind zwei neue Katzen. Beide Katzen haben ihre eigenen ID- und Namensattribute, daher sind ID und Name hier nicht statische Mitgliedsvariablen, das heißt, es gibt keine statische Änderung. Jedes Mal, wenn eine neue Katze erstellt wird, hat diese neue Katze ihre eigene ID und ihren eigenen Namen, d. h. die nicht statischen Mitgliedsvariablen id und name haben separate Kopien für jedes Objekt. Für statische Mitgliedsvariablen gibt es jedoch nur eine Kopie. Unabhängig davon, wie viele Objekte neu sind, behalten die statischen Mitgliedsvariablen eine Kopie im Datenbereich, auch wenn keine neuen Objekte vorhanden sind. Wie die Sid hier wird die Sid im Datenbereich gespeichert. Unabhängig davon, wie viele neue Katzen sich im Heapspeicher befinden, gibt es nur eine Kopie der Sid und nur eine Kopie wird im Datenbereich gespeichert.
Statische Mitgliedsvariablen gehören zur gesamten Klasse und nicht zu einem bestimmten Objekt. Wie kann man also auf den Wert dieser statischen Mitgliedsvariablen zugreifen? Erstens kann jedes Objekt auf diesen statischen Wert zugreifen und greift beim Zugriff auf denselben Speicher zu. Der zweite Punkt besteht darin, dass Sie auf diesen statischen Wert zugreifen können, auch wenn kein Objekt vorhanden ist. Sie können auf diesen statischen Wert über „Klassenname. Name der statischen Mitgliedsvariablen“ zugreifen, sodass in Zukunft ein bestimmter Klassenname plus „.“ angezeigt wird. gefolgt von Wenn es eine Sache gibt, muss die folgende Sache statisch sein, z. B. „System.out“. Hier wird auf diesen Ausgang über den Klassennamen (Systemklasse) plus „.“ zugegriffen, daher muss dieser Ausgang statisch sein.
Wenn ein Klassenmitglied als statisch deklariert ist, kann auf es zugegriffen werden, bevor ein Objekt der Klasse erstellt wird, ohne dass auf ein Objekt verwiesen werden muss. Das häufigste Beispiel für ein statisches Mitglied ist main(). Da main() aufgerufen werden muss, wenn das Programm mit der Ausführung beginnt, wird es als statisch deklariert.
Als statisch deklarierte Variablen sind im Wesentlichen globale Variablen. Wenn ein Objekt deklariert wird, wird keine Kopie der statischen Variablen generiert, sondern alle Instanzvariablen der Klasse verwenden dieselbe statische Variable. Beispiel: Deklarieren Sie eine statische Variablenanzahl als Anzahl neuer Klasseninstanzen. Für statisch deklarierte Methoden gelten die folgenden Einschränkungen:
(1) Sie können nur andere statische Methoden aufrufen.
(2) Sie können nur auf statische Daten zugreifen.
(3) Sie können in keiner Weise auf this oder super verweisen.
Wenn Sie Ihre statischen Variablen durch Berechnung initialisieren müssen, können Sie einen statischen Block deklarieren. Der statische Block wird nur einmal ausgeführt, wenn die Klasse geladen wird. Das folgende Beispiel zeigt
Die Klasse verfügt über eine statische Methode, einige statische Variablen und einen statischen Initialisierungsblock: public class UserStatic { static int a = 3; static int b; x); System.out.println("a = " + a); System.out.println("b = " + b); } static { System.out.println("Static block initialisiert."); b = a * 4; } public static void main(String args[]) { meth(42); } } Sobald die UseStatic-Klasse geladen ist, werden alle statischen Anweisungen ausgeführt. Zuerst wird a auf 3 gesetzt, dann wird der statische Block ausgeführt (Drucken einer Nachricht) und schließlich wird b auf a*4 oder 12 initialisiert. Dann wird main() aufgerufen, main() ruft meth() auf und übergibt den Wert 42 an x. Die drei println()-Anweisungen beziehen sich auf zwei statische Variablen a und b sowie die lokale Variable x.
Hinweis: Es ist illegal, in einer statischen Methode auf Instanzvariablen zu verweisen.
Hier ist die Ausgabe dieses Programms:
Statischer Block initialisiert. x = 42 a = 3 b = 12
Statische Methoden und Variablen können unabhängig von Objekten außerhalb der Klasse verwendet werden, in der sie definiert sind. In diesem Fall müssen Sie nach dem Klassennamen nur den Punktoperator (.) hinzufügen. Wenn Sie beispielsweise eine statische Methode von außerhalb der Klasse aufrufen möchten, können Sie das folgende allgemeine Format verwenden:
Klassenname.method()
Hier ist Klassenname der Name der Klasse, in der die statische Methode definiert ist. Wie Sie sehen, ähnelt dieses Format dem Format zum Aufrufen nichtstatischer Methoden über Objektreferenzvariablen. Auf eine statische Variable kann im gleichen Format zugegriffen werden – dem Klassennamen plus dem Punktoperator. Auf diese Weise implementiert Java eine kontrollierte Version globaler Funktionen und globaler Variablen.
Zusammenfassen:
(1) Auf statische Mitglieder kann nicht von Instanzen zugegriffen werden, die von der Klasse erstellt wurden, in der sie sich befinden.
(2) Wenn die Mitglieder ohne statische Änderung Objektmitglieder sind, gehören sie jedem Objekt.
(3) Mit Static geänderte Mitglieder sind Klassenmitglieder, die direkt von einer Klasse aufgerufen werden können und allen Objekten gemeinsam sind.
Java Static: Als Modifikator kann er zum Ändern von Variablen, Methoden und Codeblöcken verwendet werden (er darf jedoch keine Klassen ändern).
(1) Variablen ändern:
Eine von allen Objekten einer Klasse gemeinsam genutzte Eigenschaft, auch Klassenvariable genannt. Dies ähnelt globalen Variablen in der C-Sprache. Klassenvariablen werden beim Laden der Klasse initialisiert und nur einmal initialisiert. Wenn ein Objekt im Programm eine statische Variable ändert, sehen andere Objekte den geänderten Wert. Daher können Klassenvariablen als Zähler verwendet werden. Darüber hinaus kann auf statische Java-Variablen direkt über den Klassennamen zugegriffen werden, ohne dass ein Objekt erforderlich ist.
(2) Änderungsmethode:
Eine Funktion, die allen Objekten einer Klasse gemeinsam ist, wird als statische Methode bezeichnet. Auf statische Methoden kann auch direkt über den Klassennamen zugegriffen werden, ohne dass ein Objekt erforderlich ist. Daher kann in statischen Methoden nicht direkt auf nicht statische Variablen und nicht statische Methoden zugegriffen werden, und Schlüsselwörter wie this oder super können in statischen Methoden nicht angezeigt werden.
(3) Java-Codeblöcke ändern:
Verwenden Sie Static, um einen unabhängigen Codeblock in einer Klasse zu ändern, der als statischer Codeblock bezeichnet wird. Statische Codeblöcke werden ausgeführt, wenn die Klasse zum ersten Mal geladen wird, und zwar nur einmal. Statische Codeblöcke haben keine Namen, können also nicht explizit aufgerufen werden, sondern werden von der virtuellen Maschine nur beim Laden der Klasse aufgerufen. Es wird hauptsächlich zum Abschließen einiger Initialisierungsvorgänge verwendet.
(4) Lassen Sie uns über das Laden von Klassen sprechen:
Wenn die JVM eine Klasse zum ersten Mal verwendet, geht sie zu dem durch den Klassenpfad angegebenen Pfad, um die der Klasse entsprechende Bytecode-Datei zu finden, sie in die JVM einzulesen und zu speichern. Dieser Vorgang wird als Klassenladen bezeichnet.
Es ist ersichtlich, dass die Klasse unabhängig davon, ob es sich um eine Variable, eine Methode oder einen Codeblock handelt, solange sie mit Static geändert wird, beim Laden der Klasse „bereit“ ist, dh verwendet werden kann oder ausgeführt wurde. Alle können ohne Objekte ausgeführt werden. Im Gegenteil, wenn keine statische Aufladung vorhanden ist, muss über das Objekt darauf zugegriffen werden.