Kapan variabel statis diinisialisasi?

88

Saya bertanya-tanya kapan variabel statis diinisialisasi ke nilai defaultnya. Apakah benar bahwa ketika kelas dimuat, vars statis dibuat (dialokasikan), kemudian penginisialisasi dan inisialisasi statis dalam deklarasi dijalankan? Pada titik manakah nilai default diberikan? Ini mengarah pada masalah referensi ke depan.

Juga tolong jika Anda dapat menjelaskan ini dengan mengacu pada pertanyaan yang diajukan di Mengapa bidang statis tidak diinisialisasi tepat waktu? dan terutama jawaban yang diberikan oleh Kevin Brock di situs yang sama. Saya tidak dapat memahami poin ke-3.

Ankit
sumber
2
Silakan edit pertanyaan Anda untuk menyertakan kutipan yang Anda maksud.
Oliver Charlesworth
1
Sudahkah Anda membaca spesifikasi bahasa Java? Ini adalah dokumen yang cukup mudah dibaca, sengaja begitu. Jika Anda telah membacanya, Anda mungkin mengerti apa yang sedang terjadi. Jika tidak, Anda dapat mengajukan pertanyaan yang lebih spesifik minimal ...
Maarten Bodewes
Saya pikir Tanya Jawab ini adalah duplikat dari stackoverflow.com/questions/3499214 .
Stephen C

Jawaban:

72

Dari Lihat Metode Variabel Statis Jawa :

  • Ini adalah variabel yang dimiliki kelas dan bukan objek (instance)
  • Variabel statis diinisialisasi hanya sekali, pada awal eksekusi. Variabel ini akan diinisialisasi terlebih dahulu, sebelum inisialisasi variabel instan apa pun
  • Salinan tunggal untuk dibagikan oleh semua instance kelas
  • Variabel statis dapat diakses secara langsung dengan nama kelas dan tidak memerlukan objek apa pun.

Variabel instans dan kelas (statis) secara otomatis diinisialisasi ke nilai default standar jika Anda gagal menginisialisasi mereka dengan sengaja. Meskipun variabel lokal tidak diinisialisasi secara otomatis, Anda tidak dapat mengkompilasi program yang gagal menginisialisasi variabel lokal atau menetapkan nilai ke variabel lokal tersebut sebelum digunakan.

Apa yang sebenarnya dilakukan oleh compiler adalah secara internal menghasilkan rutinitas inisialisasi kelas tunggal yang menggabungkan semua penginisialisasi variabel statis dan semua blok penginisialisasi statis dari kode, dalam urutan yang muncul di deklarasi kelas. Prosedur inisialisasi tunggal ini dijalankan secara otomatis, hanya satu kali, saat kelas pertama kali dimuat.

Dalam kasus kelas dalam , mereka tidak boleh memiliki bidang statis

Sebuah kelas batin adalah sebuah kelas bersarang yang tidak secara eksplisit maupun implisit dinyatakan static.

...

Kelas-kelas dalam tidak boleh mendeklarasikan penginisialisasi statis (§8.7) atau antarmuka anggota ...

Kelas-kelas dalam tidak boleh mendeklarasikan anggota statis, kecuali mereka adalah variabel konstan ...

Lihat JLS 8.1.3 Kelas Dalam dan Mesin Virtual Penutup

finalbidang di Jawa dapat diinisialisasi secara terpisah dari tempat deklarasinya, namun ini tidak dapat diterapkan ke static finalbidang. Lihat contoh di bawah ini.

final class Demo
{
    private final int x;
    private static final int z;  //must be initialized here.

    static 
    {
        z = 10;  //It can be initialized here.
    }

    public Demo(int x)
    {
        this.x=x;  //This is possible.
        //z=15; compiler-error - can not assign a value to a final variable z
    }
}

Hal ini karena hanya ada satu salinan dari staticvariabel yang terkait dengan jenis, bukan dari satu terkait dengan setiap contoh dari jenis seperti dengan variabel contoh dan jika kita mencoba untuk menginisialisasi zjenis static finaldalam constructor, itu akan mencoba untuk reinitialize static finalbidang jenis zkarena konstruktor dijalankan pada setiap instance kelas yang tidak boleh terjadi pada finalbidang statis .

Singa
sumber
5
In case of static inner classes, they can not have static fieldsSepertinya salah ketik. Kelas dalam tidak statis.
Daniel Lubarov
Namun, Anda harus menggunakan Alih-alih Meskipun
Suraj Jain
Saat Anda menjalankan JVM dan memuat kelas untuk pertama kalinya (ini dilakukan oleh classloader saat kelas pertama kali direferensikan dengan cara apa pun), semua blok atau bidang statis 'dimuat' ke JVM dan dapat diakses.
nhoxbypass
1
Sayangnya jawaban ini mengandung beberapa ketidakakuratan faktual tentang kapan statika diinisialisasi. Silakan lihat stackoverflow.com/a/3499322/139985 .
Stephen C
15

Lihat:

Yang terakhir secara khusus menyediakan langkah - langkah inisialisasi mendetail yang menjelaskan kapan variabel statis diinisialisasi, dan dalam urutan apa (dengan peringatan bahwa finalvariabel kelas dan bidang antarmuka yang merupakan konstanta waktu kompilasi diinisialisasi terlebih dahulu.)

Saya tidak yakin apa pertanyaan spesifik Anda tentang poin 3 (anggap saja maksud Anda yang bersarang?). Urutan rinci menyatakan ini akan menjadi permintaan inisialisasi rekursif sehingga akan melanjutkan inisialisasi.

Dave Newton
sumber
12

Bidang statis diinisialisasi saat kelas dimuat oleh pemuat kelas. Nilai default ditetapkan saat ini. Ini dilakukan secara berurutan daripada yang muncul di kode sumber.

Dave
sumber
10

Urutan inisialisasi adalah:

  1. Blok inisialisasi statis
  2. Blok inisialisasi instance
  3. Konstruktor

Detail proses dijelaskan dalam dokumen spesifikasi JVM .

Óscar López
sumber
6

variabel statis

  • Ini adalah variabel yang dimiliki kelas dan bukan objek (instance)
  • Variabel statis diinisialisasi hanya sekali, pada awal eksekusi (saat Classloader memuat kelas untuk pertama kalinya).
  • Variabel ini akan diinisialisasi terlebih dahulu, sebelum inisialisasi variabel instan apa pun
  • Salinan tunggal untuk dibagikan oleh semua instance kelas
  • Variabel statis dapat diakses secara langsung dengan nama kelas dan tidak memerlukan objek apa pun
aleroot
sumber
4

Dimulai dengan kode dari pertanyaan lain:

class MyClass {
  private static MyClass myClass = new MyClass();
  private static final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // will print null once
  }
}

Referensi ke kelas ini akan memulai inisialisasi. Pertama, kelas akan ditandai sebagai diinisialisasi. Kemudian bidang statis pertama akan diinisialisasi dengan instance baru MyClass (). Perhatikan bahwa myClass segera diberi referensi ke instance MyClass kosong . Ada ruang di sana, tetapi semua nilai adalah nol. Konstruktor sekarang dijalankan dan dicetak obj, yang nilainya null.

Sekarang kembali ke inisialisasi kelas: objdibuat referensi ke objek nyata baru, dan kita selesai.

Jika ini dipicu oleh pernyataan seperti: MyClass mc = new MyClass();ruang untuk instance MyClass baru dialokasikan lagi (dan referensi ditempatkan di mc). Konstruktor dieksekusi lagi dan mencetak lagi obj, yang sekarang bukan null.

Trik sebenarnya di sini adalah ketika Anda menggunakan new, seperti di WhatEverItIs weii = new WhatEverItIs( p1, p2 ); weiisegera diberikan referensi ke sedikit memori nulled. JVM kemudian akan melanjutkan untuk menginisialisasi nilai dan menjalankan konstruktor. Tetapi jika Anda entah bagaimana mereferensikan weii sebelum melakukannya - dengan mereferensikannya dari utas lain atau dengan merujuk dari inisialisasi kelas, misalnya - Anda melihat instance kelas yang diisi dengan nilai null.

RalphChapin
sumber
1
Kelas tidak ditandai sebagai diinisialisasi sampai inisialisasi selesai - melakukan hal lain tidak masuk akal. Menandai sebagai diinisialisasi hampir merupakan langkah terakhir yang diambil. Lihat JLS 12.4.2 .
Dave Newton
@DaveNewton: Setelah sesuatu mereferensikan kelas dan mulai menginisialisasinya, semua referensi selanjutnya akan memperlakukan kelas tersebut sebagai diinisialisasi. Mereka tidak akan mencoba untuk memulainya, dan mereka tidak akan menunggu untuk diinisialisasi. Oleh karena itu, bidang yang tampak bukan-null dari awal program sebenarnya bisa menjadi null untuk suatu waktu. Tidak memahami inilah yang menyebabkan semua kebingungan. Saya pikir itu paling sederhana untuk mengatakan kelas yang tidak diinisialisasi "ditandai" sebagai diinisialisasi pada referensi pertama, semua referensi lain memperlakukannya sebagai diinisialisasi, dan itulah mengapa ini terjadi.
RalphChapin
Koreksi untuk komentar sebelumnya: seperti yang dijelaskan Dave Newton JLS 12.4.2, kelas dikunci saat diinisialisasi. Utas lain akan menunggu kelas diinisialisasi. Namun, itu tidak memengaruhi kasus ini, yang semuanya terjadi dalam satu utas.
RalphChapin
4

Variabel statis dapat diinisialisasi dalam tiga cara berikut sebagai berikut, pilih salah satu yang Anda suka

  1. Anda dapat memulainya pada saat deklarasi
  2. atau bisa anda lakukan dengan membuat blok statis misal:

    static {
            // whatever code is needed for initialization goes here
        }
    
  3. Ada alternatif untuk blok statis - Anda dapat menulis metode statis pribadi

    class name {
        public static varType myVar = initializeVar();
    
        private static varType initializeVar() {
            // initialization code goes here
        }
    }
    
ajay verma
sumber