1. Eigenschaften: Getter und Setter

Wenn ein großes Projekt von Dutzenden von Programmierern gleichzeitig entwickelt wird, treten häufig Probleme auf, wenn diese unterschiedlich mit den in Klassenfeldern gespeicherten Daten umgehen.

Vielleicht versäumen es die Leute, die Unterrichtsdokumentation im Detail zu studieren, oder vielleicht wird nicht jeder Fall beschrieben. Daher kommt es häufig vor, dass die internen Daten eines Objekts „beschädigt“ werden und das Objekt dadurch ungültig wird.

Um diese Situationen zu vermeiden, ist es in Java üblich, alle Klassenfelder privat zu machen . Nur die Methoden der Klasse können die Variablen der Klasse ändern. Keine Methoden anderer Klassen können direkt auf die Variablen zugreifen.

Wenn Sie möchten, dass andere Klassen die Daten in Objekten Ihrer Klasse abrufen oder ändern können, müssen Sie Ihrer Klasse zwei Methoden hinzufügen – eine get-Methode und eine set-Methode. Beispiel:

Code Notiz
class Person
{
   private String name;

   public Person(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }
}


privateNamensfeld



Initialisierung des Feldes über den Konstruktor


getName()– Diese Methode gibt den Wert des Namensfelds zurück




setName()– Diese Methode ändert den Wert des Namensfelds

Keine andere Klasse kann den Wert des Namensfelds direkt ändern. Wenn jemand den Wert des Namensfelds abrufen möchte, muss er die getName() Methode für ein PersonObjekt aufrufen. Wenn ein Code den Wert des Namensfelds ändern möchte, muss er die setName() Methode für ein PersonObjekt aufrufen.

Die getName()Methode wird auch „ Getter für das Namensfeld“ und die setName()Methode „ Setter für das Namensfeld“ genannt.

Dies ist ein sehr verbreiteter Ansatz. In 80–90 % des gesamten Java-Codes werden Sie niemals öffentliche Variablen in einer Klasse sehen. Stattdessen werden sie deklariert private(oder protected) und jede Variable verfügt über öffentliche Getter und Setter.

Dieser Ansatz macht den Code länger, aber zuverlässiger.

Der direkte Zugriff auf eine Klassenvariable ist so, als würde man sein Auto durch doppelte gelbe Linien lenken : Es ist einfacher und schneller, aber wenn es jeder macht, wird es für alle schlimmer.

Nehmen wir an, Sie möchten eine Klasse erstellen, die einen Punkt ( x, y) beschreibt. So würde es ein unerfahrener Programmierer machen:

class Point
{
   public int x;
   public int y;
}

So würde es ein erfahrener Java-Programmierer machen:

Code
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y;
   }
}

Ist der Code länger? Zweifellos.

Sie können Gettern und Settern jedoch eine Parametervalidierung hinzufügen. Sie können beispielsweise sicherstellen, dass xund yimmer größer als Null (oder nicht kleiner als Null) sind. Beispiel:

Code Notiz
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x < 0 ? 0 : x;
      this.y = y < 0 ? 0 : y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x < 0 ?  0 : x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y < 0 ? 0 : y;
   }
}


2. Lebensdauer des Objekts

Sie wissen bereits, dass Objekte mit dem newOperator erstellt werden, aber wie werden Objekte gelöscht? Sie existieren nicht für immer. Dafür reicht der Speicher nicht aus.

In vielen Programmiersprachen, wie zum Beispiel C++, gibt es einen speziellen deleteOperator zum Löschen von Objekten. Aber wie funktioniert das in Java?

In Java ist alles etwas anders angeordnet. Java hat keinen Löschoperator. Bedeutet das, dass Objekte in Java nicht gelöscht werden? Nein, sie werden natürlich gelöscht. Sonst würde den Java-Anwendungen schnell der Speicher ausgehen und von einem unterbrechungsfreien Ablauf der Programme über Monate hinweg wäre keine Rede mehr.

In Java erfolgt das Löschen von Objekten vollständig automatisiert. Das Löschen von Objekten übernimmt die Java-Maschine selbst. Dieser Vorgang wird als Garbage Collection bezeichnet, und der Mechanismus, der den Müll sammelt, wird Garbage Collector ( GC ) genannt .

Woher weiß die Java-Maschine, wann sie ein Objekt löschen muss?

Der Garbage Collector unterteilt alle Objekte in „erreichbar“ und „nicht erreichbar“. Wenn mindestens eine Referenz auf ein Objekt vorhanden ist, gilt es als erreichbar. Wenn keine Variable vorhanden ist, die auf ein Objekt verweist, gilt das Objekt als nicht erreichbar und wird als Müll deklariert, was bedeutet, dass es gelöscht werden kann.

In Java können Sie keine Referenz auf ein vorhandenes Objekt erstellen – Sie können nur Referenzen zuweisen, die Sie bereits haben. Wenn wir alle Verweise auf ein Objekt löschen, ist es für immer verloren.

Zirkelverweise

Diese Logik klingt großartig, bis wir auf ein einfaches Gegenbeispiel stoßen: Angenommen, wir haben zwei Objekte, die aufeinander verweisen (Referenzen aufeinander speichern). Keine anderen Objekte speichern Verweise auf diese Objekte.

Auf diese Objekte kann über den Code nicht zugegriffen werden, sie werden jedoch weiterhin referenziert.

Aus diesem Grund unterteilt der Garbage Collector Objekte in erreichbare und nicht erreichbare Objekte und nicht in „referenzierte“ und „nicht referenzierte“ Objekte.

Erreichbare Objekte

Zunächst werden Objekte, die zu 100 % aktiv sind, zur erreichbaren Liste hinzugefügt. Zum Beispiel der aktuelle Thread ( Thread.current()) oder der Konsolen-InputStream ( System.in).

Anschließend wird die Liste der erreichbaren Objekte um Objekte erweitert, auf die von der anfänglichen Menge erreichbarer Objekte verwiesen wird. Dann wird es erneut erweitert, um Objekte einzuschließen, auf die von dieser erweiterten Menge verwiesen wird, und so weiter.

Das heißt, wenn es einige Objekte gibt, die nur aufeinander verweisen, es aber keine Möglichkeit gibt, sie von erreichbaren Objekten aus zu erreichen, werden diese Objekte als Müll betrachtet und gelöscht.


3. Müllabfuhr

Speicherfragmentierung

Ein weiterer wichtiger Punkt im Zusammenhang mit dem Löschen von Objekten ist die Speicherfragmentierung. Wenn Sie ständig Objekte erstellen und löschen, wird der Speicher bald stark fragmentiert: Bereiche mit belegtem Speicher wechseln sich mit Bereichen mit unbelegtem Speicher ab.

Infolgedessen können wir leicht in eine Situation geraten, in der wir kein großes Objekt erstellen können (z. B. ein Array mit einer Million Elementen), weil nicht viel freier Speicher vorhanden ist. Mit anderen Worten: Möglicherweise gibt es freien Speicher, sogar viel davon, aber möglicherweise keinen großen zusammenhängenden Block freien Speichers

Speicheroptimierung (Defragmentierung)

Die Java-Maschine löst dieses Problem auf spezifische Weise. Es sieht ungefähr so ​​aus:

Das Gedächtnis ist in zwei Teile geteilt. Alle Objekte werden in nur einer Speicherhälfte erstellt (und gelöscht). Wenn es an der Zeit ist, die Lücken im Speicher zu schließen, werden alle Objekte in der ersten Hälfte in die zweite Hälfte kopiert. Sie werden aber direkt nebeneinander kopiert, so dass keine Löcher entstehen.

Der Prozess sieht ungefähr so ​​aus:

Schritt 1: Nach dem Erstellen von Objekten

Garbage Collection in Java

Schritt 2: Auftreten von „Löchern“

Garbage Collection in Java 2

Schritt 3: Beseitigung von „Löchern“

Garbage Collection in Java 3

Und deshalb müssen Sie keine Objekte löschen. Die Java-Maschine kopiert einfach alle erreichbaren Objekte an einen neuen Speicherort und gibt den gesamten Speicherbereich frei, in dem die Objekte zuvor gespeichert waren.