Rumah > Java > javaTutorial > teks badan

Membolehkan anda memahami kata kunci statik dalam Java sekaligus

醉折花枝作酒筹
Lepaskan: 2021-08-04 17:49:46
ke hadapan
2152 orang telah melayarinya

Saya percaya bahawa ramai pelajar telah menemui soalan seperti ini. Mereka mungkin telah mencari maklumat itu dan kemudian terlupa jika mereka menemuinya lagi, mereka masih tidak dapat menjawabnya dengan betul. Seterusnya, melalui 4 langkah, saya akan membawa anda untuk membuka urutan pelaksanaan kod ini dan meringkaskan peraturan.

Soalan pembukaan untuk mengkaji susunan pelaksanaan kod:

public class Parent {
    static {
        System.out.println("Parent static initial block");
    }

    {
        System.out.println("Parent initial block");
    }

    public Parent() {
        System.out.println("Parent constructor block");

    }
}

public class Child extends Parent {
    static {
        System.out.println("Child static initial block");
    }

    {
        System.out.println("Child initial block");
    }
    
    private Hobby hobby = new Hobby();

    public Child() {
        System.out.println("Child constructor block");
    }
}

public class Hobby {
    static{
        System.out.println("Hobby static initial block");
    }

    public Hobby() {
        System.out.println("hobby constructor block");
    }
}
Salin selepas log masuk

Apabila Child() baharu dilaksanakan, apakah yang dikeluarkan oleh kod di atas?

Saya percaya ramai pelajar yang menghadapi masalah sebegini mungkin telah menyemak maklumat tersebut dan kemudiannya terlupa jika terjumpa lagi, mereka masih tidak dapat menjawabnya dengan betul. Seterusnya, wakil kelas akan membawa anda melalui 4 langkah untuk merungkai urutan pelaksanaan kod ini dan meringkaskan peraturan.

1. Apakah yang dioptimumkan oleh pengkompil?

Dua keping kod berikut membandingkan perubahan sebelum dan selepas penyusunan:

Child.java sebelum penyusunan

public class Child extends Parent {
    static {
        System.out.println("Child static initial block");
    }
    {
        System.out.println("Child initial block");
    }
    
    private Hobby hobby = new Hobby();
    
    public Child() {
        System.out.println("Child constructor block");
    }
}
Salin selepas log masuk

Child.class selepas kompilasi

public class Child extends Parent {
    private Hobby hobby;

    public Child() {
        System.out.println("Child initial block");
        this.hobby = new Hobby();
        System.out.println("Child constructor block");
    }

    static {
        System.out.println("Child static initial block");
    }
}
Salin selepas log masuk

Ia boleh dilihat daripada perbandingan bahawa pengkompil mengalihkan blok permulaan dan operasi penetapan medan contoh sebelum kod pembina, dan mengekalkan susunan kod yang berkaitan. Malah, jika terdapat berbilang pembina, kod permulaan akan disalin dan dipindahkan.

Berdasarkan ini, susunan keutamaan pertama boleh diperolehi:

  • Kod permulaan >
Proses pemuatan kelas boleh dibahagikan secara kasar kepada tiga peringkat: Pemuatan-> Pautan-> jenis pencetus permulaan kelas Kes ") pencetus:

Apabila membuat instantiat objek menggunakan kata kunci baharu

  • Baca atau tetapkan medan statik a taip (malar" )

  • Memanggil kaedah statik jenis

  • Apabila menggunakan refleksi untuk memanggil kelas

  • Apabila memulakan kelas, jika didapati bahawa kelas induk belum dimulakan, permulaan kelas induk akan dicetuskan dahulu

  • Apabila mesin maya dimulakan, kaedah kelas utama (termasuk main() akan dimulakan dahulu )

  • Apabila contoh MethodHandle pertama kali dipanggil, mulakan kelas di mana kaedah yang ditunjuk oleh MethodHandle berada

  • Jika dalam antara muka Kaedah lalai (kaedah antara muka diubah suai lalai) ditakrifkan dan kelas pelaksanaan antara muka dimulakan, maka antara muka mesti dimulakan sebelum

  • antara entri 2 dan 3 ialah

    Malah, fasa permulaan ialah proses melaksanakan kaedah pembina kelas<clinit> tindakan dan pembolehubah statik semua pembolehubah kelas diubah suai statik (blok{} statik), dan mengekalkan susunan kod ini muncul
Menurut item 5, JVM akan memastikan bahawa kelas induk. <clinit> Kaedah telah dilaksanakan

Untuk meringkaskan: mengakses pembolehubah kelas atau kaedah statik akan mencetuskan permulaan kelas, dan permulaan kelas adalah untuk melaksanakan <clinit>, iaitu. , untuk melaksanakan tindakan pengubahsuaian statik dan blok statik{}, dan JVM memastikan bahawa pemulaan kelas induk dilakukan terlebih dahulu, dan kemudian pemulaan subkelas dilakukan Ini membawa kepada susunan keutamaan kedua:

Kod statik kelas induk> Kod statik subkelas

3 Kod statik hanya dilaksanakan sekali

Kita semua tahu bahawa kod statik (kecuali kaedah statik) hanya dilaksanakan sekali.
  • Anda tidak pernah terfikir tentang bagaimana mekanisme ini dijamin?
Pemuatan kelas aplikasi → Pemuat Kelas Sambungan → Pemuat Kelas Mula

Kelas yang ditulis dalam pembangunan harian dimuatkan oleh pemuat kelas aplikasi secara lalai, dan ia akan diwakilkan kepada kelas induknya: pemuat kelas sambungan. Pemuat kelas sambungan seterusnya mewakilkan kepada kelas induknya: pemuat kelas permulaan. Hanya apabila pemuat kelas induk melaporkan bahawa ia tidak dapat menyelesaikan permintaan pemuatan, pemuat anak akan cuba menyelesaikan pemuatan dengan sendirinya Proses ini adalah perwakilan induk. Hubungan ibu bapa-anak antara ketiga-tiga tidak dicapai melalui pewarisan, tetapi melalui mod gabungan.

Pelaksanaan proses ini juga sangat mudah Kod pelaksanaan utama ditunjukkan di bawah:

Dengan ulasan, saya percaya ia mudah difahami oleh semua orang.

Ia boleh dilihat daripada kod yang diwakilkan oleh ibu bapa bahawa di bawah pemuat kelas yang sama, kelas hanya boleh dimuatkan sekali, yang mengehadkannya kepada hanya dimulakan sekali. Oleh itu, kod statik dalam kelas (kecuali kaedah statik) hanya dilaksanakan sekali apabila kelas dimulakan

4 <init>

Kod yang dijana secara automatik oleh pengkompil telah diperkenalkan sebelum Pembina Kelas: kaedah <clinit> ia akan mengumpulkan tindakan tugasan dan blok pernyataan statik (blok{} statik) semua pembolehubah kelas yang diubah suai statik dan mengekalkan susunan penampilan kod itu dilaksanakan apabila kelas dimulakan

Sehubungan itu, pengkompil juga akan menjana kaedah <init> yang akan mengumpul tindakan tugasan medan contoh, kod dalam blok pernyataan permulaan ({}) dan pembina (Pembina), dan mengekalkan susunan kemunculan kod , ia akan melaksanakan

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
    // 首先检查该类是否被加载过
    // 如果加载过,直接返回该类
    Class<?> c = findLoadedClass(name);
    if (c == null) {
        try {
            if (parent != null) {
                c = parent.loadClass(name, false);
            } else {
                c = findBootstrapClassOrNull(name);
            }
        } catch (ClassNotFoundException e) {
            // 如果父类抛出ClassNotFoundException
            // 说明父类无法完成加载请求
        }

        if (c == null) {
            // 如果父类无法加载,转由子类加载
            c = findClass(name);
        }
    }
    if (resolve) {
        resolveClass(c);
    }
    return c;
}
Salin selepas log masuk
selepas arahan baharu, apabila kita baharu kelas, jika JVM belum memuatkan kelas itu akan dimulakan dahulu dan kemudian dimulakan.

Pada ketika ini, peraturan keutamaan ketiga sedia untuk keluar:

  • Kod statik (blok{} statik, pernyataan tugasan medan statik) > Kod permulaan ({} blok, pernyataan tugasan medan contoh)

5 🎜> Gabungkan tiga peraturan sebelumnya dan ringkaskan dua berikut:

1 Kod statik (blok{} statik, pernyataan tugasan medan statik) > Kod pembina

2. Kod statik kelas induk > Kod statik subkelas

Menurut ringkasan sebelumnya, kod permulaan dan kod pembina dikumpul oleh pengkompil <init> kod statik dikumpulkan ke dalam <clinit>, jadi peraturan di atas digabungkan semula:

Kelas induk

> Kelas induk

> 🎜><clinit>Sesuai dengan soalan pada mulanya, mari kita praktikkannya: <clinit><init>Apabila melaksanakan Child() baharu, kata kunci baharu mencetuskan permulaan kelas Child dan JVM mendapati ia mempunyai induk kelas , kemudian mulakan kelas Induk dahulu, mula melaksanakan kaedah <clinit> kelas Induk, dan kemudian laksanakan kaedah <clinit> kelas Anak (ingat apa yang dikumpul dalam <clinit>?). <init>

Kemudian mula membuat instantiation objek kelas Anak Pada masa ini, kami bersedia untuk melaksanakan kaedah <init> Kami mendapati bahawa ia mempunyai kelas induk ; kaedah dahulu, dan kemudian laksanakan kelas anak <init> (ingat apa yang dikumpul dalam <init>?).

Saya percaya bahawa selepas membaca ini, anda sudah mempunyai jawapan kepada soalan pembukaan, anda juga boleh menulis urutan output terlebih dahulu, dan kemudian menulis kod untuk mengesahkannya sendiri.

Kesimpulan

Static sering digunakan dalam perkembangan harian Setiap kali saya menulis, selalu ada dua persoalan dalam fikiran saya Mengapa saya perlu menggunakan statik?

Seperti yang dapat dilihat daripada artikel ini, aplikasi statik melangkaui pembolehubah kelas dan semudah kaedah statik. Dalam corak singleton klasik, anda akan melihat pelbagai kegunaan statik Artikel seterusnya akan menulis tentang cara menulis corak singleton dengan cara yang mewah.

Atas ialah kandungan terperinci Membolehkan anda memahami kata kunci statik dalam Java sekaligus. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:segmentfault.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan