Java >> Java tutorial >  >> JVM

<init> og <clinit> metoder i JVM

1. Oversigt

JVM'en bruger to karakteristiske metoder til at initialisere objektforekomster og klasser.

I denne hurtige artikel skal vi se, hvordan compileren og runtime bruger   og   metoder til initialiseringsformål.

2. Forekomstinitialiseringsmetoder

Lad os starte med en ligetil objektallokering og -tildeling:

Object obj = new Object();

Hvis vi kompilerer dette uddrag og tager et kig på dets bytekode via javap -c , vil vi se noget som:

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

For at initialisere objektet, JVM kalder en speciel metode ved navn .  I JVM-jargon er denne metode en instansinitieringsmetode . En metode er en instansinitialisering, hvis og kun hvis:

  • Det er defineret i en klasse
  • Dets navn er < init>
  • Det returnerer ugyldigt

Hver klasse kan have nul eller flere instansinitialiseringsmetoder . Disse metoder svarer normalt til konstruktører i JVM-baserede programmeringssprog såsom Java eller Kotlin.

2.1. Konstruktører og instansinitialiseringsblokke

For bedre at forstå, hvordan Java-kompileren oversætter konstruktører til , lad os overveje et andet eksempel:

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

    // <init>
    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    // <init>
    public Person() {
    }
}

Dette er bytekoden for denne klasse:

public Person(java.lang.String, java.lang.String);
  Code:
     0: aload_0
     1: invokespecial #1       // Method java/lang/Object."<init>":()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

Selvom konstruktøren og initialiseringsblokkene er adskilte i Java, er de i samme tilfælde initialiseringsmetode på bytekodeniveau. Faktisk er denne   metode:

  • Initialiserer først fornavnet  og efternavn  felter (indeks 0 til 13)
  • Derefter udskriver den noget til konsollen som en del af instansinitialiseringsblokken (indeks 16 til 21)
  • Og endelig opdaterer den instansvariablerne med konstruktørargumenterne

Hvis vi opretter en Person som følger:

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

Så oversættes dette til følgende bytekode:

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

Denne gang ringer JVM til en anden   metode med en signatur, der svarer til Java-konstruktøren.

Det vigtigste her er, at konstruktørerne og andre instansinitialiserere svarer til   metode i JVM-verdenen.

3. Klasseinitialiseringsmetoder

I Java er statiske initialiseringsblokke nyttige, når vi skal initialisere noget på klasseniveau:

public class Person {

    private static final Logger LOGGER = LoggerFactory.getLogger(Person.class); // <clinit>

    // <clinit>
    static {
        System.out.println("Static Initializing...");
    }

    // omitted
}

Når vi kompilerer den foregående kode, oversætter compileren den statiske blok til en klasseinitialiseringsmetode på bytekodeniveau.

Enkelt sagt er en metode en klasseinitialisering, hvis og kun hvis:

  • Dets navn er 
  • Det returnerer ugyldigt

Derfor er den eneste måde at generere en  metode i Java er at bruge statiske felter og statiske blokinitialiserere.

JVM påberåber sig  første gang vi bruger den tilsvarende klasse. Derfor er   påkaldelsen sker under kørsel, og vi kan ikke se påkaldelsen på bytekodeniveau.

4. Konklusion

I denne hurtige artikel så vi forskellen mellem   og   metoder i JVM.   metode bruges til at initialisere objektforekomster. JVM'en kalder også   metode til at initialisere en klasse, når det er nødvendigt.

For bedre at forstå, hvordan initialisering fungerer i JVM, anbefales det stærkt at læse JVM-specifikationen.


Java tag