Kelas statis dan kelas dalam di Java

Kelas bertingkat adalah kelas yang dideklarasikan sebagai anggota kelas atau cakupan lain. Kelas bersarang adalah salah satu cara untuk mengatur kode Anda dengan lebih baik. Misalnya, Anda memiliki kelas non-bertingkat (juga dikenal sebagai kelas tingkat atas ) yang menyimpan objek dalam larik yang dapat diubah ukurannya, diikuti dengan kelas iterator yang mengembalikan setiap objek. Daripada mencemari namespace kelas tingkat atas, Anda bisa mendeklarasikan kelas iterator sebagai anggota kelas koleksi larik yang dapat diubah ukurannya. Ini berfungsi karena keduanya terkait erat.

Di Java, kelas bertingkat dikategorikan sebagai kelas anggota statis atau kelas dalam . Kelas-kelas dalam adalah kelas anggota non-statis, kelas lokal, atau kelas anonim. Dalam tutorial ini Anda akan belajar bagaimana bekerja dengan kelas anggota statis dan tiga jenis kelas dalam dalam kode Java Anda.

Hindari kebocoran memori di kelas bersarang

Lihat juga tip Java yang terkait dengan tutorial ini, di mana Anda akan mempelajari mengapa class bersarang rentan terhadap kebocoran memori.

Kelas statis di Java

Dalam tutorial Kelas dan objek Java 101 saya di Java, Anda telah mempelajari cara mendeklarasikan bidang statis dan metode statis sebagai anggota kelas. Di Class dan inisialisasi objek di Java, Anda telah mempelajari cara mendeklarasikan penginisialisasi statis sebagai anggota class. Sekarang Anda akan belajar cara mendeklarasikan kelas statis . Secara formal dikenal sebagai kelas anggota statis , ini adalah kelas bersarang yang Anda deklarasikan pada tingkat yang sama dengan entitas statis lainnya, menggunakan statickata kunci. Berikut adalah contoh deklarasi kelas anggota statis:

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

Contoh ini memperkenalkan kelas tingkat atas Cdengan bidang fstatis m(), metode statis, penginisialisasi statis, dan kelas anggota statis D. Perhatikan bahwa Dadalah anggota dari C. Bidang statis f, metode statis m(), dan penginisialisasi statis juga merupakan anggota dari C. Karena semua elemen ini milik kelas C, itu dikenal sebagai kelas penutup . Kelas Ddikenal sebagai kelas tertutup .

Enklosur dan aturan akses

Meskipun tertutup, kelas anggota statis tidak dapat mengakses bidang instance kelas yang melingkupi dan memanggil metode instance-nya. Namun, ia dapat mengakses bidang statis kelas yang melingkupi dan menjalankan metode statisnya, bahkan anggota yang dideklarasikan private. Untuk mendemonstrasikan, Listing 1 mendeklarasikan sebuah EnclosingClassdengan sebuah SMClass.

Daftar 1. Mendeklarasikan kelas anggota statis (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(); } } } 

Kode 1 mendeklarasikan kelas tingkat atas yang dinamai EnclosingClassdengan bidang skelas, metode kelas m1()dan m2(), dan kelas anggota statis SMClass. SMClassmendeklarasikan metode kelas accessEnclosingClass()dan metode instance accessEnclosingClass2(). Perhatikan hal-hal berikut:

  • m2()'doa s dari SMClass' s accessEnclosingClass()metode memerlukan SMClass.awalan karena accessEnclosingClass()dinyatakan static.
  • accessEnclosingClass()mampu akses EnclosingClass's slapangan dan memanggil nya m1()metode, meskipun keduanya telah dinyatakan private.

Listing 2 hadiah sumber kode untuk sebuah SMCDemokelas aplikasi yang menunjukkan bagaimana untuk memohon SMClass's accessEnclosingClass()metode. Ini juga mendemonstrasikan cara membuat instance SMClassdan memanggil accessEnclosingClass2()metode instance -nya .

Kode 2. Memanggil metode kelas anggota statis (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 pada Listing 2, jika Anda ingin memanggil metode kelas tingkat atas dari dalam kelas tertutup, Anda harus memberi awalan nama kelas tertutup dengan nama kelas penutupnya. Demikian juga, untuk membuat instance kelas tertutup Anda harus memberi awalan nama kelas itu dengan nama kelas yang melingkupinya. Anda kemudian dapat menjalankan metode instance dengan cara biasa.

Susun Daftar 1 dan 2 sebagai berikut:

 javac *.java 

Saat Anda mengompilasi kelas penutup yang berisi kelas anggota statis, kompilator membuat file kelas untuk kelas anggota statis yang namanya terdiri dari nama kelas yang melingkupinya, karakter tanda dolar, dan nama kelas anggota statis. Dalam hal ini, hasil kompilasi dalam EnclosingClass$SMCClass.classdan EnclosingClass.class.

Jalankan aplikasinya sebagai berikut:

 java SMCDemo 

Anda harus mengamati keluaran berikut:

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

Contoh: Kelas statis dan Java 2D

Pustaka kelas standar Java adalah pustaka runtime dari file kelas, yang menyimpan kelas yang dikompilasi dan tipe referensi lainnya. Pustaka menyertakan banyak contoh kelas anggota statis, beberapa di antaranya ditemukan di kelas bentuk geometris 2D Java yang ada di dalam java.awt.geompaket. (Anda akan belajar tentang paket di tutorial Java 101 berikutnya .)

The Ellipse2Dkelas ditemukan di java.awt.geommenggambarkan elips, yang didefinisikan oleh persegi panjang framing dalam hal sebuah (x, y) sudut kiri atas bersama dengan lebar dan tinggi luasan. Fragmen kode berikut menunjukkan bahwa arsitektur kelas ini didasarkan pada Floatdan Doublekelas anggota statis, yang keduanya merupakan 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 } 

The Floatdan Doublekelas memperpanjang Ellipse2D, menyediakan floating-point dan presisi ganda floating-point Ellipse2Dimplementasi. Pengembang menggunakan Floatuntuk mengurangi konsumsi memori, terutama karena Anda mungkin memerlukan ribuan atau lebih objek ini untuk membuat satu adegan 2D. Kami menggunakan Doublesaat akurasi yang lebih tinggi diperlukan.

Anda tidak dapat membuat instance Ellipse2Dkelas abstrak , tetapi Anda dapat membuat instance Floatatau Double. Anda juga dapat memperluas Ellipse2Duntuk mendeskripsikan bentuk kustom yang didasarkan pada elips.

Sebagai contoh, katakanlah Anda ingin memperkenalkan Circle2Dkelas, yang tidak ada dalam java.awt.geompaket. Fragmen kode berikut menunjukkan bagaimana Anda akan membuat Ellipse2Dobjek dengan implementasi floating-point:

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

Fragmen kode berikutnya menunjukkan bagaimana Anda akan membuat Ellipse2Dobjek dengan implementasi floating-point presisi ganda:

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

Sekarang Anda bisa memanggil salah satu metode yang dideklarasikan di Floatatau Doubledengan memanggil metode tersebut pada Ellipse2Dreferensi yang dikembalikan (misalnya, e2d.getX()). Dengan cara yang sama, Anda bisa memanggil salah satu metode yang umum untuk Floatdan Double, dan yang dideklarasikan dalam Ellipse2D. Contohnya adalah:

 e2d.contains(2.0, 3.0) 

Itu melengkapi pengenalan kelas anggota statis. Selanjutnya kita akan melihat kelas dalam, yang merupakan kelas anggota non-statis, kelas lokal, atau kelas anonim. Anda akan belajar bagaimana bekerja dengan ketiga tipe kelas dalam.

unduh Dapatkan kodenya Unduh kode sumber untuk contoh dalam tutorial ini. Dibuat oleh Jeff Friesen untuk JavaWorld.

Inner classes, type 1: Non-static member classes

You've learned previously in the Java 101 series how to declare non-static (instance) fields, methods, and constructors as members of a class. You can also declare non-static member classes, which are nested non-static classes that you declare at the same level as instance fields, methods, and constructors. Consider this example:

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

Here, we introduce top-level class C with instance field f, instance method m(), a constructor, and non-static member class D. All of these entities are members of class C, which encloses them. However, unlike in the previous example, these instance entities are associated with instances ofC and not with the C class itself.

Each instance of the non-static member class is implicitly associated with an instance of its enclosing class. The non-static member class's instance methods can call the enclosing class's instance methods and access its instance fields. To demonstrate this access, Listing 3 declares an EnclosingClass with a nested NSMClass.

Listing 3. Declare an enclosing class with a nested non-static member class (EnclosingClass.java, version 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(); } } } 

Listing 3 declares a top-level class named EnclosingClass with instance field s, instance method m(), and non-static member class NSMClass. Furthermore, NSMClass declares instance method accessEnclosingClass().

Because accessEnclosingClass() is non-static, NSMClass must be instantiated before this method can be called. This instantiation must take place via an instance of EnclosingClass, as shown in Listing 4.

Listing 4. NSMCDemo.java

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

Listing 4's main() method first instantiates EnclosingClass and saves its reference in local variable ec. The main() method then uses the EnclosingClass reference as a prefix to the new operator, in order to instantiate NSMClass. The NSMClass reference is then used to call accessEnclosingClass().

Should I use 'new' with a reference to the enclosing class?

Prefixing new with a reference to the enclosing class is rare. Instead, you will typically call an enclosed class's constructor from within a constructor or an instance method of its enclosing class.

Compile Listings 3 and 4 as follows:

 javac *.java 

When you compile an enclosing class that contains a non-static member class, the compiler creates a class file for the non-static member class whose name consists of its enclosing class's name, a dollar-sign character, and the non-static member class's name. In this case, compiling results in EnclosingClass$NSMCClass.class and EnclosingClass.class.

Run the application as follows:

 java NSMCDemo 

You should observe the following output:

 Called from NSMClass's accessEnclosingClass() method 

When (and how) to qualify 'this'

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()metode yang membuat instance KeySetsaat diperlukan dan mengembalikan instance ini atau instance yang disimpan dalam cache. Berikut metode lengkapnya: