Kelas statik dan kelas dalaman di Jawa

Kelas bersarang adalah kelas yang dinyatakan sebagai ahli kelas atau ruang lingkup lain. Kelas bersarang adalah salah satu cara untuk mengatur kod anda dengan lebih baik. Sebagai contoh, katakan anda mempunyai kelas yang tidak bersarang (juga dikenali sebagai kelas tingkat atas ) yang menyimpan objek dalam susunan yang boleh diubah saiznya, diikuti oleh kelas iterator yang mengembalikan setiap objek. Daripada mencemarkan ruang nama kelas tingkat atas, anda boleh menyatakan kelas iterator sebagai ahli kelas pengumpulan array yang boleh diubah saiznya. Ini berfungsi kerana kedua-duanya saling berkaitan.

Di Jawa, kelas bersarang dikategorikan sebagai kelas ahli statik atau kelas dalaman . Kelas dalaman adalah kelas ahli tidak statik, kelas tempatan, atau kelas tanpa nama. Dalam tutorial ini, anda akan belajar bagaimana bekerja dengan kelas ahli statik dan tiga jenis kelas dalaman dalam kod Java anda.

Elakkan kebocoran memori di kelas bersarang

Lihat juga tip Java yang berkaitan dengan tutorial ini, di mana anda akan mengetahui mengapa kelas bersarang rentan terhadap kebocoran memori.

Kelas statik di Jawa

Dalam kelas dan objek tutorial Java 101 saya di Java, anda belajar bagaimana menyatakan medan statik dan kaedah statik sebagai ahli kelas. Dalam kelas dan inisialisasi objek di Java, anda belajar bagaimana menyatakan pemula statis sebagai anggota kelas. Sekarang anda akan belajar cara menyatakan kelas statik . Secara rasmi dikenali sebagai kelas ahli statik , ini adalah kelas bersarang yang anda nyatakan pada tahap yang sama dengan entiti statik lain, menggunakan statickata kunci. Berikut adalah contoh pengisytiharan kelas ahli statik:

 class C { static int f; static void m() {} static { f = 2; } static class D { // members } } 

Contoh ini memperkenalkan kelas tahap atas Cdengan medan fstatik m(), kaedah statik, pemula statik, dan kelas ahli statik D. Perhatikan bahawa Dahli C. Medan statik f, kaedah statik m(), dan pemula statik juga merupakan anggota C. Oleh kerana semua elemen ini tergolong dalam kelas C, ia dikenali sebagai kelas lampiran . Kelas Ddikenali sebagai kelas tertutup .

Peraturan penutupan dan akses

Walaupun tertutup, kelas anggota statik tidak dapat mengakses medan contoh kelas melampirkan dan menggunakan kaedah contohnya. Namun, ia dapat mengakses medan statik kelas melampirkan dan menggunakan kaedah statiknya, bahkan anggota yang dinyatakan private. Untuk menunjukkan, Penyenaraian 1 menyatakan EnclosingClassdengan bersarang SMClass.

Penyenaraian 1. Menyatakan kelas ahli statik (EnclosingClass.java, versi 1)

 class EnclosingClass { private static String s; private static void m1() { System.out.println(s); } static void m2() { SMClass.accessEnclosingClass(); } static class SMClass { static void accessEnclosingClass() { s = "Called from SMClass's accessEnclosingClass() method"; m1(); } void accessEnclosingClass2() { m2(); } } } 

Penyenaraian 1 mengisytiharkan kelas tingkat atas dinamakan EnclosingClassdengan medan skelas, kaedah kelas m1()dan m2(), dan kelas ahli statik SMClass. SMClassmenyatakan kaedah kelas accessEnclosingClass()dan kaedah contoh accessEnclosingClass2(). Perhatikan perkara berikut:

  • m2()'doa s SMClass' s accessEnclosingClass()Cara memerlukan SMClass.awalan kerana accessEnclosingClass()diisytiharkan static.
  • accessEnclosingClass()dapat memberi akses EnclosingClass's sbidang dan panggilan yang m1()kaedah, walaupun kedua-duanya telah diisytiharkan private.

Penyenaraian 2 hadiah kod sumber kepada SMCDemokelas aplikasi yang menunjukkan bagaimana untuk menggunakan SMClass's accessEnclosingClass()kaedah. Ini juga menunjukkan bagaimana membuat instansi SMClassdan menggunakan accessEnclosingClass2()kaedah contohnya.

Penyenaraian 2. Memohon kaedah kelas ahli statik (SMCDemo.java)

 public class SMCDemo { public static void main(String[] args) { EnclosingClass.SMClass.accessEnclosingClass(); EnclosingClass.SMClass smc = new EnclosingClass.SMClass(); smc.accessEnclosingClass2(); } } 

Seperti yang ditunjukkan dalam Penyenaraian 2, jika anda ingin menggunakan kaedah kelas atasan dari dalam kelas tertutup, anda mesti mengawali nama kelas tertutup dengan nama kelas yang dilampirkan. Demikian juga, untuk membuat kelas tertutup, anda mesti mengawali nama kelas tersebut dengan nama kelas yang dilampirkan. Anda kemudian boleh menggunakan kaedah contoh dengan cara biasa.

Susun Senarai 1 dan 2 seperti berikut:

 javac *.java 

Apabila anda menyusun kelas lampiran yang mengandungi kelas ahli statik, penyusun membuat fail kelas untuk kelas ahli statik yang namanya terdiri daripada nama kelas yang dilampirkan, watak tanda dolar, dan nama kelas ahli statik. Dalam kes ini, menyusun hasil dalam EnclosingClass$SMCClass.classdan EnclosingClass.class.

Jalankan aplikasi seperti berikut:

 java SMCDemo 

Anda harus memerhatikan output berikut:

 Called from SMClass's accessEnclosingClass() method Called from SMClass's accessEnclosingClass() method 

Contoh: Kelas statik dan Java 2D

Pustaka kelas standard Java adalah perpustakaan runtime fail kelas, yang menyimpan kelas yang disusun dan jenis rujukan lain. Perpustakaan merangkumi banyak contoh kelas ahli statik, beberapa di antaranya terdapat di kelas bentuk geometri Java 2D yang terdapat di dalam java.awt.geompakej. (Anda akan belajar mengenai pakej dalam tutorial Java 101 seterusnya .)

The Ellipse2Dkelas dijumpai di dalam java.awt.geommenerangkan elips, yang ditakrifkan oleh segi empat rangka segi yang (x, y) sudut atas kiri bersama-sama dengan lebar dan tinggi takat. Fragmen kod berikut menunjukkan bahawa seni bina kelas ini berdasarkan Floatdan Doublekelas ahli statik, yang kedua-dua subkelas Ellipse2D:

 public abstract class Ellipse2D extends RectangularShape { public static class Float extends Ellipse2D implements Serializable { public float x, y, width, height; public Float() { } public Float(float x, float y, float w, float h) { setFrame(x, y, w, h); } public double getX() { return (double) x; } // additional instance methods } public static class Double extends Ellipse2D implements Serializable { public double x, y, width, height; public Double() { } public Double(double x, double y, double w, double h) { setFrame(x, y, w, h); } public double getX() { return x; } // additional instance methods } public boolean contains(double x, double y) { // ... } // additional instance methods shared by Float, Double, and other // Ellipse2D subclasses } 

Yang Floatdan Doublekelas melanjutkan Ellipse2D, memberikan terapung-titik dan titik apung ketepatan double Ellipse2Dpelaksanaan. Pembangun menggunakan Floatuntuk mengurangkan penggunaan memori, terutamanya kerana anda mungkin memerlukan ribuan atau lebih objek ini untuk membina pemandangan 2D. Kami menggunakan Doubleapabila ketepatan yang lebih besar diperlukan.

Anda tidak dapat mewujudkan Ellipse2Dkelas abstrak , tetapi anda boleh membuat contoh sama ada Floatatau Double. Anda juga dapat memperluas Ellipse2Duntuk menerangkan bentuk khusus yang berdasarkan elips.

Sebagai contoh, katakan anda ingin memperkenalkan Circle2Dkelas yang tidak terdapat dalam java.awt.geompakej. Fragmen kod berikut menunjukkan bagaimana anda membuat Ellipse2Dobjek dengan pelaksanaan floating-point:

 Ellipse2D e2d = new Ellipse2D.Float(10.0f, 10.0f, 20.0f, 30.0f); 

Fragmen kod seterusnya menunjukkan bagaimana anda membuat Ellipse2Dobjek dengan pelaksanaan titik apungan ketepatan ganda:

 Ellipse2D e2d = new Ellipse2D.Double(10.0, 10.0, 20.0, 30.0); 

Anda sekarang boleh menggunakan salah satu kaedah yang dinyatakan dalam Floatatau Doubledengan menggunakan kaedah tersebut pada Ellipse2Drujukan yang dikembalikan (mis., e2d.getX()). Dengan cara yang sama, anda boleh menggunakan salah satu kaedah yang biasa Floatdan Double, dan yang dinyatakan dalam Ellipse2D. Contohnya ialah:

 e2d.contains(2.0, 3.0) 

Itu melengkapkan pengenalan kepada kelas ahli statik. Seterusnya kita akan melihat kelas dalaman, iaitu kelas ahli tidak statik, kelas tempatan, atau kelas tanpa nama. Anda akan belajar bagaimana bekerja dengan ketiga-tiga jenis kelas dalaman.

muat turun Dapatkan kod Muat turun kod sumber untuk contoh dalam tutorial ini. Dicipta oleh Jeff Friesen untuk JavaWorld.

Kelas dalaman, jenis 1: Kelas ahli tidak statik

Anda telah belajar sebelumnya dalam siri Java 101 bagaimana menyatakan bidang, kaedah, dan konstruktor bukan statik (contoh) sebagai ahli kelas. Anda juga boleh mengisytiharkan kelas ahli bukan statik , iaitu kelas bukan statik bersarang yang anda nyatakan pada tahap yang sama dengan medan, kaedah, dan pembina contoh. Pertimbangkan contoh ini:

 class C { int f; void m() {} C() { f = 2; } class D { // members } } 

Di sini, kami memperkenalkan kelas tingkat atas Cdengan medan fcontoh m(), kaedah contoh , konstruktor, dan kelas anggota tidak statik D. Semua entiti ini adalah ahli kelas C, yang merangkumi mereka. Walau bagaimanapun, tidak seperti contoh sebelumnya, entiti contoh ini dikaitkan dengan contohC dan bukan dengan Ckelas itu sendiri.

Setiap contoh kelas anggota tidak statik secara implisit dikaitkan dengan contoh kelas terlampirnya. Kaedah contoh kelas ahli tidak statik boleh memanggil kaedah contoh kelas melampirkan dan mengakses medan contohnya. Untuk menunjukkan akses ini, Penyenaraian 3 menyatakan EnclosingClassdengan bersarang NSMClass.

Penyenaraian 3. Menyatakan kelas lampiran dengan kelas ahli bukan statik bersarang (EnclosingClass.java, versi 2)

 class EnclosingClass { private String s; private void m() { System.out.println(s); } class NSMClass { void accessEnclosingClass() { s = "Called from NSMClass's accessEnclosingClass() method"; m(); } } } 

Penyenaraian 3 menyatakan kelas tingkat atas yang dinamakan EnclosingClassdengan medan scontoh m(), kaedah contoh , dan kelas anggota bukan statik NSMClass. Selanjutnya, NSMClassmenyatakan kaedah contoh accessEnclosingClass().

Kerana accessEnclosingClass()tidak statik, NSMClassmesti dibuat contoh sebelum kaedah ini dapat dipanggil. Instansiasi ini harus dilakukan melalui contoh EnclosingClass, seperti yang ditunjukkan dalam Penyenaraian 4.

Penyenaraian 4. NSMCDemo.java

 public class NSMCDemo { public static void main(String[] args) { EnclosingClass ec = new EnclosingClass(); ec.new NSMClass().accessEnclosingClass(); } } 

main()Kaedah penyenaraian 4 pertama memberi contoh EnclosingClassdan menyimpan rujukannya dalam pemboleh ubah tempatan ec. The main()Cara kemudian menggunakan EnclosingClassrujukan sebagai awalan kepada newpengendali, untuk memberi contoh NSMClass. The NSMClassrujukan kemudiannya digunakan untuk panggilan accessEnclosingClass().

Perlukah saya menggunakan 'baru' dengan merujuk kepada kelas lampiran?

Awalan newdengan rujukan ke kelas lampiran jarang berlaku. Sebagai gantinya, anda biasanya akan memanggil konstruktor kelas tertutup dari dalam konstruktor atau kaedah contoh kelas penutupnya.

Susun Senarai 3 dan 4 seperti berikut:

 javac *.java 

Apabila anda menyusun kelas lampiran yang mengandungi kelas ahli bukan statik, penyusun membuat fail kelas untuk kelas ahli bukan statik yang namanya terdiri daripada nama kelas yang dilampirkan, watak tanda dolar, dan kelas anggota bukan statik nama. Dalam kes ini, menyusun hasil dalam EnclosingClass$NSMCClass.classdan EnclosingClass.class.

Jalankan aplikasi seperti berikut:

 java NSMCDemo 

Anda harus memerhatikan output berikut:

 Called from NSMClass's accessEnclosingClass() method 

Bila (dan bagaimana) untuk memenuhi syarat 'ini'

An enclosed class's code can obtain a reference to its enclosing-class instance by qualifying reserved word this with the enclosing class's name and the member access operator (.). For example, if code within accessEnclosingClass() needed to obtain a reference to its EnclosingClass instance, it would specify EnclosingClass.this. Because the compiler generates code to accomplish this task, specifying this prefix is rare.

Example: Non-static member classes in HashMap

The standard class library includes non-static member classes as well as static member classes. For this example, we'll look at the HashMap class, which is part of the Java Collections Framework in the java.util package. HashMap, which describes a hash table-based implementation of a map, includes several non-static member classes.

For example, the KeySet non-static member class describes a set-based view of the keys contained in the map. The following code fragment relates the enclosed KeySet class to its HashMap enclosing class:

 public class HashMap extends AbstractMap implements Map, Cloneable, Serializable { // various members final class KeySet extends AbstractSet { // various members } // various members } 

The and syntaxes are examples of generics, a suite of related language features that help the compiler enforce type safety. I'll introduce generics in an upcoming Java 101 tutorial. For now, you just need to know that these syntaxes help the compiler enforce the type of key objects that can be stored in the map and in the keyset, and the type of value objects that can be stored in the map.

HashMapmenyediakan keySet()kaedah yang memberi contoh KeySetapabila perlu dan mengembalikan kejadian ini atau contoh yang disimpan dalam cache. Inilah kaedah lengkap: