it-swarm-id.com

Mengapa antarmuka bersarang statis digunakan di Jawa?

Saya baru saja menemukan antarmuka bersarang statis di basis kode kami.

class Foo {
    public static interface Bar {
        /* snip */
    }
    /* snip */
}

Saya belum pernah melihat ini sebelumnya. Pengembang asli berada di luar jangkauan. Karena itu saya harus bertanya kepada SO:

Apa yang dimaksud dengan semantik di belakang antarmuka statis? Apa yang akan berubah, jika saya menghapus static? Mengapa ada orang yang melakukan hal ini?

231
Mo.

Kata kunci statis dalam contoh di atas adalah redundan (antarmuka bersarang secara otomatis "statis") dan dapat dihapus tanpa efek pada semantik; Saya akan merekomendasikan itu dihapus. Hal yang sama berlaku untuk "publik" pada metode antarmuka dan "final publik" pada bidang antarmuka - pengubah berlebihan dan hanya menambahkan kekacauan pada kode sumber.

Either way, pengembang hanya mendeklarasikan antarmuka bernama Foo.Bar. Tidak ada hubungan lebih lanjut dengan kelas terlampir, kecuali kode yang tidak dapat mengakses Foo tidak akan dapat mengakses Foo.Bar juga. (Dari kode sumber - bytecode atau refleksi dapat mengakses Foo.Bar bahkan jika Foo adalah paket-pribadi!)

Merupakan gaya yang dapat diterima untuk membuat antarmuka bersarang dengan cara ini jika Anda mengharapkannya hanya digunakan dari kelas luar, sehingga Anda tidak membuat nama tingkat atas yang baru. Sebagai contoh:

public class Foo {
    public interface Bar {
        void callback();
    }
    public static void registerCallback(Bar bar) {...}
}
// ...elsewhere...
Foo.registerCallback(new Foo.Bar() {
    public void callback() {...}
});
291
Jesse Glick

Pertanyaan telah dijawab, tetapi salah satu alasan bagus untuk menggunakan antarmuka bersarang adalah jika fungsinya terkait langsung dengan kelas yang ada di dalamnya. Contoh yang bagus untuk ini adalah Listener. Jika Anda memiliki kelas Foo dan Anda ingin kelas lain dapat mendengarkan acara di dalamnya, Anda dapat mendeklarasikan antarmuka bernama FooListener, yang ok, tetapi mungkin akan lebih jelas untuk mendeklarasikan antarmuka bersarang dan memiliki kelas-kelas lain mengimplementasikan Foo.Listener (kelas bertingkat Foo.Event tidak buruk seiring dengan ini).

71
ColinD

Antarmuka anggota secara implisit statis. Pengubah statis dalam contoh Anda dapat dihapus tanpa mengubah semantik kode. Lihat juga Java Spesifikasi Bahasa 8.5.1. Pernyataan Tipe Anggota Statis

14
Bas Leijdekkers

Antarmuka dalam harus statis agar dapat diakses. Antarmuka tidak terkait dengan instance kelas, tetapi dengan kelas itu sendiri, sehingga akan diakses dengan Foo.Bar, seperti:

public class Baz implements Foo.Bar {
   ...
}

Dalam banyak hal, ini tidak berbeda dari kelas dalam statis.

9

Jawaban Jesse dekat, tapi saya pikir ada kode yang lebih baik untuk menunjukkan mengapa antarmuka internal mungkin berguna. Lihatlah kode di bawah ini sebelum Anda membaca. Dapatkah Anda menemukan mengapa antarmuka bagian dalam bermanfaat? Jawabannya adalah kelas DoSomethingAlready dapat dipakai dengan apa saja kelas yang mengimplementasikan A dan C; bukan hanya Kebun Binatang kelas beton. Tentu saja, ini dapat dicapai bahkan jika AC tidak dalam, tetapi bayangkan menggabungkan nama yang lebih panjang (bukan hanya A dan C), dan melakukan ini untuk kombinasi lain (katakanlah, A dan B, C dan B, dll) dan Anda dengan mudah lihat bagaimana hal-hal di luar kendali. Belum lagi orang-orang yang meninjau pohon sumber Anda akan kewalahan oleh antarmuka yang hanya bermakna dalam satu kelas. Jadi, untuk meringkas, antarmuka bagian dalam memungkinkan pembangunan jenis khusus dan meningkatkan enkapsulasi mereka.

class ConcreteA implements A {
 :
}

class ConcreteB implements B {
 :
}

class ConcreteC implements C {
 :
}

class Zoo implements A, C {
 :
}

class DoSomethingAlready {
  interface AC extends A, C { }

  private final AC ac;

  DoSomethingAlready(AC ac) {
    this.ac = ac;
  }
}
6
user1982892

Untuk menjawab pertanyaan Anda secara langsung, lihat di Map.Entry.

Map.Entry

juga ini mungkin berguna

Entri blog Inerfaces Bersarang Statis

3
Henry B

Pada tahun 1998, Philip Wadler menyarankan perbedaan antara antarmuka statis dan antarmuka non-statis.

Sejauh yang saya bisa lihat, satu-satunya perbedaan dalam membuat antarmuka non-statis adalah bahwa sekarang dapat mencakup kelas-kelas dalam non-statis; jadi perubahan tidak akan membuat program Java yang ada tidak valid.

Misalnya, ia mengusulkan solusi untuk Masalah Ekspresi , yang merupakan ketidakcocokan antara ekspresi sebagai "seberapa banyak bahasa Anda dapat mengekspresikan" di satu sisi dan ekspresi sebagai "istilah yang Anda coba untuk wakili dalam bahasa Anda "di sisi lain.

Contoh perbedaan antara antarmuka bersarang statis dan non-statis dapat dilihat di kode sampelnya :

// This code does NOT compile
class LangF<This extends LangF<This>> {
    interface Visitor<R> {
        public R forNum(int n);
    }

    interface Exp {
        // since Exp is non-static, it can refer to the type bound to This
        public <R> R visit(This.Visitor<R> v);
    }
}

Sarannya tidak pernah berhasil di Java 1.5.0. Oleh karena itu, semua jawaban lain benar: tidak ada perbedaan untuk antarmuka bersarang statis dan non-statis.

0
Pindatjuh

Jika Anda akan mengubah kelas Foo menjadi antarmuka Foo kata kunci "publik" pada contoh di atas juga akan berlebihan karena

antarmuka yang didefinisikan di dalam antarmuka lain akan secara implisit statis publik.

0
Danylo Volokh

Biasanya saya melihat kelas dalam statis. Kelas dalam statis tidak dapat mereferensikan kelas yang berisi dimana kelas non-statis bisa. Kecuali Anda menjalankan beberapa tabrakan paket (sudah ada antarmuka bernama Bar dalam paket yang sama dengan Foo) Saya pikir saya akan membuatnya menjadi file sendiri. Ini juga bisa menjadi keputusan desain untuk menegakkan koneksi logis antara Foo dan Bar. Mungkin penulis bermaksud Bar hanya digunakan dengan Foo (meskipun antarmuka statis tidak akan menegakkan ini, hanya koneksi logis)

0
basszero