Главная » Java » Полномочия доступа и переопределенные методы

0

 

Метод может быть переопределен в производном классе только в том случае,

если он доступен в базовом классе.  В противном случае метод, объявленный в

производном классе и обладающий той же сигнатурой, не будет считаться пере-

определенным.  При вызове  метода  во  время  работы  программы  исполняющая

система,   принимающая  решение  о  том,   какая   из  реализаций  метода  должна

быть использована, обязана учесть возможности доступа к методу.

 Попробуем пояснить сказанное с помощью следующего, в некоторой степени искусственного,     примера.    Предположим,    что    имеется    абстрактный    класс AbstractBase, объявленный в пакете P1: 

 

package P1;

public abstract class AbstractBase {

private    void pri O { print(“bstractBase.pri O");               }

               void pacO { print("AbstractBase.pac()");              }

protected      void  pro()   {  print("AbstractBase. proO") ;             }

public             void  pub()   {  printC’AbstractBase. pubO") ;            }

public  final   void  showO  {

priO;

pac();

pro() ;

pubO;

 }

}

В нашем распоряжении четыре метода с различными признаками доступа, и каждый из них просто обозначает себя, выводя на экран строку с собственным наименованием. Метод show вызывает каждый из указанных методов в контексте текущего объекта. Поскольку show объявлен как final, он не может быть переопределен. Метод show призван продемонстрировать, какая из реализаций каждого из методов — pri, рас, pro и pub — будет вызвана в применении к объектам производных (конкретных) классов.

   Определим класс concretel, расширяющий AbstractBase и принадлежащий другому пакету, Р2:

package  P2;

import P1.AbstractBase;

 

public  class  Concretel extends AbstractBase  {

   public  void  priО   {  print("Concretel.pri()");   }

   public void  рас О   {  pri nt("Concretel. pacO") ;            }

    public void  proO   {  pri nt("Concretel. proO") ;            }

    public void  pub()   {  pri nt("Concretel. pubO") ;}

}

Класс содержит переопределенные версии каждого из методов базового класса и изменяет их реализацию таким образом, чтобы они фиксировали свою принадлежность классу Concretel. Помимо того, изменению подвергаются модификаторы доступа методов — теперь все они обозначены как public, т.е. открыты для доступа из любого внешнего кода. При выполнении инструкции

   new ConcretelO . showO ;

на экран будут выведены следующие данные:

AbstractBase.pri()

AbstractBase.рас О

Concretel.pro()

Concretel.pub()

 

Приватный метод pri недоступен для производных классов (как и для кода л бого другого класса), и поэтому при обращении из show единственной альтернативой  будет  версия  метода,   предусмотренная  в  составе  AbstractBase.   Метод  рас класса AbstractBase, обладающий признаком доступа уровня пакета, предусмотренным по умолчанию, не доступен из Concretel, и реализация рас в Concretel не является переопределенной версией метода класса AbstractBase, а поэтому из show будет вызван метод AbstractBase. рас. Методы pro и pub класса AbstractBase доступны из Concretel и потому были успешно переопределены, так что из show вызываются именно те реализации, которые даны в Concretel.

  Далее мы определим класс Concrete2, производный от Concretel и размещенный в том же пакете Pi, где содержится базовый класс AbstractBase1:

package P1;

import  P2.Concrete l;  

public  class  Concrete2  extends  Concretel  {

public void  pri()   {  print("Concrete2.pri()");   }

public void  рас О   {  pri nt("Concrete2.рас()");}

public void  proO   {  print("Concrete2.proO");   }            

public void  pubO   {  print(MConcrete2.pubO");  }

}

Каждый из четырех методов класса Concrete2 является подлинно переопреде

ленной версией соответствующего метода класса Concretel, поскольку все они

обозначены как public и потому открыты для доступа. Помимо того, так как

Concrete2 расположен в том же пакете, что и AbstractBase, метод

AbstractBase. рас доступен в Concrete2 и поэтому переопределен посредством

Concrete2 . рас. При вызове show в контексте объекта класса Concrete2 будет

получен следующий результат:          

AbstractBase.pri()

 Concrete2.pac()

 Concrete2.pro()

 Concrete2.pub()

Наконец, объявим класс Concrete3, расширяющий Concrete2, но расположенный в ином пакете, РЗ:

package РЗ;

import  Pl.Concrete2;

public  class  Concrete3 extends  Concrete2  {

public void  pri()   {          print("concrete3.pri()");              }

public  void  pac()   {       print("Concrete3. pacO");           }

public  void  proO   {       print("Concrete3. proO") ;          }

public void  pub()   {       print("Concrete3 .pubO") ;         }

 

При вызове метода show применительно к объекту класса Concrete3 мы получим следующее:

AbstractBase.pri ()

Concrete3.pac()

Concrete3.pro()

Concrete3.pub()

Похоже, что Concrete3 .рас является полноценной переопределенной версией недоступного метода AbstractBase.рас. Действительно, Concrete3.pac переопреде. ляет Concrete2.pac, a Concrete2.pac переопределяет AbstractBase.рас— отсюда следует, что Concrete3. рас транзитивным образом переопределяет AbstractBase.рас. Заново объявляя метод рас как public, Concrete2 делает его доступным и допускающим переопределение в любом производном классе.

 

Источник: Арнолд, Кен, Гослинг, Джеймс, Холмс, Дэвид. Язык программирования Java. 3-е изд .. : Пер. с англ. – М. : Издательский дом «Вильяме», 2001. – 624 с. : ил. – Парал. тит. англ.

По теме:

  • Комментарии