und Methoden in der JVM

1. Übersicht

Die JVM verwendet zwei unterschiedliche Methoden, um Objektinstanzen und -klassen zu initialisieren.

In diesem kurzen Artikel werden wir sehen, wie der Compiler und die Laufzeit das verwenden und Methoden für Initialisierungszwecke.

2. Instanzinitialisierungsmethoden

Beginnen wir mit einer einfachen Objektzuweisung und -zuweisung:

Object obj = new Object();

Wenn wir dieses Snippet kompilieren und seinen Bytecode über javap -c betrachten , sehen wir etwas wie:

0: new #2 // class java/lang/Object 3: dup 4: invokespecial #1 // Method java/lang/Object."":()V 7: astore_1

Um das Objekt zu initialisieren , ruft die JVM eine spezielle Methode mit dem Namen auf .Im JVM-Jargon ist diese Methode eine Instanzinitialisierungsmethode . Eine Methode ist genau dann eine Instanzinitialisierung, wenn:

  • Es ist in einer Klasse definiert
  • Sein Name ist < init>
  • Es kehrt ungültig zurück

Jede Klasse kann null oder mehr Instanzinitialisierungsmethoden haben . Diese Methoden entsprechen normalerweise Konstruktoren in JVM-basierten Programmiersprachen wie Java oder Kotlin.

2.1. Konstruktoren und Instanzinitialisierungsblöcke

Um besser zu verstehen, wie der Java-Compiler Konstruktoren übersetzt Betrachten wir ein anderes Beispiel:

public class Person { private String firstName = "Foo"; //  private String lastName = "Bar"; //  //  { System.out.println("Initializing..."); } //  public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } //  public Person() { } }

Dies ist der Bytecode für diese Klasse:

public Person(java.lang.String, java.lang.String); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: aload_0 5: ldc #7 // String Foo 7: putfield #9 // Field firstName:Ljava/lang/String; 10: aload_0 11: ldc #15 // String Bar 13: putfield #17 // Field lastName:Ljava/lang/String; 16: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream; 19: ldc #26 // String Initializing... 21: invokevirtual #28 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 24: aload_0 25: aload_1 26: putfield #9 // Field firstName:Ljava/lang/String; 29: aload_0 30: aload_2 31: putfield #17 // Field lastName:Ljava/lang/String; 34: return

Obwohl der Konstruktor- und der Initialisierungsblock in Java getrennt sind, befinden sie sich auf Bytecode-Ebene in derselben Instanzinitialisierungsmethode. In der Tat, diesMethode:

  • Initialisiert zunächst die Felder firstName und lastName (Index 0 bis 13).
  • Anschließend wird als Teil des Instanzinitialisierungsblocks (Index 16 bis 21) etwas auf der Konsole gedruckt.
  • Schließlich werden die Instanzvariablen mit den Konstruktorargumenten aktualisiert

Wenn wir eine Person wie folgt erstellen :

Person person = new Person("Brian", "Goetz");

Dies führt dann zu folgendem Bytecode:

0: new #7 // class Person 3: dup 4: ldc #9 // String Brian 6: ldc #11 // String Goetz 8: invokespecial #13 // Method Person."":(Ljava/lang/String;Ljava/lang/String;)V 11: astore_1

Diesmal ruft JVM eine andere an Methode mit einer dem Java-Konstruktor entsprechenden Signatur.

Der Schlüssel zum Erfolg ist, dass die Konstruktoren und andere Instanzinitialisierer dem entsprechen Methode in der JVM-Welt.

3. Methoden zur Klasseninitialisierung

In Java sind statische Initialisierungsblöcke nützlich, wenn wir etwas auf Klassenebene initialisieren möchten:

public class Person { private static final Logger LOGGER = LoggerFactory.getLogger(Person.class); //  //  static { System.out.println("Static Initializing..."); } // omitted }

Wenn wir den vorhergehenden Code kompilieren, übersetzt der Compiler den statischen Block in eine Klasseninitialisierungsmethode auf Bytecode-Ebene.

Einfach ausgedrückt ist eine Methode genau dann eine Klasseninitialisierung, wenn:

  • Sein Name ist
  • Es kehrt ungültig zurück

Daher ist der einzige Weg, um eine zu generieren In Java werden statische Felder und statische Blockinitialisierer verwendet.

JVM ruft die auf Beim ersten Mal verwenden wir die entsprechende Klasse. deshalb, dieDer Aufruf erfolgt zur Laufzeit, und der Aufruf wird auf Bytecode-Ebene nicht angezeigt.

4. Fazit

In diesem kurzen Artikel haben wir den Unterschied zwischen gesehen und Methoden in der JVM. DasMethode wird verwendet, um Objektinstanzen zu initialisieren. Außerdem ruft die JVM die aufMethode zum Initialisieren einer Klasse bei Bedarf.

Um besser zu verstehen, wie die Initialisierung in der JVM funktioniert, wird dringend empfohlen, die JVM-Spezifikation zu lesen.