Kelas batin dalam Antarmuka


97

Apakah mungkin untuk membuat kelas dalam dalam sebuah antarmuka?
Jika memungkinkan, mengapa kita ingin membuat kelas dalam seperti itu karena kita tidak akan membuat objek antarmuka apa pun?

Apakah kelas - kelas dalam ini membantu dalam proses pengembangan apa pun?

Jawaban:


51

Ya, Anda dapat membuat kelas bertingkat atau kelas dalam di dalam antarmuka Java (perhatikan bahwa berlawanan dengan kepercayaan populer tidak ada yang namanya " kelas dalam statis ": ini tidak masuk akal, tidak ada yang "dalam" dan tidak ada " outter "ketika kelas bertingkat statis, jadi tidak bisa" batin statis ").

Bagaimanapun, berikut ini mengkompilasi dengan baik:

public interface A {
    class B {
    }
}

Saya pernah melihat itu digunakan untuk meletakkan semacam "pemeriksa kontrak" langsung dalam definisi antarmuka (baik, di kelas bersarang di antarmuka, yang dapat memiliki metode statis, sebaliknya ke antarmuka itu sendiri, yang tidak bisa). Terlihat seperti ini jika saya ingat dengan benar.

public interface A {
    static class B {
        public static boolean verifyState( A a ) {
            return (true if object implementing class A looks to be in a valid state)
        }
    }
}

Perhatikan bahwa saya tidak mengomentari kegunaan hal semacam itu, saya hanya menjawab pertanyaan Anda: itu bisa dilakukan dan ini adalah salah satu jenis penggunaan yang telah saya lihat.

Sekarang saya tidak akan berkomentar tentang kegunaan konstruksi semacam itu dan dari yang pernah saya lihat: Saya telah melihatnya, tetapi ini bukan konstruksi yang sangat umum.

Basis kode 200KLOC di sini di mana ini terjadi tepat nol waktu (tetapi kemudian kami memiliki banyak hal lain yang kami anggap praktik buruk yang terjadi tepat waktu nol juga sehingga orang lain akan menganggapnya normal jadi ...).


Bisakah Anda menambahkan beberapa contoh penggunaan? Saya telah menguji sesuatu yang serupa beberapa waktu lalu dan belum memahami apa yang dapat saya peroleh dari penggunaan konstruksi ini.
Roman

@ Roman: baik saya ingat saya pernah mengalami ini di beberapa proyek (proyek yang relatif bersih akan saya tambahkan tetapi itu bukan milik saya) tetapi saya tidak tahu apakah itu benar-benar bersih atau tidak. Saya telah menambahkan contoh kecil yang terlihat seperti yang saya lihat tetapi sekali lagi: ini bukan kode saya dan saya tidak menggunakan konstruksi itu jadi saya bukan yang paling memenuhi syarat untuk menghasilkan contoh yang valid :) IIRC kelas di dalamnya selalu dinamai, misalnya StateChecker dan panggilan akan selalu terlihat seperti: A.StateChecker.check (a) atau semacamnya.
SyntaxT3rr0r

8
Jika Anda mengatakan bahwa "tidak ada yang namanya" kelas dalam statis "", jawaban Anda bahwa "Anda dapat membuat kelas bersarang atau kelas dalam di dalam antarmuka Java" pada dasarnya salah. Menggunakan definisi Anda yang dipersempit, interfaces tidak dapat memiliki kelas dalam. Anda dapat menghilangkan staticpengubah dari interfacekelas bersarang tapi tetap saja, itu adalah kelas bertingkat, bukan kelas dalam.
Holger

6
Jawaban ini salah. Antarmuka dapat memiliki kelas bertingkat statis tetapi tidak dapat memiliki kelas dalam.
Paul Boddington

1
@Puldinging Anda benar. Bahkan menghapus 'statis', Bkelas tersebut adalah kelas bertingkat statis dan bukan kelas dalam; antarmuka mendapatkan perlakuan khusus. Saya tidak dapat menemukan penyebutan ini secara online, kecuali untuk spesifikasinya sendiri: "Kelas anggota antarmuka secara implisit statis sehingga tidak pernah dianggap sebagai kelas dalam." docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Max Barraclough

110

Ya, kita dapat memiliki kelas di dalam antarmuka. Salah satu contoh penggunaan bisa jadi

public interface Input
{
    public static class KeyEvent {
         public static final int KEY_DOWN = 0;
         public static final int KEY_UP = 1;
         public int type;
         public int keyCode;
         public char keyChar;
    }
    public static class TouchEvent {
         public static final int TOUCH_DOWN = 0;
         public static final int TOUCH_UP = 1;
         public static final int TOUCH_DRAGGED = 2;
         public int type;
         public int x, y;
         public int pointer;
    }
    public boolean isKeyPressed(int keyCode);
    public boolean isTouchDown(int pointer);
    public int getTouchX(int pointer);
    public int getTouchY(int pointer);
    public float getAccelX();
    public float getAccelY();
    public float getAccelZ();
    public List<KeyEvent> getKeyEvents();
    public List<TouchEvent> getTouchEvents();
}

Di sini kode memiliki dua kelas bersarang yang untuk mengenkapsulasi informasi tentang objek acara yang kemudian digunakan dalam definisi metode seperti getKeyEvents (). Memiliki mereka di dalam antarmuka Input meningkatkan kohesi.


3
@Levit Hanya ingin tahu, bagaimana kelas yang diimplementasikan akan terlihat?
pertukaran berlebih

1
Akan sangat senang melihat implementasi beraksi untuk penggunaan di atas. Terima kasih.
Prakash K

45

Penggunaan yang valid, IMHO, adalah mendefinisikan objek yang diterima atau dikembalikan oleh metode antarmuka terlampir. Biasanya struktur penyimpanan data. Dengan cara itu, jika objek hanya digunakan untuk antarmuka itu, Anda memiliki hal-hal dengan cara yang lebih kohesif.

Contohnya:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

Tapi bagaimanapun ... itu hanya masalah selera.


35

Kutipan dari spesifikasi Java 7 :

Antarmuka mungkin berisi deklarasi tipe anggota (§8.5).

Deklarasi tipe anggota dalam sebuah antarmuka secara implisit bersifat statis dan publik. Diijinkan untuk menentukan secara berlebihan salah satu atau kedua pengubah ini.

TIDAK mungkin untuk mendeklarasikan kelas non-statis di dalam antarmuka Java, yang masuk akal bagi saya.


Terima kasih. Ini mungkin jawaban yang paling ringkas dari semuanya.
Joseph

1
Ini adalah jawaban yang saya cari .. tapi OP menanyakan beberapa pertanyaan .. pokoknya ada updoot saya.
Charlie Wallace

11

Kasus penggunaan yang menarik adalah menyediakan semacam implementasi default untuk metode antarmuka melalui kelas dalam seperti yang dijelaskan di sini: https://stackoverflow.com/a/3442218/454667 (untuk mengatasi masalah pewarisan kelas tunggal).


Dan inilah mengapa kelas anggota privat masuk akal.
Vincent

7

Ini tentu saja mungkin, dan satu kasus yang menurut saya berguna adalah ketika antarmuka harus mengeluarkan pengecualian khusus. Anda dapat menyimpan pengecualian dengan antarmuka terkaitnya, yang menurut saya sering kali lebih rapi daripada mengotori pohon sumber Anda dengan tumpukan file pengecualian sepele.

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}

7

Ya, dimungkinkan untuk memiliki definisi kelas statis di dalam antarmuka, tetapi mungkin aspek yang paling berguna dari fitur ini adalah saat menggunakan jenis enum (yang merupakan jenis kelas statis khusus). Misalnya Anda dapat memiliki sesuatu seperti ini:

public interface User {
    public enum Role {
        ADMIN("administrator"),
        EDITOR("editor"),
        VANILLA("regular user");

        private String description;

        private Role(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    public String getName();
    public void setName(String name);
    public Role getRole();
    public void setRole(Role role);
    ...
}


1

Mungkin saat Anda menginginkan konstruksi yang lebih kompleks seperti beberapa perilaku implementasi yang berbeda, pertimbangkan:

public interface A {
    public void foo();

    public static class B implements A {
        @Override
        public void foo() {
            System.out.println("B foo");
        }
    }
}

Ini adalah antarmuka Anda dan ini akan menjadi implementee:

public class C implements A {
    @Override
    public void foo() {
        A.B b = new A.B();
        b.foo(); 
    }

    public static void main(String[] strings) {
        C c = new C();
        c.foo();
    }
}

Mungkin memberikan beberapa implementasi statis, tetapi tidak akan membingungkan, saya tidak tahu.


0

Saya menemukan kegunaan dari jenis konstruksi ini.

  1. Anda dapat menggunakan konstruksi ini untuk mendefinisikan dan mengelompokkan semua konstanta final statis.
  2. Karena, ini adalah antarmuka yang dapat Anda implementasikan di kelas.

Anda memiliki akses ke semua konstanta yang dikelompokkan; nama kelas bertindak sebagai namespace dalam kasus ini.


0

Anda juga dapat membuat kelas statis "Helper" untuk fungsionalitas umum untuk objek yang mengimplementasikan antarmuka ini:

public interface A {
    static class Helper {
        public static void commonlyUsedMethod( A a ) {
           ...
        }
    }
}

0

Saya membutuhkannya sekarang. Saya memiliki antarmuka di mana akan lebih mudah untuk mengembalikan kelas unik dari beberapa metode itu. Kelas ini hanya masuk akal sebagai wadah untuk tanggapan dari metode antarmuka ini.

Oleh karena itu, akan lebih mudah untuk memiliki definisi kelas bertingkat statis, yang dikaitkan hanya dengan antarmuka ini, karena antarmuka ini harus menjadi satu-satunya tempat di mana kelas penampung hasil ini pernah dibuat.


0

Misalnya ciri-ciri (seperti antarmuka dengan metode yang diterapkan) di Groovy. Mereka dikompilasi ke antarmuka yang berisi kelas dalam tempat semua metode diimplementasikan.

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.