Ini kode saya:
class A {
static A obj = new A();
static int num1;
static int num2=0;
private A() {
num1++;
num2++;
}
public static A getInstance() {
return obj;
}
}
public class Main{
public static void main(String[] arg) {
A obj = A.getInstance();
System.out.println(obj.num1);
System.out.println(obj.num2);
}
}
Outputnya adalah 1 0
, tapi saya tidak bisa mengerti.
Adakah yang bisa menjelaskannya kepada saya?
Jawaban:
Di Jawa terjadi dua fase: 1. Identifikasi, 2. Eksekusi
Dalam tahap identifikasi semua variabel statis terdeteksi dan diinisialisasi dengan nilai default.
Jadi sekarang nilainya adalah:
A obj=null
num1=0
num2=0
Tahap kedua, eksekusi , dimulai dari atas ke bawah. Di Java, eksekusi dimulai dari anggota statis pertama.
Di sini variabel statis pertama Anda adalah
static A obj = new A();
, jadi pertama-tama ia akan membuat objek dari variabel itu dan memanggil konstruktor, maka nilai darinum1
dannum2
menjadi1
.Dan kemudian, lagi,
static int num2=0;
akan dieksekusi, yang membuatnum2 = 0;
.Sekarang, misalkan konstruktor Anda seperti ini:
Ini akan membuang
NullPointerException
karenaobj
masih belum mendapat referensiclass A
.sumber
static A obj = new A();
bawahstatic int num2=0;
dan Anda akan mendapatkan 1 dan 1.A obj = new A(); int num1; int num2 = 0;
Akan berubah menjadi ini:A obj; int num1; int num2; obj = new A(); num2 = 0;
. Java melakukan ini sehingganum1, num2
ditentukan pada saat Anda mencapainew A()
konstruktor.Apa yang
static
dimaksud pengubah ketika diterapkan ke deklarasi variabel adalah bahwa variabel tersebut adalah variabel kelas daripada variabel instan. Dengan kata lain ... hanya ada satunum1
variabel, dan hanya satunum2
variabel.(Selain: variabel statis seperti variabel global dalam beberapa bahasa lain, kecuali bahwa namanya tidak terlihat di mana-mana. Bahkan jika dideklarasikan sebagai
public static
, nama yang tidak memenuhi syarat hanya terlihat jika dideklarasikan di kelas saat ini atau superclass , atau jika diimpor menggunakan impor statis. Itulah perbedaannya. Global sejati terlihat tanpa kualifikasi di mana pun.)Jadi, saat Anda merujuk ke
obj.num1
danobj.num2
, Anda sebenarnya mengacu pada variabel statis yang sebutan sebenarnya adalahA.num1
danA.num2
. Demikian pula, ketika konstruktor menambahnum1
dannum2
, itu menambah variabel yang sama (masing-masing).Kerutan yang membingungkan dalam contoh Anda ada pada inisialisasi kelas. Kelas diinisialisasi dengan default pertama menginisialisasi semua variabel statis, dan kemudian mengeksekusi penginisialisasi statis yang dideklarasikan (dan blok penginisialisasi statis) sesuai urutan kemunculannya di kelas. Dalam kasus ini, Anda memiliki ini:
Ini terjadi seperti ini:
Statika memulai dengan nilai awal default mereka;
A.obj
adalahnull
danA.num1
/A.num2
adalah nol.Deklarasi pertama (
A.obj
) membuat turunan dariA()
, dan konstruktor untukA
penambahanA.num1
danA.num2
. Ketika deklarasi selesai,A.num1
danA.num2
keduanya1
, danA.obj
mengacu padaA
instance yang baru dibangun .Deklarasi kedua (
A.num1
) tidak memiliki penginisialisasi, jadiA.num1
tidak berubah.Deklarasi ketiga (
A.num2
) memiliki penginisialisasi yang menetapkan nolA.num2
.Jadi, di akhir inisialisasi kelas,
A.num1
is1
danA.num2
is0
... dan itulah yang ditunjukkan oleh pernyataan cetak Anda.Perilaku membingungkan ini sebenarnya karena Anda membuat instance sebelum inisialisasi statis selesai, dan bahwa konstruktor yang Anda gunakan bergantung dan memodifikasi statis yang belum diinisialisasi. Ini sesuatu yang harus Anda hindari dalam kode nyata.
sumber
1,0 benar.
Ketika kelas dimuat, semua data statis diinisialisasi di tempat mereka dideklarasikan. Secara default int adalah 0.
static int num1;
tidak melakukan apa-apastatic int num2=0;
ini menulis 0 sampai num2sumber
Ini karena urutan penginisialisasi statis. Ekspresi statis di kelas dievaluasi dalam urutan dari atas ke bawah.
Yang pertama dipanggil adalah konstruktor
A
, yang menetapkannum1
dannum2
keduanya menjadi 1:static A obj = new A();
Kemudian,
dipanggil dan set num2 = 0 lagi.
Itulah mengapa
num1
1 dannum2
0.Sebagai catatan tambahan, konstruktor tidak boleh memodifikasi variabel statis, itu adalah desain yang sangat buruk. Sebagai gantinya, coba pendekatan berbeda untuk mengimplementasikan Singleton di Java .
sumber
Bagian di JLS dapat ditemukan: §12.4.2 .
Jadi ketiga variabel statis tersebut akan diinisialisasi satu per satu dalam urutan tekstual.
Begitu
Jika saya mengubah urutan menjadi:
Hasilnya akan seperti itu
1,1
.Perhatikan bahwa
static int num1;
ini bukan penginisialisasi variabel karena ( §8.3.2 ):Dan variabel kelas ini diinisialisasi saat kelas dibuat. Ini terjadi pertama kali ( §4.12.5 ).
sumber
Mungkin akan membantu jika memikirkannya seperti ini.
Kelas adalah cetak biru untuk objek.
Objek dapat memiliki variabel saat dibuat instance-nya.
Kelas juga dapat memiliki variabel. Ini dinyatakan sebagai statis. Jadi mereka ditetapkan pada kelas daripada contoh objek.
Anda hanya dapat memiliki satu dari setiap kelas dalam sebuah aplikasi jadi ini seperti penyimpanan global khusus untuk kelas itu. Variabel statis ini tentu saja dapat diakses dan dimodifikasi dari mana saja di aplikasi Anda (dengan asumsi variabel tersebut bersifat publik).
Berikut ini dan contoh kelas "Anjing" yang menggunakan variabel statis untuk melacak jumlah instance yang telah dibuat.
Kelas "Anjing" adalah cloud sedangkan kotak Oranye adalah instance "Anjing".
Baca lebih lajut
Semoga ini membantu!
Jika Anda merasa seperti beberapa hal sepele, ide ini pertama kali diperkenalkan oleh Plato
sumber
Kata kunci statis digunakan di java terutama untuk manajemen memori. Kami dapat menerapkan kata kunci statis dengan variabel, metode, blok dan kelas bersarang. Kata kunci statis termasuk dalam kelas daripada instance kelas. Untuk penjelasan singkat tentang kata kunci statis:
http://www.javatpoint.com/static-keyword-in-java
sumber
Banyak dari jawaban di atas benar. Tetapi untuk menggambarkan apa yang terjadi, saya telah membuat beberapa modifikasi kecil di bawah ini.
Seperti yang disebutkan beberapa kali di atas, yang terjadi adalah instance kelas A dibuat sebelum kelas A dimuat sepenuhnya. Jadi apa yang dianggap sebagai 'perilaku' normal tidak diamati. Ini tidak terlalu berbeda dengan memanggil metode dari konstruktor yang dapat diganti. Dalam hal ini, variabel instan mungkin tidak dalam keadaan intuitif. Dalam contoh ini variabel kelas tidak dalam keadaan intuitif.
Outputnya adalah
sumber
java tidak menginisialisasi nilai dari setiap anggota data statis atau non statis sampai ia tidak dipanggil tetapi membuatnya.
Jadi disini ketika num1 dan num2 akan dipanggil main maka akan diinisialisasi dengan nilai
num1 = 0 + 1; dan
num2 = 0;
sumber