Apakah mungkin untuk membuat kelas dalam anonim di Java menjadi statis?

123

Di Java, kelas bertingkat bisa berupa salah satu staticatau tidak. Jika ya static, mereka tidak berisi referensi ke pointer dari instance yang memuatnya (mereka juga tidak lagi disebut kelas dalam, mereka disebut kelas bersarang).

Lupa membuat kelas bersarang staticjika tidak membutuhkan referensi tersebut dapat menyebabkan masalah pada pengumpulan sampah atau escape analysis.

Apakah mungkin untuk membuat kelas dalam anonim staticjuga? Atau apakah kompilator mengetahui hal ini secara otomatis (yang bisa, karena tidak dapat ada subkelas)?

Misalnya, jika saya membuat pembanding anonim, saya hampir tidak pernah membutuhkan referensi ke luar:

  Collections.sort(list, new Comparator<String>(){
       int compare(String a, String b){
          return a.toUpperCase().compareTo(b.toUpperCase());
       }
  }
Thilo
sumber
Apa masalah dengan "pengumpulan sampah atau analisis pelarian" saat lupa untuk membuat kelas dalam menjadi statis? Saya pikir ini hanya tentang kinerja ...
Tim Büthe
17
Instance kelas dalam Anda membuat referensi ke instans luarnya tetap hidup, bahkan jika Anda tidak membutuhkannya. Ini bisa mencegah barang-barang dikumpulkan dari sampah. Bayangkan sebuah objek pabrik (sumber daya-berat) yang membuat contoh sesuatu yang ringan. Setelah pabrik menyelesaikan tugasnya (mis. Selama startup aplikasi), ini dapat dibuang, tetapi itu hanya berfungsi jika hal-hal yang telah dibuatnya tidak ditautkan kembali.
Thilo
Saya tahu, ini hanya contoh, tetapi karena ini adalah contoh berulang, harus disebutkan bahwa Collections.sort(list, String.CASE_INSENSITIVE_ORDER)berfungsi sejak Java 2, baca, karena API Koleksi ada…
Holger

Jawaban:

138

Tidak, Anda tidak bisa, dan tidak, kompilator tidak bisa memahaminya. Inilah sebabnya mengapa FindBugs selalu menyarankan untuk mengubah kelas dalam anonim menjadi statickelas bertingkat bernama jika mereka tidak menggunakan thisreferensi implisitnya .

Edit: Tom Hawtin - tackline mengatakan bahwa jika kelas anonim dibuat dalam konteks statis (misalnya dalam mainmetode), kelas anonim sebenarnya static. Tapi JLS tidak setuju :

Kelas anonim tidak pernah abstract(§8.1.1.1). Kelas anonim selalu merupakan kelas dalam (§8.1.3); itu tidak pernah static(§8.1.1, §8.5.1). Kelas anonim selalu secara implisit final(§8.1.1.2).

Glosarium Java Roedy Green mengatakan bahwa fakta bahwa kelas anonim diperbolehkan dalam konteks statis bergantung pada implementasi:

Jika Anda ingin membingungkan mereka yang memelihara kode Anda, wags telah ditemukan javac.exeakan mengizinkan kelas anonim di dalam statickode dan staticmetode init , meskipun spesifikasi bahasa mengatakan bahwa kelas anonim tidak pernah static. Kelas anonim ini, tentu saja, tidak memiliki akses ke bidang instance objek. Saya tidak merekomendasikan melakukan ini. The fitur dapat ditarik sewaktu-waktu.

Edit 2: JLS sebenarnya mencakup konteks statis secara lebih eksplisit di §15.9.2 :

Biarkan C menjadi kelas yang dipakai, dan biarkan saya menjadi contoh yang dibuat. Jika C adalah kelas dalam maka saya mungkin memiliki instans yang segera melampirkan. Instance terlampir dari i (§8.1.3) ditentukan sebagai berikut.

  • Jika C adalah kelas anonim, maka:
    • Jika ekspresi pembuatan instance kelas terjadi dalam konteks statis (§8.1.3), maka saya tidak memiliki instance yang langsung melingkupi.
    • Jika tidak, instance i yang langsung melampirkan adalah this.

Jadi kelas anonim dalam konteks statis secara kasar setara dengan statickelas bertingkat yang tidak menyimpan referensi ke kelas yang melingkupi, meskipun secara teknis bukan statickelas.

Michael Myers
sumber
19
1 untuk FindBugs - setiap pengembang Java harus memiliki ini di build mereka.
Andrew Duffy
13
Itu sangat disayangkan, karena itu berarti Anda mungkin ingin menghindari sintaks yang hampir ringkas ini karena alasan kinerja.
Thilo
2
JLS 3rd Ed menangani kasus kelas dalam dalam konteks statis. Mereka tidak statis dalam arti JLS, tetapi statis dalam arti yang diberikan dalam pertanyaan.
Tom Hawtin - tackline
6
Berikut adalah contoh bagaimana implementasinya bergantung: kode ini dicetak truemenggunakan javac (sun-jdk-1.7.0_10) dan falsemenggunakan compiler Eclipse.
Paul Bellora
1
@MichaelMyers Saya telah mencoba untuk mensimulasikan FindBugs yang memperingatkan saya untuk melakukan Anonymous Inner tanpa menggunakan referensi 'ini', dan tidak ada yang terjadi. Dapatkah Anda menunjukkan bagaimana FindBugs memperingatkan Anda seperti yang Anda katakan di awal jawaban Anda? Cukup tempelkan beberapa tautan atau apa pun.
Thufir Hawat
15

Agak. Kelas dalam anonim yang dibuat dengan metode statis jelas akan menjadi statis secara efektif karena tidak ada sumber untuk bagian luar ini.

Ada beberapa perbedaan teknis antara kelas dalam dalam konteks statis dan kelas bertingkat statis. Jika Anda tertarik, baca JLS 3rd Ed.

Tom Hawtin - taktik
sumber
Sebenarnya, saya mengambilnya kembali; JLS tidak setuju. java.sun.com/docs/books/jls/third%5Fedition/html/… : "Kelas anonim selalu merupakan kelas dalam; tidak pernah statis."
Michael Myers
1
statis dalam arti yang berbeda dengan yang ada dalam pertanyaan.
Tom Hawtin - tackline
1
Saya telah menambahkan sedikit klarifikasi.
Tom Hawtin - tackline
15

Saya pikir ada sedikit kebingungan dalam nomenklatur di sini, yang memang terlalu konyol dan membingungkan.

Apa pun sebutan Anda, pola ini (dan beberapa variasi dengan visibilitas berbeda) semuanya mungkin, normal, legal Java:

public class MyClass {
  class MyClassInside {
  }
}

public class MyClass {
  public static class MyClassInside {
  }
}

public class MyClass {
  public void method() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

public class MyClass {
  public static void myStaticMethod() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

Mereka dipenuhi dalam spesifikasi bahasa (jika Anda benar-benar terganggu, lihat bagian 15.9.5.1 untuk yang ada di dalam metode statis).

Tapi kutipan ini salah :

javac.exe akan mengizinkan kelas anonim di dalam kode init statis dan metode statis, meskipun spesifikasi bahasa mengatakan bahwa kelas anonim tidak pernah statis

Saya pikir penulis yang dikutip membingungkan kata kunci statis dengan konteks statis . (Memang, JLS juga agak membingungkan dalam hal ini.)

Sejujurnya, semua pola di atas baik-baik saja (apa pun yang Anda sebut "bersarang", "dalam", "anonim" apa pun ...). Sungguh, tidak ada yang akan tiba-tiba menghapus fungsi ini pada rilis Java berikutnya. Secara jujur!

Neil Coffey
sumber
2
"(Harus diakui, JLS juga agak membingungkan dalam hal ini.)" Anda benar. Kedengarannya aneh untuk mengatakan bahwa itu tergantung pada implementasinya, tetapi saya tidak ingat pernah melihat kesalahan yang jelas dalam Daftar Istilah Java sebelumnya. Mulai sekarang, saya mengambilnya dengan sebutir garam.
Michael Myers
2
Kami sebenarnya tidak berbicara tentang pola apa pun. Maksud kami kelas bertingkat anonim itu statis. Yaitu menambahkan "statis" antara newdan JComponentdalam contoh ketiga Anda.
Timmmm
Saya menambahkan klarifikasi ke pertanyaan asli untuk menunjukkan apa yang diinginkan.
Timmmm
@MichaelMyers, Dikte di JLS selalu perlu ditafsirkan.
Pacerier
6

Kelas-kelas dalam tidak boleh statis - kelas bertingkat statis bukanlah kelas dalam. Tutorial Java membahasnya di sini .

Andrew Duffy
sumber
1
Saya telah memperbarui pertanyaan dengan mengacu pada nomenklatur resmi.
Thilo
0

kelas dalam anonim tidak pernah statis (mereka tidak dapat mendeklarasikan metode statis atau bidang statis non final), tetapi jika mereka didefinisikan dalam konteks statis (metode statis atau bidang statis) mereka berperilaku sebagai statis dalam arti bahwa mereka tidak bisa mengakses anggota non-statis (misalnya) dari kelas yang melingkupi (seperti yang lainnya dari konteks statis)

Luca
sumber
-3

Pada catatan membuat kelas dalam anonim statis dengan memanggil mereka dalam metode statis.

Ini tidak benar-benar menghapus referensi. Anda dapat mengujinya dengan mencoba membuat serial kelas anonim dan tidak membuat kelas yang melingkupi dapat diserialkan.

Terra Caines
sumber
5
-1: Membuat kelas anonim dalam metode statis sebenarnya tidak menghapus referensi ke kelas luar. Anda dapat mengujinya dengan mencoba membuat serial kelas anonim dan tidak membuat kelas yang melingkupi dapat diserialkan. (Saya baru saja melakukannya.)
Christian Semrau