Инкапсуляция данных в классе. Управление доступом в Java. Модификаторы private, protected, public
Содержание
- 1. Что такое инкапсуляция в классе?
- 2. Какие существуют категории доступности членов данных класса в языке Java?
- 3. Какие преимущества дает использование механизма инкапсуляции в классе?
- 4. Какие модификаторы доступа применяются к данным из методов класса?
- 5. Какая общая форма объявления элемента класса с заданным модификатором доступа?
- 6. Доступ к элементам класса, которые объявлены с модификатором доступа private. Пример
- 7. Доступ к элементам класса, которые объявлены с модификатором доступа public. Примеры
- 8. Доступ к элементам класса, которые объявлены с модификатором доступа protected. Примеры
- 9. Особенности доступа к элементам класса в случае отсутствия модификатора доступа. Примеры
- 10. Какой тип доступа имеют члены класса по умолчанию?
- 11. Можно ли объявлять конструктор класса с модификатором доступа private?
- Связанные темы
Поиск на других ресурсах:
1. Что такое инкапсуляция в классе?
Инкапсуляция в классе означает предоставление соответствующего доступа к членам класса с помощью специальных модификаторов доступа: private, protected, public. Доступ можно задавать как к данным, так и к методам класса.
⇑
2. Какие существуют категории доступности членов данных класса в языке Java?
В языке Java выделяются 4 категории доступности:
- производные классы (подклассы) в одном пакете;
- классы в одном пакете, которые не являются производными;
- производные классы (подклассы) в разных пакетах;
- классы, которые находятся в разных пакетах и не являются производными (не являются подклассами).
⇑
3. Какие преимущества дает использование механизма инкапсуляции в классе?
Инкапсуляция данных в классе дает следующие преимущества:
- если данные класса есть скрытыми, то это защищает от злоупотреблений или случайного доступа к ним. Доступ к данным обеспечивается с помощью специально разработанных методов класса;
- если данные (методы) класса есть скрытыми, то они представляют своего рода «черный ящик». Взаимодействие с данными обеспечивается через соответствующие методы класса;
- гибкость в предоставлении доступа к разным видам данных класса с помощью соответствующих модификаторов;
- в методах доступа к скрытым данным класса можно делать соответствующие проверки на корректность.
⇑
4. Какие модификаторы доступа применяются к данным из методов класса?
Для управления доступом к данным из методов класса, в Java используются следующие модификаторы доступа:
- private. В этом случае данные (методы) есть скрытыми. Доступ к таким данным имеют только методы класса. Из экземпляра (объекта) класса private-элементы есть недоступны;
- public. Если член класса объявлен с модификатором доступа public, то этот член класса есть доступным из любого кода данного пакета и за пределами пакета (для всех методов всех классов);
- protected. Этот модификатор используется в случае, когда нужно, чтобы элемент класса был доступным за пределами текущего пакета, но только классам, непосредственно производным (унаследованным) от данного класса.
Также элементы класса могут быть объявлены без модификатора доступа.
⇑
5. Какая общая форма объявления элемента класса с заданным модификатором доступа?
Модификатор доступа к конкретному члену данных или методу устанавливается перед его объявлением.
Общая форма класса, в котором объявляются один член данных класса и один метод следующая
class ClassName { // объявление члена данных класса access_modifier type variable; // объявление метода в классе access_modifier return_type MethodName(parameters) { // тело метода // ... } }
где
- ClassName – имя объявляемого класса;
- access_modifier – один из модификаторов доступа private, public, protected;
- type – тип члена данных класса с именем variable;
- variable – член данных класса, который объявлен с типом type;
- return_type – тип, который возвращает метод класса с именем MethodName();
- parameters – параметры, которые получает метод MethodName().
⇑
6. Доступ к элементам класса, которые объявлены с модификатором доступа private. Пример
Элементы класса, которые объявленные с модификатором доступа private, есть скрытыми. К ним имеют доступ только методы данного класса. Из всех других частей программного кода к private-членам класса нет доступа.
Такой способ скрытия данных в классе есть эффективным в случаях, если нужно:
- спрятать детали организации структур данных и реализации данного класса;
- избегнуть возможные случайные изменения данных в экземпляре класса;
- обеспечить удобство доступа к данным в классе с помощью специально разработанных методов. Здесь имеется ввиду разработка методов в классе которые обеспечивают чтение/запись данных класса. Эти методы могут включать соответствующие проверки на корректность при изменении данных в классе;
- избегнуть возможные злоупотребления данными в классе что может привести к возникновению трудноуловимых ошибок в программе.
Пример. Демонстрируется пример доступа к private-переменной класса с помощью методов доступа.
Объявляется класс, реализующий день недели. В классе объявляется скрытый (private) член данных класса с именем value. Для доступа к value в классе используются:
- конструктор DayWeek(), который инициализирует значение value=1. Конструктор объявлен без модификатора. Это значит, что в пределах пакета он имеет тип доступа public;
- метод Get(), возвращающий значение value. Поскольку метод объявлен в классе DayWeek, то в теле метода есть доступ к переменной value;
- метод Set(), устанавливающий новое значение value. Метод также объявлен в классе, поэтому имеет доступ к value. В методе осуществляется проверка на корректность значения value в границах 1..7. Если задать другое значение, то значение value не изменится;
- метод GetName(), возвращающий название дня недели в зависимости от значения value.
Реализация класса DayWeek следующая
// класс, который реализует день недели class DayWeek { private int value; // скрытая переменная класса // конструктор класса, инициализирует переменную value DayWeek() { value = 1; // по умолчанию - "Monday" } // методы доступа // метод, который возвращает данные в классе public int Get() { return value; } // метод, который устанавливает новый день недели public void Set(int _value) { // в методе выполняется проверка на корректность значения _value if ((_value>=1)&&(_value<=7)) value = _value; } // дополнительный метод // возвращает название дня недели, которому соответствует value public String GetName() { String day = "Monday"; switch (value) { case 2: day = "Tuesday"; break; case 3: day = "Wednesday"; break; case 4: day = "Thursday"; break; case 5: day = "Friday"; break; case 6: day = "Saturday"; break; case 7: day = "Sunday"; break; } return day; } }
Использовать такой класс в другом коде (методе) можно, например, следующим образом
public class HiddenData { public static void main(String[] args) { // доступ к private-члену данных класса DayWeek dw = new DayWeek(); int Day; String strDay; Day = dw.Get(); // Day = 1 strDay = dw.GetName(); // strDay = "Monday" System.out.println("Day = " + Day); System.out.println("strDay = " + strDay); // установить новое значение дня dw.Set(3); // проверка Day = dw.Get(); // Day = 3 strDay = dw.GetName(); // strDay = "Wednesday" System.out.println("Day = " + Day); System.out.println("strDay = " + strDay); } }
Результат выполнения вышеприведенной программы
Day = 1 strDay = Monday Day = 3 strDay = Wednesday
⇑
7. Доступ к элементам класса, которые объявлены с модификатором доступа public. Примеры
К элементам класса, которые объявлены с модификатором доступа public есть доступ из любого программного кода пакета, в котором объявлен данный класс.
Если нужно иметь доступ к public-элементам класса из других пакетов, то этот класс должен быть объявлен с модификатором public. Более подробно об особенностях доступа к public-классам из других пакетов описывается в теме:
⇑
7.1. Пример доступа к public-элементу класса в пределах пакета
Задан класс A с членом данных value, который объявлен с модификатором public. Ниже продемонстрированы три возможных способа доступа к public-члену данных value:
- из текущего класса A;
- из класса B, который объявлен в данном пакете;
- из класса C, который объявлен в данном пакете и есть производным от класса A.
// некоторый класс class A { public int value; // переменная, объявленная с модификатором public // доступ из метода текущего класса void methodA() { value = 5; } } class B { // доступ из метода другого класса данного пакета void methodB() { A objA = new A(); objA.value = 10; } } // класс C наследует класс A class C extends A { // доступ из метода производного класса void methodC() { value = 30; } }
⇑
7.2. Пример доступа к public-элементу класса из другого пакета
Чтобы иметь доступ к public-элементу класса из другого пакета этот класс может быть также объявлен как public.
Пусть в пакете Package1 задан класс с именем DemoPackage1. В классе объявляется public-переменная value.
// модификатор доступа public, пакет Package1 package Package1; // Пакет Package1 // public-класс DemoPackage1 public class DemoPackage1 { public int value; // эта переменная есть доступна за пределами пакета public static void main(String[] args) { } }
Тогда, доступ из другого пакета Package2 к переменной value может быть:
- с помощью использования экземпляра (объекта) класса Package1.DemoPackage1;
- с помощью класса, который есть производным от класса Package1.DemoPackage1.
// Пакет Package2 package Package2; // подключение класса DemoPackage1 из пакета Package1. import Package1.DemoPackage1; // некоторый класс в пакете Package2 public class DemoPackage2 { public static void main(String[] args) { // создание экземпляра класса DemoPackage1, // который размещается в пакете Package1 - разрешено Package1.DemoPackage1 dp1 = new Package1.DemoPackage1(); // доступ к public-переменной класса из другого пакета, который объявлен как public dp1.value = 30; } } // класс, который наследует (расширяет) класс DemoPackage1 из пакета Package1 class DemoPackage3 extends DemoPackage1 { // метод, который имеет доступ к Package1.DemoPackage1.value void IncValue(int _delta) { value = value + _delta; // увеличить value на величину delta } }
Следует заметить, если в пакете Package2 размещается директива
import Package1.DemoPackage1;
то к классу DemoPackage1 из пакета Package1 можно обращаться любым из двух способов:
- с учетом имени пакета: Package1.DemoPackage1;
- без использования имени пакета перед именем класса: DemoPackage1.
⇑
8. Доступ к элементам класса, которые объявлены с модификатором доступа protected. Примеры
Рассматривают два случая доступа к protected-элементу класса:
- в пределах пакета, в котором класс с данным protected-элементом объявлен (в текущем пакете);
- из другого пакета.
Если в некотором пакете элемент класса объявлен с ключевым словом protected, то:
- в текущем пакете этот элемент есть видимый из любого кода (также как и public-элемент);
- в другом пакете этот элемент есть видимым только в производных классах.
⇑
8.1. Пример доступа к protected-члену данных класса в пределах пакета
Задан класс A, в котором объявлен protected-член данных value. Из данного пакета к элементу класса value можно иметь доступ следующими способами:
- из текущего класса A;
- из класса B, который объявлен в данном пакете;
- из класса C, который объявлен в данном пакете и есть производным от класса A.
// модификатор доступа protected, пакет Package1 package Package1; // некоторый класс class A { protected int value; // переменная, объявленная с модификатором protected // доступ из метода текущего класса void methodA() { value = 5; } } class B { // доступ из метода другого класса данного пакета void methodB() { A objA = new A(); objA.value = 10; } } // класс C наследует класс A class C extends A { // доступ из метода производного класса void methodC() { value = 30; } }
Из вышеприведенного кода можно сделать следующий вывод:
- в пределах пакета доступ к protected-элементам класса такой же как и к public-элементам класса.
⇑
8.2. Пример доступа к protected-члену данных класса из другого пакета
Для того, чтобы protected-элемент класса был доступен за пределами данного пакета, этот класс обязательно должен быть объявлен с модификатором public.
Чтобы доступиться к protected-элементу класса из классов других пакетов нужно, чтобы эти классы были производными от данного класса.
Рассмотрим это на примере.
Пусть задан пакет с именем Package1. В этом пакете реализован класс DemoPackage1, в котором объявляется protected-переменная value.
// модификатор доступа protected, // пакет Package1 package Package1; // public-класс DemoPackage1 public class DemoPackage1 { // за пределами пакета эта переменная доступна только в производных классах protected int value; public static void main(String[] args) { } }
В нижеследующем коде продемонстрирован доступ из другого пакета Package2 к protected-переменной value класса DemoPackage1 (пакет Package1).
// Пакет Package2 package Package2; // подключение класса DemoPackage1 из пакета Package1. import Package1.DemoPackage1; // некоторый класс в пакете Package2 public class DemoPackage2 { public static void main(String[] args) { // создание экземпляра класса DemoPackage1, // который размещается в пакете Package1 - разрешен Package1.DemoPackage1 dp1 = new Package1.DemoPackage1(); // доступ к protected-переменной класса из другого пакета // dp1.value = 30; - ЗАПРЕЩЕНО, ошибка } } // класс, который наследует (расширяет) класс DemoPackage1 из пакета Package1 // этот класс имеет доступ к protected-переменной value class DemoPackage3 extends DemoPackage1 { // метод, который имеет доступ к Package1.DemoPackage1.value void IncValue(int _delta) { value = value + _delta; // доступ РАЗРЕШЕН } }
Если снять комментарий из строки
dp1.value = 30;
то компилятор выдаст ошибку
The field DemoPackage1.value is not visible
⇑
9. Особенности доступа к элементам класса в случае отсутствия модификатора доступа. Примеры
При объявлении модификатор доступа к членам класса может отсутствовать. В этом случае к члену класса имеют доступ:
- методы этого класса;
- методы производного подкласса, который объявлен в этом самом пакете;
- методы любого класса, который размещен в этом самом пакете.
Запрещен доступ из других пакетов к элементам класса не имеющим модификатора доступа.
Пример 1. В примере демонстрируется доступ к переменной value класса A из методов других классов. Переменная value класса A объявлена без модификатора доступа.
// пакет Package1 // модификатор доступа отсутствует package Package1; class A { int value; // переменная, объявленная без модификатора доступа // доступ из метода текущего класса void method() { value = 5; // доступ разрешен } } class B { // доступ из метода другого класса данного пакета void method() { A obj = new A(); // экземпляр класса A obj.value = 10; // доступ разрешен } } class C extends A { // доступ из метода производного класса void method() { value = 30; // доступ разрешен } }
Пример 2. Демонстрация запрета доступа из другого пакета к переменной value класса DemoPackage1, которая объявлена без модификатора доступа.
Заданы два пакета с именами Package1 и Package2. В пакете Package1 объявляется public-класс с именем DemoPackage1. В этом классе объявляется переменная value без модификатора доступа.
Текст пакета Package1 следующий:
// Пакет Package1 // класс DemoPackage1 public class DemoPackage1 { int value; // эта переменная доступна только в этом пакете public static void main(String[] args) { } }
В другом пакете Package2 объявляется класс DemoPackage2 и директива import, которая подключает пакет Package1.
// Пакет Package2 package Package2; // подключение класса DemoPackage1 из пакета Package1. import Package1.DemoPackage1; // некоторый класс в пакете Package2 public class DemoPackage2 { public static void main(String[] args) { // создание экземпляра класса DemoPackage1, // который размещается в пакете Package1 - разрешено Package1.DemoPackage1 dp1 = new Package1.DemoPackage1(); // невозможно доступиться к переменной другого пакета, // которая объявлена без модификатора // dp1.value = 10; - ошибка, доступ к переменной dp1.value ЗАПРЕЩЕН! } }
Как видно из примера, попытка вызвать строку
dp1.value = 10;
из пакета Package2 вызовет ошибку компилятора со следующим сообщением
The field DemoPackage1.value is not visible
Это значит, что поле value класса DemoPackage1 есть невидимым.
⇑
10. Какой тип доступа имеют члены класса по умолчанию?
Перед объявлением переменной, экземпляру или методу в классе не обязательно указывать модификатор доступа. Если модификатор доступа отсутствует перед объявлением членов класса, то принимается доступ по умолчанию. Для членов класса в Java установлен общедоступный (public) доступ по умолчанию.
⇑
11. Можно ли объявлять конструктор класса с модификатором доступа private?
Да можно. Такой конструктор никогда не будет вызван за пределами класса, то есть из экземпляра (объекта) класса. Но такой конструктор может быть использован в методах, которые объявляются в самом классе при создании экземпляров этого класса.
Например. Пусть задан класс с именем CData. В классе объявляются:
- конструктор без параметров с модификатором доступа public;
- скрытый (private) конструктор с одним параметром. Этот конструктор будет использоваться в методе UseCData(), который объявлен в этом же классе;
- метод CData(), который использует скрытый (private) конструктор CData с одним параметром.
Текст объявления и использования класса имеет вид:
// класс, который содержит скрытый конструктор class CData { int d; // член данных d имеет доступ public по умолчанию // public-конструктор, видимый за пределами класса CData() { d = 0; } // скрытый конструктор, видимый только в пределах класса private CData(int _d) { d = _d; } // метод, который использует скрытый (private) конструктор класса public void UseCData(int _d) { CData DD = new CData(_d); // использовать private-конструктор класса System.out.println("DD = "+DD.d); } } public class TestClass { public static void main(String[] args) { // создать экземпляр класса CData CData D1 = new CData(); // вызов public-конструктора без параметра // Запрещено вызывать private-конструктор класса CData //CData D2 = new CData(2); // доступ к члену данных d D1.d = 30; System.out.println("D1.d = " + D1.d); D1.UseCData(55); // вывести на экран DD=55 } }
Как видно из объявления класса, в методе UseCData() будет вызван скрытый (private) конструктор с одним параметром
... CData DD = new CData(_d); // использовать private-конструктор класса ...
В результате выполнения вышеприведенного кода, на экран будет выведено:
D1.d = 30 DD = 55
⇑
Связанные темы
- Применение классов в программах на Java. Определение класса и объекта класса. Примеры
- Пакеты. Использование пакетов в Java. Директивы import и package. Компилированные модули (.java). Промежуточные .class файлы. Структура проекта. Использование стандартных библиотек Java
- Управление доступом к классам в пакетах. Пакетный уровень доступа к классу. Общедоступный (public) уровень доступа к классу
⇑