Java: memanggil metode yang dilindungi kelas super dari subkelas - tidak terlihat?

Saya memanggil metode yang dilindungi kelas super dari subkelas. Mengapa metode ini "tidak terlihat"?

Saya telah membaca beberapa postingan seperti yang ini, sepertinya bertentangan dengan hal-hal berikut:

Kelas super:

package com.first;

public class Base
{
    protected void sayHello()
    {
        System.out.println("hi!");
    }
}

Subkelas:

package com.second;

import com.first.Base;

public class BaseChild extends Base
{
    Base base = new Base();

    @Override
    protected void sayHello()
    {
        super.sayHello(); //OK :)
        base.sayHello(); //Hmmm... "The method sayHello() from the type Base is not visible" ?!?
    }   
}

person rapt    schedule 24.03.2016    source sumber
comment
stackoverflow.com/a/19949354/868975   -  person Bax    schedule 24.03.2016
comment
Mungkin sama seperti ini: stackoverflow.com/questions/36093187/   -  person aioobe    schedule 24.03.2016


Jawaban (3)


base adalah variabel yang tidak istimewa dalam hal apa pun: variabel tersebut bukan bagian dari hierarki kelas dan akses yang dilindungi tidak tersedia melaluinya. Meskipun sayHello memiliki akses ke anggota Base yang dilindungi, ia hanya memiliki akses tersebut melalui pewarisan (karena tidak berada dalam paket yang sama: kata kunci protected mengizinkan akses melalui pewarisan dan paket, lihat tabel di tutorial Oracle ini).

Akses melalui this dan super diperbolehkan karena keduanya merupakan bagian dari hierarki warisan.

person Paul Hicks    schedule 24.03.2016
comment
Saya pikir Anda adalah satu-satunya di sini yang memperhatikan bahwa base hanyalah sebuah variabel. - person Scary Wombat; 24.03.2016
comment
Saya rasa saya memerlukan terminologi yang lebih baik.. Saya tahu apa yang ingin saya katakan, tetapi saya rasa ada istilah yang lebih diterima di luar sana yang saat ini saya tidak dapat mengingatnya.. - person Paul Hicks; 24.03.2016
comment
Ini masih mengejutkan, karena Anda dapat memanggil metode privat pada instance mana pun dari kelas yang dideklarasikan saat ini (this dan instance apa pun selain this). Kode berikut berfungsi: public class A { private void b() { new A().b(); }} - person Stefan Dollase; 24.03.2016
comment
@StefanDollase, itu ada di dalam A. Tentu saja, metode pribadi A tersedia untuk A. - person ChiefTwoPencils; 24.03.2016
comment
@ChiefTwoPencils Ya, tetapi argumennya masih sama: Jawabannya mengatakan tidak berfungsi, karena hierarki warisannya sama tetapi bukan instance yang sama. Saya menunjukkan bahwa dalam kasus pengubah private, cukup berada dalam hierarki warisan yang sama (hanya terdiri dari tipe itu sendiri). Untuk private, tidak masalah apakah itu instance yang sama. Saya hanya menunjukkan bahwa saya terkejut dengan perilaku yang berbeda. - person Stefan Dollase; 24.03.2016
comment
Bedanya, kelasnya sama. Tidak ada subkelas yang terlibat. Lihat kutipan dasblinkenlight untuk detail lebih spesifik. - person Paul Hicks; 24.03.2016
comment
@StefanDollase, saya membacanya secara berbeda. Kedengarannya benar dan tidak sama dengan contoh Anda. Perbedaan utamanya adalah OP mencoba menggunakan instance dari induknya seolah-olah itu this. Kalau di kelas lain ya, itu akan sangat mengejutkan. - person ChiefTwoPencils; 24.03.2016
comment
Untuk memperjelas: Saya tidak terkejut dengan perilaku private tetapi dengan perilaku protected. Saya berharap pengubah protected memiliki perilaku yang sama seperti private sehubungan dengan situasi yang dijelaskan di atas. Namun sepertinya hanya saya saja yang terkejut, jadi sudahlah :-P - person Stefan Dollase; 24.03.2016
comment
@ChiefTwoPencils Tapi bagaimana Anda mengakses barang-barang pribadi di kelas lain? Saya setuju dengan Stefan Dollase bahwa ini agak tidak konsisten. - person rapt; 24.03.2016
comment
@rapt, desainnya tidak konsisten. Anda tidak mengakses hal-hal pribadi (secara langsung atau tanpa sihir) di kelas lain baik yang diwarisi atau tidak; itu tidak akan bersifat pribadi kalau begitu. Jika cara kerjanya bertentangan dengan desain Anda, mungkin desain tersebut memerlukan pemikiran lebih lanjut. - person ChiefTwoPencils; 24.03.2016
comment
@ChiefTwoPencils Saya tidak berbicara tentang mengakses barang-barang pribadi dari tipe lain. Saya pikir Anda masih melewatkan maksud saya: Untuk private Anda harus berada di kelas deklarasi yang sama tetapi Anda dapat menggunakan private hal dari instance lain selain this. Untuk protected Anda harus berada dalam hierarki kelas yang sama dengan kelas yang mendeklarasikan dan Anda hanya dapat menggunakan protected barang dari this. - person Stefan Dollase; 24.03.2016
comment
@StefanDollase, maaf, saya mengerti apa yang Anda katakan tetapi gagal memahami apa yang mengejutkan darinya. Bahkan jika Anda memiliki kelas lain, Anda masih berada di kelas yang sama. Meskipun hal tersebut mungkin tampak tidak konsisten, dan mungkin, menurut definisinya, hal tersebut sangat masuk akal (bagi saya). Selain berada di dalam kelas yang memastikan tidak ada privasi yang dilanggar, beberapa hal seperti definisi rekursif mungkin tidak mungkin atau sulit dilakukan. Bayangkan BinaryTreeNode yang tidak memiliki akses ke barang pribadi yang disimpan oleh referensinya. Itu akan mengejutkan bagi saya. Semua pendapat :) - person ChiefTwoPencils; 24.03.2016
comment
@ChiefTwoPencils Seperti yang saya katakan, saya tidak terkejut dengan perilaku pribadi tetapi dengan perilaku dilindungi. Jadi pertanyaannya bukan kenapa boleh untuk privat tapi kenapa tidak boleh untuk dilindungi. Mari kita transfer contoh algoritma Anda yang menggunakan metode privat pada instance selain this ke versi yang dilindungi: Mengapa saya tidak dapat mengimplementasikan algoritma yang menggunakan metode yang dilindungi dari hierarki warisan saat ini tetapi pada instance lain selain this? Mengapa saya tidak dapat mengakses metode yang dilindungi dari kelas induk dari node anak di BinaryTreeNode? - person Stefan Dollase; 24.03.2016
comment
@ChiefTwoPencils Saya akan menghentikan ini di sini, karena ini adalah topik untuk pertanyaan lain. Bersulang! - person Stefan Dollase; 24.03.2016
comment
@Stefan, sebagai catatan, saya sedang menggunakan ponsel saya dan melewatkan komentar klarifikasi Anda. Maaf, sampai waktu berikutnya... - person ChiefTwoPencils; 24.03.2016

Ini adalah perilaku yang benar. Faktanya, Spesifikasi Bahasa Java, bagian , 6.6.2-1, memiliki contoh yang sangat mirip dengan contoh Anda, dengan komentar yang tidak boleh dikompilasi.

Rincian akses anggota yang dilindungi dirinci di bagian 6.6.2.1:

6.6.2.1. Akses ke Anggota yang dilindungi

Misalkan C adalah kelas dimana anggota yang dilindungi dideklarasikan. Akses hanya diizinkan dalam badan subkelas S dari C.

Selain itu, jika Id menunjukkan bidang instans atau metode instans, maka:

Jika aksesnya menggunakan nama berkualifikasi Q.Id, dengan Q adalah NamaEkspresi, maka akses diperbolehkan jika dan hanya jika tipe ekspresi Q adalah S atau subkelas S.

Jika akses dilakukan dengan ekspresi akses bidang E.Id, dengan E adalah ekspresi Primer, atau dengan ekspresi pemanggilan metode E.Id(. . .), dengan E adalah ekspresi Primer, maka akses diizinkan jika dan hanya jika tipe E adalah S atau subkelas dari S.

Ini adalah paragraf terakhir yang menjelaskan mengapa akses harus ditolak. Dalam contoh Anda, C adalah Base, S adalah BaseChild, dan E, jenis variabel base, juga Base. Karena Base bukan merupakan BaseChild atau subkelas dari BaseChild, aksesnya ditolak.

person Sergey Kalinichenko    schedule 24.03.2016
comment
Meskipun saya memahami bahwa ini mencegah akses melalui base, saya tidak mengerti bagaimana hal ini mengizinkan akses melalui super. Bukankah super bertipe sama dengan base? Mungkin saya melewatkan sesuatu di JLS? Apakah diperbolehkan di bagian lain JLS? Saya tidak dapat menemukan bagian yang mengizinkannya. - person Stefan Dollase; 24.03.2016
comment
@StefanDollase Itu masalahnya, super bukan sebuah bidang, itu adalah kata kunci yang memungkinkan Anda mengakses metode kelas dasar yang diganti di kelas Anda. Namun sebenarnya referensi dilakukan melalui this, bukan melalui variabel lain. - person Sergey Kalinichenko; 24.03.2016

Keyboard dilindungi ditujukan untuk visibilitas pada paket yang sama. Jika kelas anak bukan dari paket yang sama, metode induk yang dilindungi tidak akan terlihat oleh kelas anak.

person Dust Francis    schedule 24.03.2016
comment
Untuk menjelaskan penilaian negatif: keyboard adalah perangkat untuk masuk karakter ke dalam komputer. protected adalah untuk visibilitas pada paket yang sama - dalam paket yang sama, tapi saya ngelantur. protected terutama digunakan untuk memberikan akses ke subkelas. Jika kelas anak bukan dari paket yang sama - dalam paket yang sama... metode induk yang dilindungi tidak terlihat oleh kelas anak. Tidak. Akses dari subkelas adalah inti dari protected. Yang Anda maksud mungkin adalah visibilitas default, yang termasuk dalam akses protected. - person Johannes Kuhn; 15.07.2018