Bidang statis pada referensi null di Java


119

staticanggota ( staticbidang atau staticmetode) di Java dikaitkan dengan kelasnya masing-masing daripada objek kelas ini. Kode berikut mencoba mengakses bidang statis pada nullreferensi.

public class Main
{
    private static final int value = 10;

    public Main getNull()
    {
        return null;
    }

    public static void main(String[] args)
    {
        Main main=new Main();
        System.out.println("value = "+main.getNull().value);
    }
}

Meskipun main.getNull()kembali null, itu berfungsi dan ditampilkan value = 10. Bagaimana kode ini bekerja?



4
Untuk bersenang-senang, cobalah Main main = null; main.getNull().value.
Marko Topolnik

1
Ini mengingatkan saya di new Thread[]{}[-1].sleep(10);mana sleep () adalah metode statis. Ini dulu berhasil pada beberapa versi Java yang lebih lama.
hertzsprung

Jawaban:


93

Perilaku itu ditentukan dalam Spesifikasi Bahasa Java :

referensi null dapat digunakan untuk mengakses variabel kelas (statis) tanpa menyebabkan pengecualian.

Dalam rincian lebih lanjut, sebuah evaluasi lapangan statis , seperti Primary.staticFieldkarya-karya sebagai berikut (penekanan) - dalam kasus Anda, Primary = main.getNull():

  • Ekspresi utama dievaluasi, dan hasilnya dibuang . [...]
  • Jika bidang adalah bidang akhir yang tidak kosong, maka hasilnya adalah nilai variabel kelas yang ditentukan di kelas atau antarmuka yang merupakan jenis ekspresi Primer. [...]

5
Jika ada yang punya info tentang mengapa pilihan ini dibuat, itu akan menarik.

6
@JonofAllTrades Saya pikir ini jelas: masuk akal untuk tidak membuang pengecualian saat memanggil referensi null karena tidak masalah karena metode ini statis.
Malcolm

13
@JonofAllTrades: pertanyaan sebenarnya adalah mengapa pilihan untuk mengizinkan anggota statis dipanggil sebagai instance dibuat ... Bagi saya, itu tampaknya hanya menyebabkan kebingungan dan kode yang kurang dapat dibaca.
Falanwe

2
@Falanwe: Setuju, dan ini adalah konstruksi yang tidak saya butuhkan, meskipun saya kebanyakan bekerja di .NET di mana itu tidak diizinkan. Saya kira Anda mungkin ingin memanggil metode statis subclass yang sesuai ketika Anda diberi referensi ke kelas induk.

8
@Falanwe Ini diperbolehkan, tetapi memunculkan peringatan di Eclipse: "Bidang statis Main.value harus diakses dengan cara statis". Setidaknya bagi kita yang pilih-pilih tentang peringatan (seperti saya) akan menghindari kode seperti itu.
Artyom

19

Karena, seperti yang Anda katakan, bidang statis tidak terkait dengan sebuah instance.

Kemampuan untuk mengakses bidang statis dari referensi instance (seperti yang Anda lakukan) hanyalah gula sintaksis dan tidak memiliki arti tambahan.
Kode Anda dikompilasi ke

main.getNull(); 
Main.value

7
Saya akan menyebutnya gula sintaksis, lebih seperti debu gergaji sintaksis;)
Stephen Swensen

3

Kapan pun Anda mengakses variabel statis atau metode dengan objek pada waktu kompilasi, itu diubah menjadi nama Kelas. misalnya:

Main main = null;
System.out.println(main.value);

Ini akan mencetak nilai nilai variabel statis karena pada waktu kompilasi Ini akan diubah menjadi

System.out.println(Main.value);

Bukti:

unduh decompiler dan Dekompilasi file .class Anda ke file .java dan Anda dapat melihat semua metode statis atau variabel yang dirujuk nama objek secara otomatis diganti dengan nama kelas.


3
  1. Mengakses staticanggota dengan nama kelas adalah legal, tetapi tidak tertulis bahwa seseorang tidak dapat mengakses staticanggota menggunakan variabel referensi objek. Jadi ini berfungsi di sini.

  2. Sebuah nullvariabel referensi obyek diperbolehkan untuk mengakses staticvariabel kelas tanpa membuang pengecualian baik di kompilasi atau run time.


2

Variabel dan metode statis selalu menjadi milik kelas. Jadi ketika kita membuat objek apa pun hanya variabel non-statis dan metode pergi ke heap bersama dengan objek tetapi statis berada di area metode dengan kelas. Itulah mengapa ketika kita mencoba mengakses variabel statis atau metode itu diubah menjadi nama kelas variabel titik atau nama metode.

Silakan lihat tautan di bawah ini untuk detail lebih lanjut.

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.