Java видимость внутри пакета

Модификаторы доступа, переопределение методов, реализация абстрактных методов

— Я расскажу тебе про « модификаторы доступа ». Когда-то я уже рассказывал про них, но повторение – мать учения.

Ты можешь управлять доступом (видимостью) методов и переменных твоего класса из других классов. Модификатор доступа отвечает на вопрос «Кто может обращаться к данному методу/переменной?». Каждому методу или переменной можно указывать только один модификатор.

1) Модификатор « public ».

К переменной, методу или классу, помеченному модификатором public , можно обращаться из любого места программы. Это самая высокая степень открытости – никаких ограничений нет.

2) Модификатор « private ».

К переменной, методу или классу, помеченному модификатором private , можно обращаться только из того же класса, где он объявлен. Для всех остальных классов помеченный метод или переменная – невидимы. Это самая высокая степень закрытости – только свой класс. Такие методы не наследуются и не переопределяются. Доступ к ним из класса-наследника также невозможен.

3) «Модификатор « по умолчанию ».

Если переменная или метод не помечены никаким модификатором, то считается, что они помечены «модификатором по умолчанию». Переменные и методы с таким модификатором видны всем классам пакета, в котором они объявлены, и только им. Этот модификатор еще называют « package » или « package private », намекая, что доступ к переменным и методам открыт для всего пакета, в котором находится их класс

4) Модификатор « protected ».

Этот уровень доступа чуть шире, чем package . К переменной, методу или классу, помеченному модификатором protected , можно обращаться из его же пакета (как package), но еще из всех классов, унаследованных от текущего.

Тип видимости Ключевое слово Доступ
Свой класс Свой пакет Класс — наследник Все классы
Закрытый private Есть Нет Нет Нет
Пакет (нет модификатора) Есть Есть Нет Нет
Защищенный protected Есть Есть Есть Нет
Открытый public Есть Есть Есть Есть

Есть способ, чтобы легко запомнить эту таблицу. Представь себе, что ты составляешь завещание и делишь все вещи на четыре категории. Кто может пользоваться твоими вещами?

Кто имеет доступ Модификатор Пример
Только я сам private Личный дневник
Семья (нет модификатора) Семейные фотографии
Семья и наследники protected Фамильное поместье
Все public Мемуары

— Если представить, что классы, лежащие в одном пакете, – это одна семья, то очень даже похоже.

— Хочу также рассказать тебе несколько интересных нюансов насчет переопределения методов.

1) Неявная реализация абстрактного метода.

И ты решил унаследовать от него класс тигр и добавить новому классу интерфейс

interface HasName < String getName(); int getWeight(); >
class Tiger extends Cat implements HasName < public int getWeight() < return 115; >>

Если ты просто реализуешь все недостающие методы, которые тебе подскажет Intellij IDEA, то можешь потом долго искать ошибку.

Оказывается, что в классе Tiger есть унаследованный от Cat метод getName, который и будет считаться реализацией метода getName для интерфейса HasName.

— Не вижу в этом ничего страшного.

— Это не очень плохо, это скорее потенциальное место для ошибок.

interface HasWeight < int getValue(); >
interface HasSize < int getValue(); >
class Tiger extends Cat implements HasWeight, HasSize < public int getValue() < return 115; >>

Оказывается, ты не всегда можешь унаследоваться от нескольких интерфейсов. Вернее унаследоваться можешь, а вот корректно их реализовать – нет. Посмотри на пример, оба интерфейса требуют, чтобы ты реализовал метод getValue(), и не ясно, что он должен возвращать: вес(weight) или размер(size). Это довольно-таки неприятная вещь, если тебе придется с ней столкнуться.

Читайте также:  Using php and wordpress

— Да, согласен. Хочешь реализовать метод, а не можешь. Вдруг ты уже унаследовал метод с таким же именем от базового класса. Обломись.

— Но есть и приятные новости.

2) Расширение видимости. При переопределении типа разрешается расширить видимость метода. Вот как это выглядит:

class Cat < protected String getName() < return "Васька"; >>
class Tiger extends Cat < public String getName() < return "Василий Тигранович"; >>
public static void main(String[] args)
public static void main(String[] args)

Если бы этого сделать было нельзя, всегда можно было бы объявить метод в Tiger:
public String getPublicName()
super.getName(); //вызов protected метода
>

public static void main(String[] args)

— Не уверен, что понял полностью, но то, что так можно делать, запомню.

3) Сужение типа результата.

В переопределенном методе мы можем поменять тип результата , сузив его.

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; > >
public static void main(String[] args)
public static void main(String[] args)

Если бы этого сделать было нельзя, всегда можно было бы объявить метод в Tiger:
public Tiger getMyTigerParent()
return (Tiger) this.parent;
>

public static void main(String[] args) < Tiger parent = new Tiger(); Cat me = new Tiger(); me.setMyParent(parent); Cat myParent = me.getMyParent(); >

Нет ничего страшного при вызове метода getMyParent , т.к. его результат , хоть и класса Tiger, все равно сможет отлично присвоиться в переменную myParent базового класса (Cat).

— Ага. Я понял. Надо при переопределении методов беспокоиться о том, как все это будет работать, если мы передадим наши объекты в код, который умеет обращаться только с базовым классом, и ничего о нашем классе не знает.

— Именно! Тогда вопрос на засыпку, почему нельзя расширить тип результата при переопределении метода?

— Это же очевидно, тогда перестанет работать код в базовом классе:

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 "я - сирота"; > >
public static void main(String[] args) < Tiger parent = new Tiger(); Cat me = new Tiger(); Cat myParent = me.getMyParent(); >

Метод getMyParent может вернуть любой объект типа Object, т.к. на самом деле он вызывается у объекта типа Tiger.

В Java перед вызовом метода не проверяется, есть ли такой метод у объекта или нет. Все проверки происходят во время выполнения. И [гипотетический] вызов отсутствующего метода, скорее всего, приведет к тому, что программа начнет выполнять байт-код там, где его нет. Это, в конце концов, приведет к фатальной ошибке, и операционная система принудительно закроет программу.

Java-университет

Хотелось бы немного ясности внести относительно модификаторов доступа и классов, в которых они находятся. Частенько встречал в лекциях такое смелое утверждение, которое гласит, что модификатор доступа public делать помеченный член класса/интерфейса общедоступным из любой точки программы. Так ли это на самом деле? Это действительно так, но с оговорками, о которых почему-то ничего не говорится! Это же и касается других модификаторов доступа. Сейчас постараюсь пояснить идею. На самом деле, первое, что необходимо запомнить и на что обращать внимание, это уровень доступа самого класса/интерфейса. Классы и интерфейсы верхнего уровня (которые не являются вложенными относительно других классов и интерфейсов), как известно, могут иметь всего 2 уровня доступа. Класс может быть общедоступным (public) или же быть инкапсулированным в пакете, в котором он находится (в том случае, если класс явно не помечен модификатором public). Так вот, если класс или интерфейс изначально имеет пакетный доступ, то никакие его члены не будут доступны за пределами пакета. Мы можем помечать их public или protected, но их реальный доступ не будет выше, чем package-private, так как доступ к конктреному члену класса не может быть выше, чем доступ самого класса (это и очевидно, так как доступ к членам класса всегда осуществляется через сам класс). Что касается классов-членов/интерфейсов-членов, которые составляют основу некоторой иерархии вложенности (вложены в какой-то обрамляющий их класс), то уровень доступа таких классов можно задать любой (доступны все 4 уровня доступа), если они объявлены внутри класса и исключительно public, если внутри интерфейса. Разумеется, что уровень доступа вложенных классов/интерфейсов добавляет дополнительные ограничения. К примеру, если класс приватный, то он будет полностью инкапсулирон внутри обрамляющего класса и какими бы модификаторами не были помечены его члены, они не будут доступны за пределами класса.

Читайте также:  Frontend javascript backend php

Cat cat = new Cat(); Tigr tigr = (Tigr) cat; И теперь мы сможем вызывать все методы класса Tigr с помощью переменной tigr. Я думаю это хотели донести.

Еще в процессе прочтения лекции понял, что следует искать выжимки в комментариях, как впрочем и всегда.. Но обратил внимание, что среди самых популярных комментов многие больше вдохновляются от объяснения более общей темы, «Проблемы сужения и расширения объектов и иже с ними».. , в то время как в статье рассматривались несколько более частные случаи возникающие в процессе переопределения методов. Потому, на мой взгляд и на взгляд других неравнодушных 47 проплюсовавших, подниму вот такой коммент от yurii: 1. Если в классе-родители реализован такой же метод, как и в реализуемом интерфейсе, то такой метод будет считаться реализацией аналогичного метода интерфейса. 2. При переопределении метода допускается расширение модификатора доступа, сужение нет : protected -> public — OK; public -> private — Error 3. При переопределении метода разрешается сужение типа возвращаемого значение, расширение нет: Cat —> Tiger — OK Cat —> Object — Error Пусть и несовершенен стиль описания, но суть статьи в тезисах выдана..

Лекция ужасна, не старайтесь раздуплить ее. Отсортируйте комменты по популярности и наслаждайтесь. Там будут и объяснения и ссылки на полезные ресурсы.

 class Cat < public Cat parent; // это переменная тип объект public Cat getMyParent() //что возвращает этот геттер < return this.parent; >public void setMyParent(Cat cat) // и что устанавливает этот сеттер и что принимает < this.parent = cat; >> 

С protected примерами намудрили, половина не правильно или правильно но при особых обстоятельствах о которых в примере ни слова.

не ну это талант,запутать в том что уже знаешь)) попробую обьяснить допустим у нас есть класс родитель Animal от него наследуется класс Pet,а от него Cat тобишь вертикаль иерархии..представили это слева и так же справа Animal an = new Animal(); Pet p = new Pet(); Cat cat = new Сat(); слева от равно это переменная, которая хранит объект который находиться справа от равно. то какие методы будут доступны определяет тип переменной,то какая именно реализация этого метода будет вызванна определяет объект так вот,в верхний класс можно сохранить объект любого класса наследника (те что ниже по иерархии) НО не наоборот..в переменную класса Pet сохранить объект Animal НЕЛЬЗЯ,то есть по иерархии переменная может хранить объект своего уровня или ниже,но не выше,если нам нужно это обойти делаем явное приведение типа (сужение) или расширение типа

Читайте также:  Javascript файл в массиве

для наибольшего понимания советую прогонять весь этот код в среде разраба и выводить постоянно на экран ссылку на объект и смотреть чему она равна: Tiger либо Cat

Источник

Java/Видимость

Доступен внутри пакета и своим подклассам из других пакетов.

class A  protected int x; protected void f() <> protected static String name = "Ku-Ku"; > class B extends A  public void someFunc()  x = 10; //Доступ к защищённому члену родительского класса f(); A ref = new A(); ref.x = 13; //В контексте дочернего класса обращение к защищённым членам ЗАПРЕЩЕНО (приведет к ошибке компиляции) String bebe = A.name; //Статические переменные - не исключение > > class C  public void someFunc()  String mmm = A.name; //Неверный вызов. Переменная name - защищена и не видна извне (Только если класс С находится в другом пакете. Если класс С находится в том же пакете, что и А, то переменная name будет доступна) A a = new A(); int myX = a.x; //Неверный вызов. Переменная x - не видна извне (Только если класс С находится в другом пакете. Если класс С находится в том же пакете, что и А, то переменная х будет доступна) a.x = 1; //Неверный вызов. Переменная x - не видна извне (Только если класс С находится в другом пакете. Если класс С находится в том же пакете, что и А, то переменная х будет доступна) a.f(); //Неверный вызов. Функция f - не видна извне (Только если класс С находится в другом пакете. Если класс С находится в том же пакете, что и А, то функция f будет доступна) > > 

package-private [ править ]

Доступен в пределах своего пакета package . Присваивается автоматически, если не указан модификатор доступа.

class A  //Этот класс виден только в пакете, в котором находится сам int x; //Члены класса видны для всех классов данного пакета > 

private [ править ]

Доступен только внутри своего класса.

class A  private int x; //переменную x видно исключительно внутри класса A public void setX(int value)  //обычно такую функцию называют "setter" x = value; > public int getX()  //обычно такую функцию называют "getter" return x; > > class B extends A  public void someFunc()  this.x = 10; //Ошибка! Приватные переменные не видны даже наследникам > > 

setX и getX — являются функциями доступа к приватной переменной. Если мы решим, что переменная x может содержать исключительно числа от 1 до 100, то нам не понадобится искать все обращения к x по всем классам, а просто добавить проверку между строками N и N .

Источник

Оцените статью