"Saya akan memberitahu anda tentang « pengubah suai akses ». Saya pernah memberitahu tentangnya sebelum ini, tetapi pengulangan adalah tonggak pembelajaran."

Anda boleh mengawal akses (keterlihatan) yang ada pada kelas lain kepada kaedah dan pembolehubah kelas anda. Pengubah suai akses menjawab soalan «Siapa yang boleh mengakses kaedah/pembolehubah ini?». Anda boleh menentukan hanya satu pengubah suai untuk setiap kaedah atau pembolehubah.

1) pengubah suai « awam ».

Pembolehubah, kaedah atau kelas yang ditandakan dengan pengubah suai awam boleh diakses dari mana-mana sahaja dalam program. Ini adalah tahap keterbukaan tertinggi: tiada sekatan.

2) pengubah suai « persendirian ».

Pembolehubah, kaedah atau kelas yang ditandakan dengan pengubah suai persendirian hanya boleh diakses dalam kelas di mana ia diisytiharkan. Kaedah atau pembolehubah yang ditanda disembunyikan daripada semua kelas lain. Ini ialah tahap privasi tertinggi: hanya boleh diakses oleh kelas anda. Kaedah sedemikian tidak diwarisi dan tidak boleh ditimpa. Selain itu, mereka tidak boleh diakses dalam kelas keturunan.

3)  « Pengubah suai lalai».

Jika pembolehubah atau kaedah tidak ditandakan dengan mana-mana pengubah, maka ia dianggap ditandakan dengan pengubah "lalai". Pembolehubah dan kaedah dengan pengubah suai ini boleh dilihat oleh semua kelas dalam pakej di mana ia diisytiharkan, dan hanya kepada kelas tersebut. Pengubah suai ini juga dipanggil akses " pakej " atau " pakej peribadi ", membayangkan fakta bahawa akses kepada pembolehubah dan kaedah terbuka kepada keseluruhan pakej yang mengandungi kelas.

4) " dilindungi " pengubah suai.

Tahap akses ini lebih luas sedikit daripada pakej . Pembolehubah, kaedah atau kelas yang ditandakan dengan pengubah suai yang dilindungi boleh diakses daripada pakejnya (seperti "pakej") dan daripada semua kelas yang diwarisi.

Jadual ini menerangkan semuanya:

Jenis keterlihatan Kata kunci Akses
Kelas awak Pakej anda Keturunan Semua kelas
Persendirian persendirian ya Tidak Tidak Tidak
Pakej (tiada pengubah suai) ya ya Tidak Tidak
Dilindungi dilindungi ya ya ya Tidak
Awam awam ya ya ya ya

Terdapat cara untuk mengingati jadual ini dengan mudah. Bayangkan anda sedang menulis surat wasiat. Anda membahagikan semua perkara anda kepada empat kategori. Siapa yang boleh menggunakan barang anda?

Siapa yang mempunyai akses Pengubah suai Contoh
Hanya  saya persendirian Jurnal peribadi
Keluarga (tiada pengubah suai) Foto keluarga
Keluarga dan waris dilindungi Harta pusaka keluarga
Semua orang awam Kenangan

"Ia sama seperti membayangkan bahawa kelas dalam pakej yang sama adalah sebahagian daripada satu keluarga."

"Saya juga ingin memberitahu anda beberapa nuansa menarik tentang kaedah mengatasi."

1) Pelaksanaan tersirat kaedah abstrak.

Katakan anda mempunyai kod berikut:

Kod
class Cat
{
 public String getName()
 {
  return "Oscar";
 }
}

Dan anda memutuskan untuk mencipta kelas Tiger yang mewarisi kelas ini dan menambah antara muka pada kelas baharu

Kod
class Cat
{
 public String getName()
 {
   return "Oscar";
 }
}
interface HasName
{
 String getName();
 int getWeight();
}
class Tiger extends Cat implements HasName
{
 public int getWeight()
 {
  return 115;
 }

}

Jika anda hanya melaksanakan semua kaedah yang hilang yang IntelliJ IDEA memberitahu anda untuk melaksanakan, kemudian anda mungkin menghabiskan masa yang lama mencari pepijat.

Ternyata kelas Tiger mempunyai kaedah getName yang diwarisi daripada Cat, yang akan diambil sebagai pelaksanaan kaedah getName untuk antara muka HasName.

"Saya tidak nampak apa-apa yang mengerikan tentang itu."

"Ia tidak terlalu teruk, ia adalah tempat yang mungkin berlaku untuk kesilapan."

Tetapi ia boleh menjadi lebih teruk lagi:

Kod
interface HasWeight
{
 int getValue();
}
interface HasSize
{
 int getValue();
}
class Tiger extends Cat implements HasWeight, HasSize
{
 public int getValue()
 {
  return 115;
 }
}

Ternyata anda tidak selalu boleh mewarisi daripada berbilang antara muka. Lebih tepat lagi, anda boleh mewarisinya, tetapi anda tidak boleh melaksanakannya dengan betul. Tengok contoh. Kedua-dua antara muka memerlukan anda melaksanakan kaedah getValue(), tetapi tidak jelas apa yang harus dikembalikan: berat atau saiz? Perkara ini agak tidak menyenangkan untuk dihadapi.

"Saya setuju. Anda ingin melaksanakan kaedah, tetapi anda tidak boleh. Anda telah mewarisi kaedah dengan nama yang sama dari kelas asas. Ia rosak."

"Tetapi ada berita baik."

2) Meluaskan penglihatan. Apabila anda mewarisi jenis, anda boleh mengembangkan keterlihatan kaedah. Begini rupanya:

kod Java Penerangan
class Cat
{
 protected String getName()
 {
  return "Oscar";
 }
}
class Tiger extends Cat
{
 public String getName()
 {
  return "Oscar Tiggerman";
 }
}
Kami telah mengembangkan keterlihatan kaedah daripada protectedkepada public.
Kod Mengapa ini "sah"
public static void main(String[] args)
{
 Cat cat = new Cat();
 cat.getName();
}
Semuanya hebat. Di sini kita tidak tahu bahawa keterlihatan telah dilanjutkan dalam kelas keturunan.
public static void main(String[] args)
{
 Tiger tiger = new Tiger();
 tiger.getName();
}
Di sini kita memanggil kaedah yang keterlihatan telah dilanjutkan.

Jika ini tidak mungkin, kami sentiasa boleh mengisytiharkan kaedah dalam Tiger:
public String getPublicName()
{
super.getName(); //panggil kaedah yang dilindungi
}

Dalam erti kata lain, kami tidak bercakap tentang sebarang pelanggaran keselamatan.

public static void main(String[] args)
{
 Cat catTiger = new Tiger();
 catTiger.getName();
}
Sekiranya semua syarat yang diperlukan untuk memanggil kaedah dalam kelas asas ( Cat ) dipenuhi, maka mereka pasti berpuas hati untuk memanggil kaedah pada jenis keturunan ( Harimau ) . Kerana sekatan pada panggilan kaedah adalah lemah, tidak kuat.

"Saya tidak pasti saya faham sepenuhnya, tetapi saya akan ingat bahawa ini mungkin."

3) Menyempitkan jenis pulangan.

Dalam kaedah yang diganti, kita boleh menukar jenis pulangan kepada jenis rujukan yang disempitkan.

kod Java Penerangan
class Cat
{
 public Cat parent;
 public Cat getMyParent()
 {
  return this.parent;
 }
 public void setMyParent(Cat cat)
 {
  this.parent = cat;
 }
}
class Tiger extends Cat
{
 public Tiger getMyParent()
 {
  return (Tiger) this.parent;
 }
}
Kami mengatasi kaedah getMyParent, dan kini ia mengembalikan Tigerobjek.
Kod Mengapa ini "sah"
public static void main(String[] args)
{
 Cat parent = new Cat();

 Cat me = new Cat();
 me.setMyParent(parent);
 Cat myParent = me.getMyParent();
}
Semuanya hebat. Di sini kita tidak tahu bahawa jenis pulangan kaedah getMyParent telah diluaskan dalam kelas keturunan.

Bagaimana «kod lama» berfungsi dan berfungsi.

public static void main(String[] args)
{
 Tiger parent = new Tiger();

 Tiger me = new Tiger();
 me.setMyParent(parent);
 Tiger myParent = me.getMyParent();
}
Di sini kita panggil kaedah yang jenis pulangannya telah disempitkan.

Jika ini tidak mungkin, kami sentiasa boleh mengisytiharkan kaedah dalam Tiger:
public Tiger getMyTigerParent()
{
return (Tiger) this.parent;
}

Dalam erti kata lain, tiada pelanggaran keselamatan dan/atau jenis pelanggaran pemutus.

public static void main(String[] args)
{
 Tiger parent = new Tiger();

 Cat me = new Tiger();
 me.setMyParent(parent);
 Cat myParent = me.getMyParent();
}
Dan semuanya berfungsi dengan baik di sini, walaupun kami meluaskan jenis pembolehubah kepada kelas asas (Cat).

Kerana mengatasi, kaedah setMyParent yang betul dipanggil.

Dan tiada apa yang perlu dibimbangkan apabila memanggil kaedah getMyParent , kerana nilai pulangan, walaupun kelas Tiger, masih boleh diberikan kepada pembolehubah myParent bagi kelas asas (Cat) tanpa sebarang masalah.

Objek harimau boleh disimpan dengan selamat dalam kedua-dua pembolehubah Harimau dan pembolehubah Cat.

"Ya. Faham. Apabila mengatasi kaedah, anda perlu mengetahui cara semua ini berfungsi jika kita menghantar objek kita kepada kod yang hanya boleh mengendalikan kelas asas dan tidak tahu apa-apa tentang kelas kita. "

"Tepat sekali! Kemudian persoalan besarnya ialah mengapa kita tidak boleh mengecilkan jenis nilai pulangan apabila mengatasi kaedah?"

"Sudah jelas bahawa dalam kes ini kod dalam kelas asas akan berhenti berfungsi:"

kod Java Penjelasan masalah
class Cat
{
 public Cat parent;
 public Cat getMyParent()
 {
  return this.parent;
 }
 public void setMyParent(Cat cat)
 {
  this.parent = cat;
 }
}
class Tiger extends Cat
{
 public Object getMyParent()
 {
  if (this.parent != null)
   return this.parent;
  else
   return "I'm an orphan";
 }
}
Kami membebankan kaedah getMyParent dan mengecilkan jenis nilai pulangannya.

Semuanya baik-baik saja di sini.

public static void main(String[] args)
{
 Tiger parent = new Tiger();

 Cat me = new Tiger();
 Cat myParent = me.getMyParent();
}
Kemudian kod ini akan berhenti berfungsi.

Kaedah getMyParent boleh mengembalikan sebarang contoh Objek, kerana ia sebenarnya dipanggil pada objek Harimau.

Dan kami tidak mempunyai cek sebelum tugasan. Oleh itu, kemungkinan besar pembolehubah myParent jenis Cat akan menyimpan rujukan String.

"Contoh yang bagus, Amigo!"

Di Jawa, sebelum kaedah dipanggil, tiada pemeriksaan sama ada objek itu mempunyai kaedah sedemikian. Semua semakan berlaku pada masa jalan. Dan panggilan [hipotesis] kepada kaedah yang hilang kemungkinan besar akan menyebabkan program cuba untuk melaksanakan kod bait yang tidak wujud. Ini akhirnya akan membawa kepada ralat maut, dan sistem pengendalian akan menutup program secara paksa.

"Wah. Sekarang saya tahu."