Wir haben das Konzept des „Objekts“ schon früher verwendet, aber wir haben nicht die spezifische Art und Weise besprochen, wie Objekte im Speicher gespeichert werden. Diese Diskussion führt zum wichtigen Konzept der „Objektreferenz“.
Objektreferenz
Wir verwenden weiterhin die zuvor definierte Human-Klasse und haben eine Test-Klasse:
Kopieren Sie den Codecode wie folgt:
Öffentlicher Klassentest
{
public static void main(String[] args)
{
Human aPerson = new Human(160);
}
}
KlasseMensch
{
/**
* Konstruktor
*/
öffentlich Mensch(int h)
{
this.height = h;
}
/**
*Accessor
*/
public int getHeight()
{
return this.height;
}
/**
* Mutator
*/
öffentliche Leere wachsenHöhe(int h)
{
this.height = this.height + h;
}
private int-Höhe;
}
Klassen können extern aufgerufen werden, um Objekte zu erstellen, wie zum Beispiel das oben stehende in der Test-Klasse:
Kopieren Sie den Codecode wie folgt:
Human aPerson = new Human(160);
Es wird ein Objekt der Klasse „Person“ der Klasse „Mensch“ erstellt.
Das Obige ist eine sehr einfache Aussage, aber wir müssen noch auf viele Details eingehen:
1. Schauen Sie sich zunächst die rechte Seite des Gleichheitszeichens an. new eröffnet Platz für Objekte im Speicher. Insbesondere eröffnet new Platz für Objekte im Heap des Speichers. In diesem Bereich werden die Daten und Methoden des Objekts gespeichert.
2. Schauen Sie sich die linke Seite des Gleichheitszeichens an. aPerson bezieht sich auf ein menschliches Objekt, das als Objektreferenz bezeichnet wird. Tatsächlich ist eine Person nicht das Objekt selbst, sondern ähnelt einem Zeiger auf das Objekt. aPerson existiert im Stapel im Speicher.
3. Wenn wir das Gleichheitszeichen verwenden, um einen Wert zuzuweisen, wird der Objektreferenz die Adresse des Objekts zugewiesen, das im Heap von new auf der rechten Seite erstellt wurde.
Der Speicher bezieht sich hier auf den Java-Prozessspeicherraum, der von der JVM (Java Virtual Machine) virtualisiert wird. Informationen zu den Konzepten von Heap und Stack im Speicher finden Sie unter „Linux From Program to Process“.
Der Stapel kann schneller gelesen werden als der Heap, die auf dem Stapel gespeicherten Daten sind jedoch durch den gültigen Bereich begrenzt. Wenn in der C-Sprache ein Funktionsaufruf endet, wird der entsprechende Stapelrahmen gelöscht und die im Stapelrahmen gespeicherten Parameter und automatischen Variablen verschwinden. Auch der Stack von Java unterliegt der gleichen Einschränkung. Wenn ein Methodenaufruf endet, werden die von der Methode auf dem Stack gespeicherten Daten gelöscht. In Java werden alle (normalen) Objekte auf dem Heap gespeichert. Daher besteht die volle Bedeutung des neuen Schlüsselworts darin, ein Objekt auf dem Heap zu erstellen.
Objekte primitiver Typen wie int und double werden auf dem Stapel gespeichert. Wenn wir einen Basistyp deklarieren, ist kein neuer erforderlich. Nach der Deklaration speichert Java primitive Datentypen direkt auf dem Stapel. Daher repräsentiert der Variablenname eines Basistyps die Daten selbst und keine Referenz.
Die Beziehung zwischen Referenzen und Objekten ist wie ein Drachen und eine Person. Wenn wir in den Himmel schauen (im Programm geschrieben), sehen wir einen Drachen (Referenz), aber was dem Drachen entspricht, ist eine Person (Objekt):
Trennung von Referenzen und Objekten; Referenzen verweisen auf Objekte
Obwohl Referenzen und Objekte getrennt sind, muss unser gesamter Zugriff auf Objekte durch die „Tür“ der Referenzen erfolgen, z. B. der Zugriff auf Objektmethoden über reference.method(). In Java können wir Referenzen nicht überspringen und Objekte nicht direkt berühren. Wenn beispielsweise das Datenelement von Objekt a ein gewöhnliches Objekt b ist, speichert das Datenelement von a einen Verweis auf Objekt b (wenn es sich um eine Basistypvariable handelt, speichert das Datenelement von a die Basistypvariable selbst). .
In Java spielen Referenzen die Rolle von Zeigern, aber wir können den Wert des Zeigers nicht direkt ändern, z. B. wie in der Sprache C, indem wir 1 zum Zeigerwert hinzufügen. Wir können Operationen an Objekten nur über Referenzen ausführen. Dieses Design vermeidet viele Fehler, die Zeiger verursachen können.
Referenzzuordnung
Wenn wir eine Referenz einer anderen Referenz zuweisen, kopieren wir tatsächlich die Adresse des Objekts. Beide Referenzen verweisen auf dasselbe Objekt. Beispielsweise führt dummyPerson=aPerson zu:
Ein Objekt kann mehrere Referenzen haben (eine Person kann mehrere Drachen steigen lassen). Wenn ein Programm ein Objekt über eine Referenz ändert, ist die Änderung über andere Referenzen sichtbar. Wir können die folgende Testklasse verwenden, um den tatsächlichen Effekt zu testen:
Kopieren Sie den Codecode wie folgt:
Öffentlicher Klassentest
{
public static void main(String[] args)
{
Human aPerson = new Human(160);
Human dummyPerson = aPerson;
System.out.println(dummyPerson.getHeight());
aPerson.growHeight(20);
System.out.println(dummyPerson.getHeight());
}
}
Unsere Änderungen an aPerson wirken sich auf dummyPerson aus. Diese beiden Referenzen verweisen tatsächlich auf dasselbe Objekt.
Daher wird durch das Zuweisen einer Referenz zu einer anderen Referenz nicht das Objekt selbst kopiert. Wir müssen andere Mechanismen finden, um Objekte zu kopieren.
Müllabfuhr
Wenn der Methodenaufruf endet, werden Referenz- und Primitivtypvariablen gelöscht. Da sich das Objekt auf dem Heap befindet, wird der vom Objekt belegte Speicher nicht gelöscht, wenn der Methodenaufruf endet. Der Prozessraum kann sich schnell mit zu erstellenden Objekten füllen. Java verfügt über einen integrierten Garbage-Collection-Mechanismus zum Löschen von Objekten, die nicht mehr verwendet werden, um Speicherplatz freizugeben.
Das Grundprinzip der Garbage Collection besteht darin, dass das Objekt nicht recycelt wird, wenn ein Verweis auf ein Objekt vorhanden ist. Wenn kein Verweis auf ein Objekt vorhanden ist, wird das Objekt gelöscht. Der Platz, den es einnimmt, wird zurückgewonnen.
In der obigen Abbildung wird der Speicherstatus in der JVM zu einem bestimmten Zeitpunkt angenommen. Das menschliche Objekt verfügt über drei Referenzen: aPerson und dummyPerson aus dem Stapel sowie den Präsidenten, ein Datenelement eines anderen Objekts. Das Clubobjekt hat keinen Bezug. Wenn zu diesem Zeitpunkt die Speicherbereinigung gestartet wird, wird das Clubobjekt geleert und die Referenz des menschlichen Objekts (Präsident) aus dem Clubobjekt wird ebenfalls gelöscht.
Die Garbage Collection ist ein wichtiger Mechanismus in Java, der sich direkt auf die Betriebseffizienz von Java auswirkt. Auf die Details dazu gehe ich später noch ein.
Parameterübergabe
Wenn wir die Konzepte von Referenzen und Objekten trennen, ist der Parameterübergabemechanismus von Java-Methoden tatsächlich sehr klar: Die Übergabe von Java-Parametern erfolgt nach Wert. Das heißt, wenn wir einen Parameter übergeben, erhält die Methode eine Kopie des Parameters.
Tatsächlich ist einer der Parameter, die wir übergeben, eine Variable vom Basistyp und der andere ein Verweis auf das Objekt.
Die Wertübergabe für Variablen vom primitiven Typ bedeutet, dass die Variable selbst kopiert und an die Java-Methode übergeben wird. Änderungen an Variablen durch Java-Methoden haben keinen Einfluss auf die ursprünglichen Variablen.
Die Wertübergabe bedeutet, dass die Adresse des Objekts kopiert und an die Java-Methode übergeben wird. Der auf dieser Referenz basierende Java-Methodenzugriff wirkt sich auf das Objekt aus.
Hier gibt es noch eine weitere erwähnenswerte Situation: Wir verwenden new innerhalb der Methode, um ein Objekt zu erstellen und eine Referenz auf das Objekt zurückzugeben. Wenn die Rückgabe durch eine Referenz empfangen wird und die Referenz des Objekts nicht 0 ist, ist das Objekt immer noch vorhanden und wird nicht durch Garbage Collection erfasst.
Zusammenfassen
neu
Referenz, Objekt
Bedingungen für die Müllabfuhr
Parameter: als Wert übergeben