public class SuperClass
{
public void method1()
{
System.out.println("superclass method1");
this.method2();
}
public void method2()
{
System.out.println("superclass method2");
}
}
public class SubClass extends SuperClass
{
@Override
public void method1()
{
System.out.println("subclass method1");
super.method1();
}
@Override
public void method2()
{
System.out.println("subclass method2");
}
}
public class Demo
{
public static void main(String[] args)
{
SubClass mSubClass = new SubClass();
mSubClass.method1();
}
}
keluaran yang saya harapkan:
subclass method1
superclass method1
superclass method2
keluaran sebenarnya:
subclass method1
superclass method1
subclass method2
Saya tahu secara teknis saya telah mengganti metode publik, tetapi saya pikir karena saya memanggil super, panggilan apa pun di dalam super akan tetap di super, ini tidak terjadi. Ada ide bagaimana saya bisa mewujudkannya?
java
inheritance
overriding
super
jsonfry.dll
sumber
sumber
Jawaban:
Kata kunci
super
tidak "melekat". Setiap pemanggilan metode ditangani secara individual, jadi meskipun Anda harus melakukannyaSuperClass.method1()
dengan memanggilsuper
, itu tidak memengaruhi pemanggilan metode lain yang mungkin Anda lakukan di masa mendatang.Itu berarti tidak ada cara langsung untuk memanggil
SuperClass.method2()
dariSuperClass.method1()
tanpa meskipunSubClass.method2()
kecuali Anda bekerja dengan sebuah contoh aktualSuperClass
.Anda bahkan tidak dapat mencapai efek yang diinginkan dengan menggunakan Refleksi (lihat dokumentasi
java.lang.reflect.Method.invoke(Object, Object...)
).[EDIT] Sepertinya masih ada kebingungan. Izinkan saya mencoba penjelasan yang berbeda.
Saat Anda memohon
foo()
, Anda benar-benar memohonthis.foo()
. Java hanya memungkinkan Anda menghilangkanthis
. Dalam contoh di pertanyaan, tipe darithis
adalahSubClass
.Jadi, ketika Java mengeksekusi kode tersebut
SuperClass.method1()
, kode itu akhirnya tiba dithis.method2();
Menggunakan
super
tidak mengubah contoh yang ditunjukkan olehthis
. Jadi panggilan masuk keSubClass.method2()
karenathis
adalah tipeSubClass
.Mungkin lebih mudah untuk dipahami ketika Anda membayangkan bahwa Java lolos
this
sebagai parameter pertama yang tersembunyi:Jika Anda mengikuti stack panggilan, Anda dapat melihat bahwa
this
tidak pernah berubah, itu selalu instance yang dibuatmain()
.sumber
super
. Setiap kali memanggil metode, ia akan melihat jenis instans, dan mulai mencari metode dengan jenis ini, tidak peduli seberapa sering Anda memanggilsuper
. Jadi, saat Anda memanggilmethod2
sebuah instanceSubClass
, itu akan selalu melihat yangSubClass
pertama.super
tidak mengubah contoh. Itu tidak menyetel beberapa bidang tersembunyi "mulai sekarang, semua panggilan metode harus mulai menggunakanSuperClass
". Atau dengan kata lain: Nilaithis
tidak berubah.Anda hanya dapat mengakses metode yang diganti dalam metode penggantian (atau dalam metode lain dari kelas penggantian).
Jadi: jangan timpa
method2()
atau panggilsuper.method2()
di dalam versi yang diganti.sumber
Anda menggunakan
this
kata kunci yang sebenarnya merujuk pada "instance yang sedang berjalan dari objek yang Anda gunakan", yaitu, Anda memanggilthis.method2();
superclass Anda, yang akan memanggil method2 () pada objek yang Anda ' menggunakan kembali, yang merupakan SubClass.sumber
this
juga tidak akan membantu. Doa yang tidak memenuhi syarat secara implisit menggunakanthis
method2()
kompilator akan melihatthis.method2()
. Jadi meskipun Anda menghapusnyathis
tetap tidak akan berfungsi. Apa yang dikatakan @Sean Patrick Floyd benarthis
this
mengacu pada "kelas contoh berjalan beton" (dikenal dalam runtime) dan bukan (seperti yang tampaknya diyakini poster) ke "kelas unit kompilasi saat ini" (di mana kata kunci digunakan, dikenal di waktu kompilasi). Tapi itu juga bisa menyesatkan (seperti yang dikatakan Shervin):this
juga direferensikan secara implisit dengan pemanggilan metode biasa;method2();
adalah sama denganthis.method2();
Saya memikirkannya seperti ini
Biarkan saya memindahkan subclass itu sedikit ke kiri untuk mengungkapkan apa yang ada di bawah ... (Sobat, saya suka grafik ASCII)
Dengan kata lain, mengutip dari Spesifikasi Bahasa Jawa :
Dalam istilah awam,
this
pada dasarnya adalah sebuah objek (* objek **; objek yang sama yang dapat Anda pindahkan dalam variabel), instance dari kelas yang dipakai, variabel biasa dalam domain data;super
seperti penunjuk ke blok kode pinjaman yang ingin Anda jalankan, lebih seperti pemanggilan fungsi belaka, dan ini relatif terhadap kelas tempat pemanggilannya.Oleh karena itu jika Anda menggunakan
super
dari superclass Anda mendapatkan kode dari kelas superduper [the grandparent] dieksekusi), sedangkan jika Anda menggunakanthis
(atau jika digunakan secara implisit) dari superclass itu terus menunjuk ke subclass (karena tidak ada yang mengubahnya - dan tidak ada bisa).sumber
Jika Anda tidak ingin superClass.method1 memanggil subClass.method2, jadikan metode2 bersifat pribadi sehingga tidak dapat diganti.
Inilah sarannya:
Jika tidak berhasil seperti ini, polimorfisme tidak mungkin (atau setidaknya tidak setengah berguna).
sumber
Karena satu-satunya cara untuk menghindari metode untuk diganti adalah dengan menggunakan kata kunci super , saya telah berpikir untuk memindahkan method2 () dari SuperClass ke kelas Base baru lainnya dan kemudian memanggilnya dari SuperClass :
Keluaran:
sumber
this
selalu mengacu pada objek yang sedang dieksekusi.Untuk lebih mengilustrasikan poin di sini adalah sketsa sederhana:
Jika Anda memiliki contoh kotak luar, suatu
Subclass
objek, di mana pun Anda kebetulan menjelajah di dalam kotak, bahkan ke dalamSuperclass
'area', itu tetaplah contoh kotak luar.Terlebih lagi, dalam program ini hanya ada satu objek yang dibuat dari tiga kelas, jadi
this
hanya bisa merujuk ke satu hal dan itu adalah:seperti yang ditunjukkan di Netbeans 'Heap Walker'.
sumber
panggilan
keluaran
sumber
Saya tidak percaya Anda bisa melakukannya secara langsung. Salah satu solusinya adalah memiliki implementasi internal pribadi dari metode2 di superclass, dan memanggilnya. Sebagai contoh:
sumber
Kata kunci "ini" mengacu pada referensi kelas saat ini. Itu berarti, ketika digunakan di dalam metode, kelas 'saat ini' masih SubKelas dan jawabannya dijelaskan.
sumber
Untuk meringkas, ini menunjuk ke objek saat ini dan pemanggilan metode di java bersifat polimorfik. Jadi, pemilihan metode untuk eksekusi, sangat bergantung pada objek yang ditunjuk oleh ini. Oleh karena itu, memanggil metode method2 () dari kelas induk memanggil method2 () dari kelas anak, karena ini menunjuk ke objek kelas anak. Definisi ini tidak berubah, terlepas dari kelas mana pun itu digunakan.
PS. tidak seperti metode, variabel anggota kelas tidak polimorfik.
sumber
Selama penelitian saya untuk kasus serupa, saya telah mengakhiri dengan memeriksa pelacakan tumpukan dalam metode subclass untuk mencari tahu dari mana panggilan itu berasal. Mungkin ada cara yang lebih cerdas untuk melakukannya, tetapi itu berhasil bagi saya dan ini adalah pendekatan yang dinamis.
Saya pikir pertanyaan untuk mendapatkan solusi untuk kasus ini masuk akal. Tentu saja ada cara untuk menyelesaikan masalah dengan nama metode yang berbeda atau bahkan jenis parameter yang berbeda, seperti yang telah disebutkan di utas, tetapi dalam kasus saya, saya tidak suka bingung dengan nama metode yang berbeda.
sumber
Lebih jauh lagi, hasil yang lebih luas dari pertanyaan yang diajukan, ini akan memberikan lebih banyak wawasan tentang penentu akses dan perilaku penggantian.
sumber