вторник, 1 июля 2014 г.

Java модификаторы доступа


Что-то я стала сомневаться по поводу двух модификаторов доступа: protected и default. И решила написать статью, чтобы освежить знания. В основном приходится сталкиваться с private и public.

В Java определены 4 модификатора доступа:
  • public (наименее ограничивающий доступ) (UML обозначение  - "+")
  • protected (UML обозначение  - "#")
  • default
  • private (наиболее ограничивающий доступ) (UML обозначение  - "-")

Понимание public-модификатора доступа


Public классы и интерфейсы доступны из всех пакетов, в производных и непроизводных (несвязанных) классах.

Таблица получения доступа к public классу и его членам


Понимание protected-модификатора доступа




Члены класса, объявленного с модификатором доступа protected, доступны из:
  1. Классы и интерфейсы, объявленные в том же пакете.
  2. Все производные классы, даже если они определены в различных пакетах.

Но есть тут один скользкий момент

Рассмотрим на примере (здесь оба класса расположены в пакете by.modifier):

package by.modifier;

public class ModifierTest extends PrivateModifier{
 
 public static void main(String[] args){
  new ModifierTest().modifierTest();  
 }
 
 public void modifierTest(){
     System.out.println("Test 1 " + getHello());
  
  PrivateModifier privateModifier = new PrivateModifier();
  System.out.println("Protected test " + privateModifier.getHello());
 }

}

В данном примере все хорошо, компиляция пройдет успешно


Test 1 hello
Protected test hello

С одной стороны похожий пример, но совершенно другой на самом деле (здесь ModifierTest находится в default package (здесь имеет значение только то, что это другой пакет)). То есть родитель-класс и наследник находятся в разных пакетах.

import by.modifier.PrivateModifier;
public class ModifierTest extends PrivateModifier{
 
 public static void main(String[] args){
  new ModifierTest().modifierTest();  
 }
 
 public void modifierTest(){
     System.out.println("Test 1 " + getHello());
  
  PrivateModifier privateModifier = new PrivateModifier();
  System.out.println("Protected test " + privateModifier.getHello());
 }

}

Так вот здесь мы получим интересную ошибку

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
 The method getHello() from the type PrivateModifier is not visible

 at ModifierTest.modifierTest(ModifierTest.java:15)
 at ModifierTest.main(ModifierTest.java:8)

Ошибка произошла из-за попытки доступа к protected методу класса наследника, который находится в другом пакете, через создание нового ссылочного объекта родителя.

Кратко сформулируем:
 
Класс-наследник может наследовать и получать доступ к protected-членам своего родительского класса, несмотря на то, в каком пакете он определен.
Производный класс в отличном пакете от пакета, в котором находится родительский класс, не может получать доступ к protected-переменным родительского класса, используя ссылочную переменную на родителя(новый объект-родитель).
 


Понимание default-модификатора (пакетный доступ) доступа

Члены класса, объявленные без явного указания модификатора доступа, определены с пакетным доступом. Они доступны только классам и интерфейсам объявленным в одном и том же пакете.


Подсказка

Модификатор доступа по умолчанию можно сравнить с уровнем доступа на уровне пакета (доступ только внутри пакета), а protected (защищенный доступ) можно сравнить с уровнем доступа на уровне пакета + "наследники". Наследники могут иметь доступ только, используя наследование, а не ссылку (доступ к членам класса используя оператор "." на объекте).


Понимание private-модификатора

Это самый строгий модификатор доступа. Члены класса, объявленные с модификатором private доступны только из него самого.