Mengapa kita tidak dapat memiliki metode statis di kelas batin non-statis?
Jika saya membuat kelas dalam statis itu berfungsi. Mengapa?
static
.")
Mengapa kita tidak dapat memiliki metode statis di kelas batin non-statis?
Jika saya membuat kelas dalam statis itu berfungsi. Mengapa?
static
.")
Jawaban:
Karena turunan dari kelas dalam secara implisit dikaitkan dengan turunan dari kelas luarnya, ia tidak dapat mendefinisikan metode statis itu sendiri. Karena kelas bersarang statis tidak dapat merujuk langsung ke variabel instan atau metode yang didefinisikan dalam kelas terlampir, ia dapat menggunakannya hanya melalui referensi objek, aman untuk mendeklarasikan metode statis di kelas bersarang statis.
A.B.sync(X)
atau bahkan (dari dalam A) B.sync(x)
?
Tidak banyak gunanya mengizinkan metode statis di kelas batin non-statis; bagaimana Anda mengaksesnya? Anda tidak dapat mengakses (setidaknya pada awalnya) instance kelas dalam non-statis tanpa melalui instance kelas luar. Tidak ada cara yang sepenuhnya statis untuk membuat kelas dalam yang tidak statis.
Untuk kelas luar Outer
, Anda dapat mengakses metode statis test()
seperti ini:
Outer.test();
Untuk kelas dalam statis Inner
, Anda dapat mengakses metode statisnya innerTest()
seperti ini:
Outer.Inner.innerTest();
Namun, jika Inner
tidak statis, sekarang tidak ada cara statis murni untuk referensi metode innertest
. Kelas dalam non-statis terkait dengan turunan khusus dari kelas luarnya. Fungsi berbeda dari konstanta, di mana referensi ke Outer.Inner.CONSTANT
dijamin tidak ambigu dengan cara yang tidak dipanggil fungsi Outer.Inner.staticFunction();
. Katakanlah Anda memiliki Inner.staticFunction()
panggilan itu getState()
, yang didefinisikan dalam Outer
. Jika Anda mencoba menjalankan fungsi statis itu, Anda sekarang memiliki referensi yang ambigu ke kelas Inner. Yaitu, pada instance kelas dalam mana Anda menjalankan fungsi statis? Itu penting. Lihat, tidak ada cara yang benar-benar statis untuk referensi metode statis itu, karena referensi implisit ke objek luar.
Paul Bellora benar bahwa para perancang bahasa bisa mengizinkan ini. Mereka kemudian harus dengan hati-hati melarang akses ke referensi implisit ke kelas luar dalam metode statis dari kelas dalam non-statis. Pada titik ini, berapakah nilai dari ini menjadi kelas dalam jika Anda tidak dapat mereferensikan kelas luar, kecuali secara statis? Dan jika akses statis baik-baik saja, mengapa tidak mendeklarasikan seluruh kelas dalam statis? Jika Anda hanya membuat kelas dalam itu sendiri statis, maka Anda tidak memiliki referensi implisit ke kelas luar, dan Anda tidak lagi memiliki ambiguitas ini.
Jika Anda benar - benar membutuhkan metode statis pada kelas dalam non-statis, maka Anda mungkin perlu memikirkan kembali desain Anda.
Outer.Inner i = new Outer().new Inner();
Juga, kelas batin yang diperbolehkan untuk menyatakan statis konstanta menurut JLS §15.28.
Outer.Inner.staticMethod()
seperti yang dapat Anda akses Outer.Inner.CONSTANT
. "Kamu tidak bisa mengakses ... instance kelas dalam non-statis tanpa melalui instance kelas luar." Mengapa Anda membutuhkan contoh? Anda tidak perlu instance Outer
untuk menelepon Outer.staticMethod()
. Saya tahu ini nitpicky tapi maksud saya adalah tidak masuk akal untuk membingkai jawaban Anda dengan cara ini. IMHO, perancang bahasa bisa mengizinkannya jika mereka mau.
Outer.Inner.CONSTANT
dan Outer.Inner.staticMethod()
adalah bahwa referensi ke konstanta tidak memiliki kesempatan untuk secara implisit merujuk pada instance Outer
yang Inner
dipakai. Semua referensi untuk Outer.staticMethod()
berbagi keadaan yang persis sama. Semua referensi untuk Outer.Inner.CONSTANT
berbagi keadaan yang persis sama. Namun, referensi Outer.Inner.staticMethod()
tidak jelas: Status "statis" tidak sepenuhnya statis, karena referensi implisit ke kelas luar di setiap instance dari Inner
. Tidak ada cara yang benar-benar jelas dan statis untuk mengaksesnya.
Outer.this
. Saya setuju dengan perancang bahasa Jawa bahwa tidak ada alasan untuk mengizinkan metode statis atau bidang statis non-final di kelas dalam, karena semua yang ada di kelas dalam harus berada dalam konteks kelas penutup.
Saya punya teori, yang mungkin atau mungkin tidak benar.
Pertama, Anda harus tahu beberapa hal tentang bagaimana kelas batin diterapkan di Jawa. Misalkan Anda memiliki kelas ini:
class Outer {
private int foo = 0;
class Inner implements Runnable {
public void run(){ foo++; }
}
public Runnable newFooIncrementer(){ return new Inner(); }
}
Ketika Anda mengompilasinya, bytecode yang dihasilkan akan terlihat seolah-olah Anda menulis sesuatu seperti ini:
class Outer {
private int foo = 0;
static class Inner implements Runnable {
private final Outer this$0;
public Inner(Outer outer){
this$0 = outer;
}
public void run(){ this$0.foo++; }
}
public Runnable newFooIncrementer(){ return new Inner(this); }
}
Sekarang, jika kami mengizinkan metode statis di kelas dalam non-statis, Anda mungkin ingin melakukan sesuatu seperti ini.
class Outer {
private int foo = 0;
class Inner {
public static void incrFoo(){ foo++; }
}
}
... yang terlihat cukup masuk akal, karena Inner
kelas tampaknya memiliki satu inkarnasi per Outer
instance. Tetapi seperti yang kita lihat di atas, kelas-kelas dalam non-statis benar-benar hanya gula sintaksis untuk kelas-kelas "dalam" statis, sehingga contoh terakhir kira-kira setara dengan:
class Outer {
private int foo = 0;
static class Inner {
private final Outer this$0;
public Inner(Outer outer){
this$0 = outer;
}
public static void incrFoo(){ this$0.foo++; }
}
}
... yang jelas tidak akan berfungsi, karena this$0
tidak statis. Jenis penjelasan ini menjelaskan mengapa metode statis tidak diizinkan (walaupun Anda dapat membuat argumen bahwa Anda dapat mengizinkan metode statis selama mereka tidak merujuk objek yang melampirkan), dan mengapa Anda tidak dapat memiliki bidang statis non-final ( itu akan menjadi kontra-intuitif jika instance kelas dalam non-statis dari objek yang berbeda berbagi "keadaan statis"). Ini juga menjelaskan mengapa bidang akhir yang diperbolehkan (selama mereka tidak referensi objek melampirkan).
public static double sinDeg(double theta) { ... }
kelas utilitas matematika dalam?
Satu-satunya alasan adalah "bukan keharusan", jadi mengapa repot-repot mendukungnya?
Secara sintaksis, tidak ada alasan untuk melarang kelas dalam memiliki anggota statis. Meskipun turunan Inner
terkait dengan turunan Outer
, masih mungkin digunakan Outer.Inner.myStatic
untuk merujuk anggota statis Inner
jika java memutuskan untuk melakukannya.
Jika Anda perlu membagikan sesuatu di antara semua contoh Inner
, Anda dapat menjadikannya Outer
sebagai anggota statis. Ini tidak lebih buruk daripada Anda menggunakan anggota statis Inner
, di mana Outer
masih dapat mengakses anggota pribadiInner
(tidak meningkatkan enkapsulasi).
Jika Anda perlu berbagi sesuatu di antara semua contoh yang Inner
dibuat oleh satu outer
objek, lebih masuk akal untuk memasukkannya ke dalamOuter
kelas sebagai anggota biasa.
Saya tidak setuju pendapat bahwa "kelas bersarang statis cukup banyak hanya kelas tingkat atas". Saya pikir lebih baik untuk benar-benar menganggap kelas bertingkat statis / kelas dalam sebagai bagian dari kelas luar, karena mereka dapat mengakses anggota pribadi kelas luar. Dan anggota kelas luar adalah "anggota kelas dalam" juga. Jadi tidak perlu mendukung anggota statis di kelas dalam. Anggota biasa / statis di kelas luar akan cukup.
Dari: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Seperti halnya metode instan dan variabel, kelas dalam dikaitkan dengan turunan dari kelas penutupnya dan memiliki akses langsung ke metode dan bidang objek itu. Juga, karena kelas dalam dikaitkan dengan sebuah instance, itu tidak dapat mendefinisikan anggota statis itu sendiri.
Penjelasan Oracle dangkal dan handwavy. Karena tidak ada alasan teknis atau sintaksis untuk mendahului anggota statis dalam kelas dalam (diizinkan dalam bahasa lain seperti C #), motivasi desainer Java kemungkinan besar adalah rasa konseptual dan / atau masalah kenyamanan teknis.
Inilah spekulasi saya:
Tidak seperti kelas tingkat atas, kelas dalam bergantung pada instance: instance kelas dalam dikaitkan dengan instance dari setiap kelas luarnya dan memiliki akses langsung ke anggota mereka. Ini adalah motivasi utama untuk memilikinya di Jawa. Dinyatakan dengan cara lain: kelas dalam dimaksudkan untuk instantiasi dalam konteks instance kelas luar. Tanpa instance kelas luar, kelas dalam seharusnya tidak lebih berguna daripada anggota instance kelas luar lainnya. Mari kita lihat ini sebagai semangat kelas batin yang bergantung pada instance .
Sifat anggota statis (yang TIDAK berorientasi objek) bentrok dengan instance-dependent semangat dari kelas dalam (yang IS berorientasi objek) karena Anda dapat mereferensikan / memanggil anggota statis dari kelas dalam tanpa instance kelas luar oleh menggunakan nama kelas batin yang berkualitas.
Variabel statis khususnya dapat menyinggung dengan cara lain: dua contoh kelas batin yang terkait dengan contoh berbeda dari kelas luar akan berbagi variabel statis. Karena variabel adalah komponen dari keadaan, kedua instance kelas dalam akan, pada dasarnya, berbagi status secara independen dari instance kelas luar yang terkait dengannya. Bukan berarti tidak dapat diterima bahwa variabel statis bekerja dengan cara ini (kami menerimanya di Jawa sebagai kompromi yang masuk akal untuk kemurnian OOP), tetapi bisa dibilang ada pelanggaran yang lebih dalam yang bisa terjadi dengan mengizinkan mereka di kelas dalam yang instansinya sudah digabungkan dengan instance kelas luar dengan desain. Melarang anggota statis di dalam kelas batin yang mendukung semangat bergantung pada instance akan menuai bonus tambahan untuk mencegah pelanggaran OOP yang lebih dalam ini.
Di sisi lain, tidak ada pelanggaran seperti itu yang disyaratkan oleh konstanta statis, yang tidak secara bermakna membentuk keadaan dan karenanya ini diperbolehkan. Mengapa tidak melarang konstanta statis untuk konsistensi maksimum dengan semangat instance-dependent ? Mungkin karena konstanta tidak perlu mengambil lebih banyak memori daripada yang diperlukan (jika mereka dipaksa non-statis maka mereka disalin ke setiap instance kelas batin yang berpotensi boros). Kalau tidak, saya tidak bisa membayangkan alasan pengecualian.
Ini mungkin bukan alasan yang kuat tapi IMO itu membuat paling masuk akal dari komentar sepintas Oracle tentang masalah ini.
Jawaban singkat: Model mental yang dimiliki sebagian besar programmer tentang bagaimana ruang lingkup bekerja bukanlah model yang digunakan oleh javac. Mencocokkan model yang lebih intuitif akan membutuhkan perubahan besar pada cara kerja javac.
Alasan utama yang diinginkan anggota statis di kelas dalam adalah untuk kebersihan kode - anggota statis yang hanya digunakan oleh kelas batin harus tinggal di dalamnya, daripada harus ditempatkan di kelas luar. Mempertimbangkan:
class Outer {
int outID;
class Inner {
static int nextID;
int id = nextID++;
String getID() {
return outID + ":" + id;
}
}
}
Pertimbangkan apa yang sedang terjadi di getID () ketika saya menggunakan pengidentifikasi tanpa pengecualian "outID". Ruang lingkup di mana pengenal ini muncul terlihat seperti:
Outer -> Inner -> getID()
Di sini, sekali lagi karena ini adalah cara kerja javac, level "Outer" dari lingkup mencakup anggota statis dan instance dari Outer. Ini membingungkan karena kita biasanya disuruh berpikir bagian statis dari kelas sebagai tingkat lain dari ruang lingkup:
Outer static -> Outer instance -> instanceMethod()
\----> staticMethod()
Dengan cara berpikir seperti ini, tentu saja staticMethod () hanya dapat melihat anggota statis Outer. Tetapi jika itu adalah cara javac bekerja, maka referensi variabel instan dalam metode statis akan menghasilkan kesalahan "nama tidak dapat diselesaikan". Apa yang sebenarnya terjadi adalah bahwa nama tersebut ditemukan dalam lingkup, tetapi kemudian tingkat tambahan dari pemeriksaan muncul dan mengetahui bahwa nama tersebut dinyatakan dalam konteks instance dan sedang direferensikan dari konteks statis.
OK, bagaimana hubungannya dengan kelas batin? Secara naif, kami pikir tidak ada alasan kelas dalam tidak dapat memiliki cakupan statis, karena kami membayangkan lingkup berfungsi seperti ini:
Outer static -> Outer instance -> Inner instance -> getID()
\------ Inner static ------^
Dengan kata lain, deklarasi statis di kelas dalam dan deklarasi instance di kelas luar sama-sama berada dalam ruang lingkup dalam konteks instance dari kelas dalam, tetapi tak satu pun dari ini sebenarnya bersarang di yang lain; keduanya malah bersarang di lingkup statis Outer.
Itu bukan cara javac bekerja - ada satu tingkat ruang lingkup untuk anggota statis dan instan, dan ruang lingkup selalu benar-benar sarang. Bahkan pewarisan diimplementasikan dengan menyalin deklarasi ke dalam subclass daripada bercabang dan mencari lingkup superclass.
Untuk mendukung anggota statis dari kelas dalam, javac harus memecah lingkup statis dan instance dan mendukung percabangan dan bergabung kembali dengan hierarki lingkup, atau harus memperluas ide "konteks statis" boolean sederhana untuk mengubah untuk melacak jenis konteks di semua tingkatan kelas bersarang dalam lingkup saat ini.
Mengapa kita tidak dapat memiliki metode statis di kelas batin non-statis?
Catatan: Kelas bersarang non-statis dikenal sebagai kelas dalam sehingga Anda tidak memilikinya non-static inner class
.
Instance kelas dalam tidak memiliki keberadaan tanpa instance kelas luar yang sesuai. Kelas dalam tidak dapat mendeklarasikan anggota statis selain mengkompilasi konstanta waktu. Jika diizinkan maka akan ada ambiguitas tentang makna static
. Dalam hal ini akan ada kebingungan tertentu:
Itulah sebabnya para desainer mungkin mengambil keputusan untuk tidak menangani masalah ini sama sekali.
Jika saya membuat kelas dalam statis itu berfungsi. Mengapa
Sekali lagi Anda tidak dapat membuat kelas dalam statis daripada Anda dapat mendeklarasikan kelas statis sebagai bersarang. Dalam hal ini kelas bertingkat ini sebenarnya adalah bagian dari kelas luar dan dapat memiliki anggota statis tanpa masalah.
Topik ini telah menarik perhatian banyak orang, masih akan saya coba jelaskan dalam istilah yang paling sederhana.
Pertama, dengan merujuk ke http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 , kelas atau antarmuka diinisialisasi segera sebelum kejadian / doa pertama dari setiap anggota yang didahului oleh kata kunci statis.
Jadi, jika kita memasang dengan anggota statis di dalam kelas batin, itu akan mengarah ke inisialisasi kelas batin, belum tentu kelas luar / penutup. Jadi, kami menghambat urutan inisialisasi kelas.
Juga pertimbangkan fakta bahwa kelas dalam non-statis dikaitkan dengan turunan dari kelas penutup / luar. Jadi, mengasosiasikan dengan instance akan berarti, bahwa kelas dalam akan ada di dalam instance kelas luar dan akan berbeda di antara instance.
Menyederhanakan intinya, untuk mengakses anggota statis kita memerlukan turunan dari kelas luar, dari mana kita perlu membuat turunan dari kelas dalam yang tidak statis. Anggota statis tidak seharusnya terikat pada instance dan karenanya Anda menerima kesalahan kompilasi.
Kelas dalam adalah sesuatu yang sama sekali berbeda dari kelas bersarang statis meskipun keduanya sama dalam sintaksis. Kelas bersarang statis hanyalah sarana untuk pengelompokan sedangkan kelas batin memiliki asosiasi yang kuat - dan akses ke semua nilai - kelas luarnya. Anda harus yakin mengapa Anda ingin menggunakan kelas dalam dan kemudian itu akan menjadi sangat alami mana yang harus Anda gunakan. Jika Anda perlu mendeklarasikan metode statis itu mungkin kelas bersarang statis yang Anda inginkan.
misalkan ada dua contoh dari kelas luar & mereka berdua memiliki kelas batin instantiated. Sekarang jika kelas dalam memiliki satu anggota statis maka itu akan menyimpan hanya satu salinan dari anggota itu di daerah tumpukan. Dalam hal ini kedua objek dari kelas luar akan merujuk ke ini salinan tunggal & mereka dapat mengubahnya bersama-sama. Ini dapat menyebabkan situasi "Kotor dibaca" maka untuk mencegah Java ini telah menerapkan pembatasan ini. Poin kuat lainnya untuk mendukung argumen ini adalah bahwa java memungkinkan anggota statis akhir di sini, mereka yang nilainya tidak dapat diubah dari salah satu objek kelas luar. Tolong, biarkan saya jika saya salah.
Pertama-tama mengapa seseorang ingin mendefinisikan anggota statis di kelas batin non-statis? jawabannya adalah, sehingga anggota kelas luar dapat menggunakan anggota statis itu dengan nama kelas dalam saja, bukan?
Tetapi untuk kasus ini kita dapat secara langsung mendefinisikan anggota di kelas luar. yang akan dikaitkan dengan semua objek kelas dalam, dalam instance kelas luar.
seperti kode di bawah ini,
public class Outer {
class Inner {
public static void method() {
}
}
}
dapat ditulis seperti ini
public class Outer {
void method() {
}
class Inner {
}
}
Jadi menurut saya untuk tidak menyulitkan kode desainer java tidak memungkinkan fungsi ini atau kita dapat melihat fungsi ini dalam rilis mendatang dengan beberapa fitur lainnya.
Cobalah untuk memperlakukan kelas sebagai bidang normal, maka Anda akan mengerti.
//something must be static. Suppose something is an inner class, then it has static keyword which means it's a static class
Outer.something
Tidak ada gunanya memiliki anggota kelas dalam sebagai statis karena Anda tidak akan dapat mengaksesnya sejak awal.
Pikirkan tentang ini, untuk mengakses anggota statis yang Anda gunakan className.memberName ,, dalam kasus kami, itu harus berupa outerclassName.innerclassName.memberName ,,, sekarang apakah Anda melihat mengapa innerclass harus statis ....