Wie Sie zu wissen scheinen und die obige Antwort auch deutlich macht, dass Begleitobjekte in Klassen übersetzt werden und die Klasse, die sie deklariert, einen statischen Verweis auf das Objekt der Begleitklasse enthält, wie folgt:
public static final MyClass.Companion Companion = new MyClass.Companion(null);
Nun die Frage
Bleiben Begleitobjekte für den Lebenszyklus der App im Speicher?
Da die deklarierende Klasse einen staticVerweis auf die Companion-Klasse enthält, reduziert sich die Frage auf die Lebensdauer der staticFelder in jvm classund die Antwort liegt in der JVM-Spezifikation , aber die Spezifikation ist in der Erklärung etwas trocken, sodass ich einige Ausschnitte aus dem Buch Inside hinzufüge die Java Virtual Machine .
Nehmen wir an, wir haben wie in Ihrem Beispiel ein classObjekt mit nur einem Begleiter.
Die erste Frage ist, wann ein Objekt der Companion-Klasse erstellt wird. oder wenn staticFelder initialisiert werden?
relevanter Text aus dem Buch . (Für den Kontext spricht das Buch über das Laden von Klassen)
Initialisierung
Der letzte Schritt, der erforderlich ist, um eine Klasse oder Schnittstelle für ihre erste aktive Verwendung vorzubereiten, ist die Initialisierung, bei der Klassenvariablen auf ihre richtigen Anfangswerte gesetzt werden. Wie hier verwendet, ist ein "richtiger" Anfangswert der gewünschte Startwert des Programmierers für eine Klassenvariable. Ein korrekter Anfangswert steht im Gegensatz zu dem Standardanfangswert, der Klassenvariablen während der Vorbereitung zugewiesen wird. Wie oben beschrieben, weist die virtuelle Maschine Standardwerte zu, die nur auf dem Typ jeder Variablen basieren. Die richtigen Anfangswerte basieren dagegen auf einem Masterplan, der nur dem Programmierer bekannt ist. In Java-Code wird ein geeigneter Anfangswert über einen Klassenvariablen-Initialisierer oder einen statischen Initialisierer angegeben.
Wir wissen also, dass nach dem MyClassLaden und Initialisieren das Objekt der Companion-Klasse erstellt wird.
aber was würde dazu führen, dass JVM geladen wird MyClass?
Die Java Virtual Machine-Spezifikation bietet Implementierungen Flexibilität beim Timing des Ladens und der Verknüpfung von Klassen und Schnittstellen, definiert jedoch das Timing der Initialisierung streng. Alle Implementierungen müssen jede Klasse und Schnittstelle bei ihrer ersten aktiven Verwendung initialisieren. Eine aktive Nutzung einer Klasse ist:
Der Aufruf eines Konstruktors für eine neue Instanz der Klasse
Die Erstellung eines Arrays, dessen Elementtyp die Klasse ist
Der Aufruf einer von der Klasse deklarierten Methode (nicht von einer Oberklasse geerbt)
4 Die Verwendung oder Zuweisung eines von der Klasse deklarierten Felds (nicht von einer Oberklasse oder Superschnittstelle geerbt), mit Ausnahme von Feldern, die sowohl statisch als auch endgültig sind und durch einen konstanten Ausdruck zur Kompilierungszeit initialisiert werden
Also ab dem 4. Punkt, wenn Sie MyClass.foo()von Kotlin oder MyClass.Companion.foo()an diesem Punkt tun, MyClasswird geladen und bereit. (Wahrscheinlich viel zu früh)
Bitte beachten Sie, dass zu diesem Zeitpunkt kein Objekt MyClassexistiert, dh wir haben keinen Ausdruck verwendet MyClass().
Bedeutet dies, dass staticFelder so lange im Speicher bleiben, wie die Anwendung ausgeführt wird?
Sie können Müll gesammelt werden, wenn der deklarierende Typ entladen wird. In unserem Fall, wenn JVM oder ART (auf Android) entladen werden, MyClassbesteht die Möglichkeit, dass das Begleitobjekt Müll gesammelt wird.
JVM Spec hat Folgendes zum Entladen von Klassen zu sagen
Eine Implementierung der Programmiersprache Java kann Klassen entladen.
Eine Klasse oder Schnittstelle kann genau dann entladen werden, wenn ihr definierender Klassenlader vom Garbage Collector zurückgefordert werden kann, wie in § 12.6 beschrieben.
Vom Bootstrap Loader geladene Klassen und Schnittstellen dürfen nicht entladen werden.
In der praktischen Klasse kommt das Entladen fast (ich sagte fast) nie vor, also bleiben Begleitobjekte für den Lebenszyklus der App im Speicher .