Kelas Tanpa Nama di Jawa

1. Pengenalan

Dalam tutorial ini, kita akan mempertimbangkan kelas tanpa nama di Java.

Kami akan menerangkan bagaimana kami dapat menyatakan dan membuat contohnya. Kami juga akan membincangkan sifat dan batasan mereka secara ringkas.

2. Pengisytiharan Kelas Tanpa Nama

Kelas tanpa nama adalah kelas dalaman tanpa nama. Oleh kerana mereka tidak mempunyai nama, kami tidak dapat menggunakannya untuk membuat contoh kelas tanpa nama. Hasilnya, kita harus menyatakan dan mewujudkan kelas tanpa nama dalam satu ungkapan pada saat penggunaan.

Kami boleh melanjutkan kelas yang ada atau melaksanakan antara muka.

2.1. Memanjangkan Kelas

Apabila kami membuat kelas tanpa nama dari kelas yang ada, kami menggunakan sintaks berikut:

Dalam kurungan, kami menentukan parameter yang diperlukan oleh pembina kelas yang kami luaskan:

new Book("Design Patterns") { @Override public String description() { return "Famous GoF book."; } }

Secara semula jadi, jika pembina kelas induk tidak menerima hujah, kita harus membiarkan tanda kurung kosong.

2.2. Laksanakan Antaramuka

Kami juga dapat mewujudkan kelas tanpa nama dari antara muka:

Jelas, antara muka Java tidak mempunyai konstruktor, jadi tanda kurung selalu kosong. Ini adalah satu-satunya cara yang harus kita lakukan untuk melaksanakan kaedah antara muka:

new Runnable() { @Override public void run() { ... } }

Setelah kami membuat kelas tanpa nama, kami dapat memberikan contoh tersebut kepada pemboleh ubah agar dapat merujuknya di suatu tempat kemudian.

Kita boleh melakukan ini menggunakan sintaks standard untuk ungkapan Java:

Runnable action = new Runnable() { @Override public void run() { ... } };

Seperti yang telah kita sebutkan, pengisytiharan kelas tanpa nama adalah ungkapan, oleh itu mesti merupakan bahagian dari pernyataan . Ini menjelaskan mengapa kita meletakkan titik koma di akhir penyataan.

Jelas, kita dapat mengelakkan menetapkan instance ke pemboleh ubah jika kita membuat instance tersebut sebaris:

List actions = new ArrayList(); actions.add(new Runnable() { @Override public void run() { ... } });

Kita harus menggunakan sintaks ini dengan berhati-hati kerana mudah membaca kod terutamanya apabila pelaksanaan kaedah run () memerlukan banyak ruang.

3. Hartanah Kelas Tanpa Nama

Terdapat kekhususan tertentu dalam menggunakan kelas tanpa nama sehubungan dengan kelas tingkat atas biasa. Di sini kita menyentuh secara ringkas masalah yang paling praktikal. Untuk maklumat yang paling tepat dan terkini, kami mungkin selalu melihat Spesifikasi Bahasa Java.

3.1. Pembina

Sintaks kelas tanpa nama tidak membenarkan kami menjadikannya melaksanakan pelbagai antara muka. Semasa pembinaan, mungkin terdapat satu contoh kelas tanpa nama . Oleh itu, mereka tidak boleh abstrak. Oleh kerana mereka tidak mempunyai nama, kami tidak dapat memperluasnya. Atas sebab yang sama, kelas tanpa nama tidak boleh menyatakan pembina secara jelas.

Sebenarnya, ketiadaan konstruktor tidak menimbulkan masalah kepada kami kerana sebab-sebab berikut:

  1. kami membuat contoh kelas tanpa nama pada masa yang sama semasa kami menyatakannya
  2. dari contoh kelas tanpa nama, kita dapat mengakses pemboleh ubah tempatan dan merangkumi ahli kelas

3.2. Ahli Statik

Kelas tanpa nama tidak boleh mempunyai ahli statik kecuali kelas yang tetap.

Contohnya, ini tidak akan menyusun:

new Runnable() { static final int x = 0; static int y = 0; // compilation error! @Override public void run() {...} };

Sebaliknya, kami akan mendapat ralat berikut:

The field y cannot be declared static in a non-static inner type, unless initialized with a constant expression

3.3. Skop Pemboleh ubah

Kelas tanpa nama menangkap pemboleh ubah tempatan yang berada dalam ruang lingkup blok di mana kami telah menyatakan kelas:

int count = 1; Runnable action = new Runnable() { @Override public void run() { System.out.println("Runnable with captured variables: " + count); } }; 

Seperti yang kita lihat, jumlah dan tindakan pemboleh ubah tempatan ditentukan dalam blok yang sama. Atas sebab ini, kita dapat mengakses kiraan dari dalam deklarasi kelas.

Perhatikan bahawa untuk dapat menggunakan pemboleh ubah tempatan, mereka mesti benar-benar muktamad. Sejak JDK 8, tidak diperlukan lagi kita menyatakan pemboleh ubah dengan kata kunci akhir . Walaupun begitu, pemboleh ubah tersebut mestilah muktamad . Jika tidak, kami mendapat ralat penyusunan:

[ERROR] local variables referenced from an inner class must be final or effectively final

Agar penyusun memutuskan bahawa pemboleh ubah, sebenarnya, tidak berubah, dalam kod, harus ada satu tempat di mana kita memberikan nilai padanya. Kami mungkin mendapat lebih banyak maklumat mengenai pemboleh ubah akhir yang berkesan dalam artikel kami "Mengapa Pembolehubah Lokal yang Digunakan dalam Lambdas Harus Muktamad atau Berkesan Akhir?"

Mari kita sebutkan bahawa seperti setiap kelas dalaman, kelas tanpa nama dapat mengakses semua anggota kelas yang dilampirkan .

4. Kes Penggunaan Kelas Tanpa Nama

Mungkin terdapat pelbagai aplikasi kelas tanpa nama. Mari kita terokai beberapa kes penggunaan yang mungkin.

4.1. Hierarki dan Enkapsulasi Kelas

We should use inner classes in general use cases and anonymous ones in very specific ones in order to achieve a cleaner hierarchy of classes in our application. When using inner classes, we may achieve a finer encapsulation of the enclosing class's data. If we define the inner class functionality in a top-level class, then the enclosing class should have public or package visibility of some of its members. Naturally, there are situations when it is not very appreciated or even accepted.

4.2. Cleaner Project Structure

We usually use anonymous classes when we have to modify on the fly the implementation of methods of some classes. In this case, we can avoid adding new *.java files to the project in order to define top-level classes. This is especially true if that top-level class would be used just one time.

4.3. UI Event Listeners

In applications with a graphical interface, the most common use case of anonymous classes is to create various event listeners. For example, in the following snippet:

button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ... } }

we create an instance of an anonymous class that implements interface ActionListener. Its actionPerformed method gets triggered when a user clicks the button.

Since Java 8, lambda expressions seem to be a more preferred way though.

5. General Picture

Kelas tanpa nama yang kami anggap di atas hanyalah sebilangan besar kelas bersarang. Umumnya, kelas bersarang adalah kelas yang dinyatakan dalam kelas atau antara muka lain :

Melihat rajah, kita melihat bahawa kelas tanpa nama bersama dengan anggota tempatan dan bukan statik membentuk kelas dalaman yang disebut . Bersama dengan kelas ahli statik , mereka membentuk kelas bersarang.

6. Kesimpulannya

Dalam artikel ini, kami telah mempertimbangkan pelbagai aspek kelas tanpa nama Java. Kami telah menggambarkan juga hierarki umum kelas bersarang.

Seperti biasa, kod lengkap boleh didapati di repositori GitHub kami.