Pertanyaan Dalam urutan apa blok statis / instance initializer di Java dijalankan?


Katakanlah sebuah proyek berisi beberapa kelas, yang masing-masing memiliki blok penginisialisasi statis. Dalam urutan apa blok-blok itu dijalankan? Saya tahu bahwa di dalam kelas, blok tersebut dijalankan dalam urutan yang muncul dalam kode. Saya telah membaca bahwa itu sama di seluruh kelas, tetapi beberapa contoh kode yang saya tulis tidak setuju dengan itu. Saya menggunakan kode ini:

package pkg;

public class LoadTest {
    public static void main(String[] args) {
        System.out.println("START");
        new Child();
        System.out.println("END");
    }
}

class Parent extends Grandparent {
    // Instance init block
    {
        System.out.println("instance - parent");
    }

    // Constructor
    public Parent() {
        System.out.println("constructor - parent");
    }

    // Static init block
    static {
        System.out.println("static - parent");
    }
}

class Grandparent {
    // Static init block
    static {
        System.out.println("static - grandparent");
    }

    // Instance init block
    {
        System.out.println("instance - grandparent");
    }

    // Constructor
    public Grandparent() {
        System.out.println("constructor - grandparent");
    }
}

class Child extends Parent {
    // Constructor
    public Child() {
        System.out.println("constructor - child");
    }

    // Static init block
    static {
        System.out.println("static - child");
    }

    // Instance init block
    {
        System.out.println("instance - child");
    }
}

dan mendapat output ini:

MULAI
  statis - kakek
  statis - orang tua
  statis - anak
  contoh - kakek
  konstruktor - kakek
  contoh - orang tua
  konstruktor - orang tua
  contoh - anak
  konstruktor - anak
  AKHIR

Jawaban yang jelas dari itu adalah bahwa orang tua 'blok berjalan sebelum anak-anak mereka, tetapi itu bisa saja menjadi suatu kebetulan dan tidak membantu jika dua kelas tidak dalam hirarki yang sama.

EDIT:

Saya memodifikasi kode contoh saya dengan menambahkan ini ke LoadTest.java:

class IAmAClassThatIsNeverUsed {
    // Constructor
    public IAmAClassThatIsNeverUsed() {
        System.out.println("constructor - IAACTINU");
    }

    // Instance init block
    {
        System.out.println("instance - IAACTINU");
    }

    // Static init block
    static {
        System.out.println("static - IAACTINU");
    }
}

Seperti yang diimplikasikan oleh nama kelas, saya tidak pernah mereferensikan kelas baru di mana saja. Program baru menghasilkan output yang sama dengan yang lama.


83
2018-01-05 17:01


asal


Jawaban:


Penginisialisasi statis untuk kelas dijalankan ketika kelas pertama kali diakses, baik untuk membuat instance, atau untuk mengakses metode atau bidang statis.

Jadi, untuk beberapa kelas, ini sepenuhnya tergantung pada kode yang dijalankan untuk menyebabkan kelas-kelas tersebut dimuat.


56
2018-01-05 17:05



Lihat bagian 12.4 dan 12.5 dari JLS versi 8, mereka membahas detail tentang semua ini (12,4 untuk statis dan 12,5 untuk variabel misalnya).

Untuk inisialisasi statis (bagian 12.4):

Kelas atau antarmuka tipe T akan diinisialisasi segera sebelum munculnya salah satu dari yang berikut ini:

  • T adalah kelas dan turunan T dibuat.
  • T adalah kelas dan metode statis yang dinyatakan oleh T dipanggil.
  • Bidang statis yang dinyatakan oleh T ditetapkan.
  • Bidang statis yang dinyatakan oleh T digunakan dan bidang bukan merupakan variabel konstan (§4.12.4).
  • T adalah kelas tingkat atas (§7.6), dan pernyataan tegas (§14.10) secara leksikal bersarang dalam T (§8.1.3) dijalankan.

(dan beberapa klausa musang-kata)


88
2018-01-05 17:07



Jawaban Keith dan Chris sangat bagus, saya hanya menambahkan beberapa detail untuk pertanyaan spesifik saya.

Blok init statis berjalan dalam urutan di mana kelas mereka diinisialisasi.  Jadi, pesanan apa itu? Per JLS 12.4.1:

Kelas atau antarmuka tipe T akan diinisialisasi segera sebelum munculnya salah satu dari yang berikut ini:

  • T adalah kelas dan turunan T dibuat.
  • T adalah kelas dan metode statis yang dinyatakan oleh T dipanggil.
  • Bidang statis yang dinyatakan oleh T ditetapkan.
  • Bidang statis yang dinyatakan oleh T digunakan dan bidang bukan merupakan variabel konstan (§4.12.4).
  • T adalah kelas top-level, dan pernyataan tegas (§14.10) secara leksikal bersarang dalam T dieksekusi.

Doakan metode reflektif tertentu di kelas Kelas dan dalam paket java.lang.reflect juga menyebabkan inisialisasi kelas atau antarmuka. Kelas atau antarmuka tidak akan diinisialisasi dalam keadaan lain.

Untuk mengilustrasikan, inilah panduan tentang apa yang terjadi dalam contoh:

  1. Masukkan utama
  2. Cetak "MULAI"
  3. Berusaha membuat instance Anak pertama, yang memerlukan inisialisasi Anak
  4. Mencoba menginisialisasi Child menyebabkan inisialisasi Induk
  5. Mencoba menginisialisasi Induk menyebabkan inisialisasi Kakek
  6. Pada awal inisialisasi Kakek, blok inisialisasi statis Kakek dijalankan
  7. Secara teknis, Objek mendapatkan suara terakhir dalam rantai inisialisasi berdasarkan menjadi orang tua Kakek, tetapi tidak memiliki kontribusi apa pun
  8. Setelah blok inisialisasi statis kakek nenek berakhir, program akan kembali ke blok inisialisasi statis Parent
  9. Setelah blok inisialisasi statis Parent berakhir, program akan kembali ke blok inisialisasi statis Child
  10. Pada titik ini, Child diinisialisasi, sehingga konstruktornya dapat dilanjutkan
  11. Karena IAmAClassThatIsNeverUsed tidak pernah direferensikan, tidak ada kode yang pernah berjalan, termasuk blok penginisialisasi statis
  12. Sisa dari walkthrough ini tidak berkaitan dengan initializers statis dan hanya disertakan untuk kelengkapan
  13. Konstruktor Child implisit memanggil super () (yaitu, konstruktor Parent)
  14. Konstruktor Parent implisit memanggil super () (yaitu, konstruk kakek nenek)
  15. Konstruktor kakek melakukan hal yang sama, yang tidak memiliki efek (sekali lagi, Object tidak memiliki kontribusi)
  16. Segera setelah panggilan konstruktor kakek nenek untuk super () datang blok inisiator contoh grandparent
  17. Sisa konstruktor konstruktor nenek moyang berjalan dan konstruktor berakhir
  18. Program ini kembali ke konstruktor Parent, segera setelah panggilannya ke super () (yaitu, konstruktor kakek nenek) menyelesaikan
  19. Seperti di atas, penginisialisasi contoh Orang Tua melakukan hal dan konstruktornya selesai
  20. Demikian pula, program kembali ke dan melengkapi konstruktor Child
  21. Pada titik ini, objek telah dipakai
  22. Cetak "END"
  23. Hentikan secara normal

29
2018-01-05 18:38



Inisialisasi kelas terdiri dari mengeksekusi initializers statis dan penginisialisasi untuk bidang statis (variabel kelas) yang dideklarasikan di kelas.

Inisialisasi antarmuka terdiri dari mengeksekusi initializers untuk bidang (konstanta) yang dideklarasikan di antarmuka.

Sebelum kelas diinisialisasi, superclass langsung harus diinisialisasi, tetapi antarmuka yang diterapkan oleh kelas tidak diinisialisasi. Demikian pula, superinterfaces dari sebuah antarmuka tidak diinisialisasi sebelum antarmuka diinisialisasi.


1
2018-05-01 12:43



Anda dapat memiliki beberapa inisialisasi statis dan instance di kelas yang sama

  • Inisialisasi statis disebut dalam tatanan tekstual yang mereka nyatakan (dari 12.4.2)
  • Instance initializers disebut dalam tatanan tekstual yang mereka nyatakan (dari 12,5)

Setiap dieksekusi seolah-olah itu adalah satu blok.


0
2018-02-25 18:21



http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

silakan periksa dokumentasi java.

kemudian dengan jelas disebutkan tidak peduli bagaimana mungkin blok statis di sana mereka akan dieksekusi sebagai satu blok dalam urutan yang muncul

Begitu,

Pemahaman saya di sini adalah java adalah mencari kode Anda sebagai

static{
i=1;
i=2;
}

int static i;

itulah mengapa Anda mendapatkan hasil 2

semoga ini bermanfaat


0
2018-05-13 10:37



Ada satu kasus di mana blok statis tidak akan dipanggil.

class Super {
    public static int i=10;
}
class Sub extends Super {
    static {
        system.out.println("Static block called");
    }
}
class Test {
    public static void main (String [] args) {
        system.out.println(Sub.i);
    } 
}

Output kode di atas 10


0
2017-11-17 09:50