Уровень инкапсуляции protected имеют элементы класса которые
Все члены класса в языке Java — поля и методы — имеют модификаторы доступа. В прошлых темах мы уже сталкивались с модификатором public . Модификаторы доступа позволяют задать допустимую область видимости для членов класса, то есть контекст, в котором можно употреблять данную переменную или метод.
В Java используются следующие модификаторы доступа:
- public : публичный, общедоступный класс или член класса. Поля и методы, объявленные с модификатором public, видны другим классам из текущего пакета и из внешних пакетов.
- private : закрытый класс или член класса, противоположность модификатору public. Закрытый класс или член класса доступен только из кода в том же классе.
- protected : такой класс или член класса доступен из любого места в текущем классе или пакете или в производных классах, даже если они находятся в других пакетах
- Модификатор по умолчанию . Отсутствие модификатора у поля или метода класса предполагает применение к нему модификатора по умолчанию. Такие поля или методы видны всем классам в текущем пакете.
Рассмотрим модификаторы доступа на примере следующей программы:
public class Program < public static void main(String[] args) < Person kate = new Person("Kate", 32, "Baker Street", "+12334567"); kate.displayName(); // норм, метод public kate.displayAge(); // норм, метод имеет модификатор по умолчанию kate.displayPhone(); // норм, метод protected //kate.displayAddress(); // ! Ошибка, метод private System.out.println(kate.name); // норм, модификатор по умолчанию System.out.println(kate.address); // норм, модификатор public System.out.println(kate.age); // норм, модификатор protected //System.out.println(kate.phone); // ! Ошибка, модификатор private >> class Person < String name; protected int age; public String address; private String phone; public Person(String name, int age, String address, String phone)< this.name = name; this.age = age; this.address = address; this.phone = phone; >public void displayName() < System.out.printf("Name: %s \n", name); >void displayAge() < System.out.printf("Age: %d \n", age); >private void displayAddress() < System.out.printf("Address: %s \n", address); >protected void displayPhone()< System.out.printf("Phone: %s \n", phone); >>
В данном случае оба класса расположены в одном пакете — пакете по умолчанию, поэтому в классе Program мы можем использовать все методы и переменные класса Person, которые имеют модификатор по умолчанию, public и protected. А поля и методы с модификатором private в классе Program не будут доступны.
Если бы класс Program располагался бы в другом пакете, то ему были бы доступны только поля и методы с модификатором public.
Модификатор доступа должен предшествовать остальной части определения переменной или метода.
Инкапсуляция
Казалось бы, почему бы не объявить все переменные и методы с модификатором public , чтобы они были доступны в любой точке программы вне зависимости от пакета или класса? Возьмем, например, поле age, которое представляет возраст. Если другой класс имеет прямой доступ к этому полю, то есть вероятность, что в процессе работы программы ему будет передано некорректное значение, например, отрицательное число. Подобное изменение данных не является желательным. Либо же мы хотим, чтобы некоторые данные были достуны напрямую, чтобы их можно было вывести на консоль или просто узнать их значение. В этой связи рекомендуется как можно больше ограничивать доступ к данным, чтобы защитить их от нежелательного доступа извне (как для получения значения, так и для его изменения). Использование различных модификаторов гарантирует, что данные не будут искажены или изменены не надлежащим образом. Подобное сокрытие данных внутри некоторой области видимости называется инкапсуляцией .
Так, как правило, вместо непосредственного применения полей используют методы доступа. Например:
public class Program < public static void main(String[] args) < Person kate = new Person("Kate", 30); System.out.println(kate.getAge()); // 30 kate.setAge(33); System.out.println(kate.getAge()); // 33 kate.setAge(123450); System.out.println(kate.getAge()); // 33 >> class Person < private String name; private int age = 1; public Person(String name, int age)< setName(name); setAge(age); >public String getName() < return this.name; >public void setName(String name) < this.name = name; >public int getAge() < return this.age; >public void setAge(int age) < if(age >0 && age < 110) this.age = age; >>
И затем вместо непосредственной работы с полями name и age в классе Person мы будем работать с методами, которые устанавливают и возвращают значения этих полей. Методы setName, setAge и наподобие еще называют мьютейтерами (mutator), так как они изменяют значения поля. А методы getName, getAge и наподобие называют аксессерами (accessor), так как с их помощью мы получаем значение поля.
Причем в эти методы мы можем вложить дополнительную логику. Например, в данном случае при изменении возраста производится проверка, насколько соответствует новое значение допустимому диапазону.
Уровень инкапсуляции protected имеют элементы класса, которые: могут — Ответ на вопрос №5096
Сотрудничество с нами обеспечивает вам высочайшее качество работ по невероятно низкой цене. Обладая эксклюзивными знаниями, полученными в престижных университетах, и обширным практическим опытом, мы гарантируем уникальность и качество в каждой задаче.
Поделитесь ссылкой:
Характеристики
Цена: Бесплатно
Просмотров/покупок ответа
Количество символов в ответе
Количество картинок в ответе
Нет картинок
Поделитесь ссылкой:
Похожие вопросы
Свежие статьи
Коллекции ответов на вопросы: как пользоваться?
Агрегатор образовательных курсов: что это?
Топ сервисов и программ для дистанционного обучения
Дневник производственной практики: руководство по написанию и отличия от отчета по практике
11 советов для студентов
Популярно сейчас
Высшая математика
Математика
399 299 руб.
Финансовая грамотность
Финансовая грамотность
Экономическая теория
Экономическая теория
Курсовой проект
Детали машин (ДМ)
11000 8999 руб.
КМ-1 + КМ-3 выполнение письменных заданий под ключ.
Разработка программного обеспечения систем управления
12900 11739 руб.
Технология программирования
Технология программирования
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
То есть уже всё готово?
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
А я могу что-то выложить?
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
А если в купленном файле ошибка?
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Можно заказать выполнение работы на СтудИзбе?
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает — и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе «Студизба»
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Модификаторы доступа
Вы уже, наверное, неоднократно видели в примерах использование таких ключевых слов, как public , private и protected . Это модификаторы доступа в языке Java. Сегодня мы рассмотрим для чего они используются.
Очень часто в Java доступ к некоторым членам класса желательно ограничить. Для этого и нужны модификаторы доступа, которые могут присутствовать в объявлении члена класса. Модификатор доступа указывается перед остальной спецификации типа члена, например:
public int i; private static double j; private int myMethod (int а , char b ) < / / . . .
Существует три модификатора доступа: public , private и protected и четыре уровня доступа:
- public (открытый) - когда член объявляется с модификатором доступа public , он становится доступным из любого другого кода.
- private (закрытый) - когда член класса объявляется с модификатором доступа private , он доступен только другим членам этого же класса.
- protected (защищенный) - применяется только при наследовании.
- Уровень доступа, предоставляемый по умолчанию - в отсутствие модификатора доступа по умолчанию член класса считается открытым в своем пакете, но недоступным для кода, находящегося за пределами этого пакета.
Ограничение уровня доступа к членам класса - это еще один механизм реализации принципа инкапсуляции.
2. Отличие уровня доступа по умолчанию, public и private
Рассмотрим отличие уровня доступа по умолчанию, public и private на следующем примере. В классе Modificators объявлено три переменные с разным уровнем доступа. Внутри самого класса Modificators можно обратится к любой из этих переменных, как показано в методе toString() :
package oop; public class Modificators < public int publicVar; // открытый уровень доступа private int privateVar; // закрытый уровень доступа int defaultVar; // уровень доступа по умолчанию public String toString() < return "Modificatorspackage oop; public class ModificatorsDemo1 < public static void main(String[] args) < Modificators object = new Modificators(); object.defaultVar = 10; object.publicVar = 20; //object.privateVar = 100; // Ошибка компиляции! >>
Создадим класс похожий на ModificatorsDemo1 , но в другом пакете. В этом классе мы точно также не можем обратиться к private переменной, но теперь и переменная с уровнем доступа по умолчанию тоже недоступна:
package oop.p2; import oop.Modificators; public class ModificatorsDemo2 < public static void main(String[] args) < Modificators object = new Modificators(); //object.defaultVar = 10;// Ошибка компиляции! object.publicVar = 20; //object.privateVar = 100; // Ошибка компиляции! >>
3. Уровень доступа protected в Java
Уровень доступа protected используется при наследовании. Он очень похож на уровень доступа по умолчанию, который раскрывает область видимости только для классов определенных в том же пакете. Protected модификатор раскрывает область видимости для классов определенных в том же пакете или для классов наследников.
Рассмотрим разницу между уровнями доступа на следующем примере.
Объявим в классе Parent три метода с разными уровнями доступа:
package oop.p1; public class Parent < public void publicAccessMethod() < >void defaultAccessMethod() < >protected void protectedAccessMethod() < >>
Определяем класс наследник в другом пакете:
package oop.p2; import oop.p1.Parent; public class Child extends Parent < public void someMethod() < publicAccessMethod(); //defaultAccessMethod(); protectedAccessMethod(); >>
Из класса Child нет доступа к default членам класса Parent , но есть доступ к protected и public членам класса Parent .
Рассмотрим следующий класс - AccessClass , находящийся в пакете отличном от класса Parent . Он не является наследником Parent , поэтому доступ из него разрешен только к public методам:
package oop.p2; import oop.p1.Parent; public class AccessClass < public static void main(String[] args) < Parent parent = new Parent(); parent.publicAccessMethod(); // parent.defaultAccessMethod(); // parent.protectedAccessMethod(); >>
Перенесем класс AccessClass в пакет, в котором находится класс Parent , и мы получим доступ не только к public членам класса, но и к protected и default :
package oop.p1; public class AccessClass < public static void main(String[] args) < Parent parent = new Parent(); parent.publicAccessMethod(); parent.defaultAccessMethod(); parent.protectedAccessMethod(); >>
4. Уровни доступа для класса
Для класса, не являющегося вложенным, может быть указан только один из двух возможных уровней доступа:
- По умолчанию - если у класса имеется уровень доступа по умолчанию, такой класс оказывается доступным только для кода из данного пакета.
- Открытый ( public ) - если класс объявлен как public , он доступен из любого другого кода.
Когда мы говорим, что код из одного класса ( class A ) имеет доступ к коду из другого класса ( class B ), это означает что класс A может делать одну из трех вещей:
- создать экземпляр класса B ,
- наследовать класс B ,
- иметь доступ к определенным членам класса B .
В этом примере показана попытка наследовать класс HotBevarage с уровнем доступа по умолчанию из другого пакета. В этом случае возникнет ошибка компиляции:
package oop.p1; class HotBeverage<>
package oop.p2; //import oop.p1.HotBeverage; public class Tea //extends HotBeverage<>
Если класс оказывается открытым, он должен быть единственным открытым классом, объявленным в файле, а имя этого файла должно совпадать с именем класса. Например:
public class Beverage <> class HotBeverage<>
- Процедурное и объектно-ориентированное программирование
- Принципы ООП
- Классы и объекты
- Конструктор
- Ключевое слово this
- Перегрузка
- Стек и куча
- Передача объектов в методы
- Java varargs
- Рекурсия
- Сборщик мусора и метод finalize
- Наследование
- Ключевое слово super
- Геттеры и сеттеры
- Переопределение методов
- Абстрактные классы и методы
- Ключевое слово final
- Задания
Определение
Инкапсуляция это набор инструментов для управления доступом к данным или методам которые управляют этими данными. С детальным определением термина “инкапсуляция” можно ознакомиться в моей предыдущей публикации на Хабре по этой ссылке. Эта статья сфокусирована на примерах инкапсуляции в Си++ и Си.
Инкапсуляция в Си++
По умолчанию, в классе ( class ) данные и методы приватные ( private ); они могут быть прочитаны и изменены только классом к которому принадлежат. Уровень доступа может быть изменен при помощи соответствующих ключевых слов которые предоставляет Си++.
В Си++ доступно несколько спецификаторов, и они изменяют доступ к данным следующим образом:
- публичные ( public ) данные — доступны всем;
- защищенные ( protected ) — доступны только классу и дочерним классам;
- приватные ( private ) —доступны только классу которому они принадлежат.
Для краткости, только два уровня (приватный и публичный) будут освещены в примерах.
Пример инкапсуляции
В классе Contact , публичные переменные и методы доступны из основной программы ( main ). Приватные переменные и методы могут прочитаны, вызваны или изменены только самим классом.
#include using namespace std; class Contact < private: int mobile_number; // private variable int home_number; // private variable public: Contact() // constructor < mobile_number = 12345678; home_number = 87654321; >void print_numbers() < cout >; int main() < Contact Tony; Tony.print_numbers(); // cout
Попытка напечатать или изменить приватную переменную mobile_number из основной программы ( main ) вызовет ошибку при компиляции потому как доступ к приватным данным в классе ограничен.
Нарушение инкапсуляции с Друзьями (Хорошая практика)
В Си++ присутствует ключевое слово “друг” ( friend ) которое позволяет добавить исключения в общие правила доступа к данным. Если функция или класс названы другом ( friend ) класса Contact — они получают свободный доступ к защищенным или приватным данным.
Существует два основных правила дружбы — дружба не наследуется и не взаимна. Также, наличие “друзей” не изменяет уровень защищенности данных — приватные данные остаются приватными с исключением в виде “друга”.
#include using namespace std; class Contact < private: int mobile_number; // private variable int home_number; // private variable public: Contact() // constructor < mobile_number = 12345678; home_number = 87654321; >// Declaring a global 'friend' function friend void print_numbers( Contact some_contact ); >; void print_numbers( Contact some_contact ) < cout int main()
В этом примере, функция print_numbers() — обычная функция, не метод класса Contact . Объявление функции print_numbers() “другом” класса Contact — единственная причина по которой функция print_numbers() имеет доступ к приватным данным. Если убрать строку с определением друга — код не скомпилируется.
Примечание: друзьями лучше не злоупотреблять. Добавление друга стоит рассматривать как исключение, не как общую практику.
Нарушение инкапсуляции с Преобразованием типов и Указателями (Плохая практика)
Прежде всего, стоит заметить что использовать указатели и преобразование типов таким способом — плохая идея. Этот способ не гарантирует получения нужных данных. Он плохо читается и плохо поддерживается. Невзирая на это, он существует.
Си++ получил в наследство от Си множество инструментов, один из которых — преобразование типов ( typecasting ). По умолчанию, все переменные и методы в классе приватные. В то же время, стандартный уровень доступа к данным в структуре ( struct ) — публичный. Возможно создать структуру или полностью публичный класс в котором данные будут расположены идентично данным в классе Contact и используя преобразование типов получить доступ к приватным данным.
#include using namespace std; class Contact < private: int mobile_number; // private variable int home_number; // private variable public: Contact() // constructor < mobile_number = 12345678; home_number = 87654321; >void print_numbers() < cout >; struct Contact_struct < int mobile_number; int home_number; >; int main() < Contact Tony; Contact_struct * structured_Tony; Tony.print_numbers(); structured_Tony = (Contact_struct *) & Tony; structured_Tony->mobile_number = 20; structured_Tony->home_number = 30; Tony.print_numbers(); return 0; >
Приватные данные были прочитаны и изменены благодаря преобразованию типов
Инкапсуляция в Си
Традиционно считается что инкапсуляция — один из ключевых ООП принципов. Тем не менее, это не лимитирует использование этого принципа в процедурно-ориентированных языках. В Си, инкапсуляция используется давно, невзирая на отсутствие ключевых слов “приватный” и “публичный”.
Приватные переменные
В контексте инкапсуляции, все данные в Си могут быть рассмотрены как публичные по умолчанию. Уровень доступа к переменным в структурах ( struct ) может быть изменен на приватный если изолировать их определение от основной программы. Нужный эффект может быть достигнут при использовании отдельных заголовочных (header, .h) и исходных (source, .c) файлов.
В данном примере, структура была определена в отдельном исходном файле “private_var.c”. Поскольку инициализация структуры в Си требует выделения и освобождения памяти, несколько вспомогательных функций были добавлены.
#include "private_var.h" #include #include struct Contact < int mobile_number; int home_number; >; struct Contact * create_contact() < struct Contact * some_contact; some_contact = malloc(sizeof(struct Contact)); some_contact->mobile_number = 12345678; some_contact->home_number = 87654321; return( some_contact ); > void delete_contact( struct Contact * some_contact )
В соответствующем заголовочном файле "private_var.h", структура Contact была объявлена, но ее содержание осталось скрытым для основной программы.
#ifndef PRIVATE_VAR #define PRIVATE_VAR struct Contact; struct Contact * create_contact(); void delete_contact( struct Contact * some_contact ); #endif /* PRIVATE_VAR */
Таким образом, для “main.c” содержание структуры неизвестно и попытки прочитать или изменить приватные данные вызовут ошибку при компиляции.
#include "private_var.h" #include int main() < struct Contact * Tony; Tony = create_contact(); // printf( "Mobile number: %d\n", Tony->mobile_number); // will cause compile time error delete_contact( Tony ); return 0; >
Получение доступа к приватным переменным с Указателями
Преобразование типов может быть использовано для преодоления инкапсуляции в Си также как и в Си++, но данный подход уже был описан. Зная, что в структуре данные расположены в порядке их декларации, указатели и арифметика указателей подойдет для достижения цели.
Доступ к переменным в структуре ограничен. Тем не менее, спрятаны только переменные, не память в которой хранятся данные. Указатели можно рассматривать как ссылку на адрес памяти, и если эта память доступна программе — данные сохраненные в этой памяти можно прочитать и изменить. Если указатель назначен на память в которой структура хранит свои данные — их можно прочитать. Используя то же определение структуры (те же “.c” и “.h” файлы) и модифицированный “main.c” файл, ограничение доступа было преодолено.
#include "private_var.h" #include int main()
Данные в структуре были прочитаны и модифицированы
Приватные функции
Функции, будучи внешними ( extern ) по умолчанию, видимы во всей так называемой единице трансляции ( translation unit ). Другими словами, если несколько файлов скомпилированы вместе в один объектный файл, любой из этих файлов сможет получить доступ к любой функции из любого другого файла. Использование ключевого слова “статический” ( static ) при создании функции ограничит ее видимость до файла в котором она была определена.Следовательно, для обеспечения приватности функции необходимо выполнить несколько шагов:
- функция должна быть объявлена статической ( static ) либо в исходном файле (.c), либо в соответствующем заголовочном файле (.h);
- определение функции должно находиться в отдельном исходном файле.
В данном примере, в файле “private_funct.c”, была определена статическая функция print_numbers() . К слову, функция delete_contact() успешно вызывает print_numbers() поскольку они находятся в одном файле.
#include "private_funct.h" #include #include struct Contact < int mobile_number; int home_number; >; struct Contact * create_contact() < struct Contact * some_contact; some_contact = malloc(sizeof(struct Contact)); some_contact->mobile_number = 12345678; some_contact->home_number = 87654321; return( some_contact ); > static void print_numbers( struct Contact * some_contact ) < printf("Mobile number: %d, ", some_contact->mobile_number); printf("home number = %d\n", some_contact->home_number); > void delete_contact( struct Contact * some_contact )
В соответствующем заголовочном файле "private_funct.h", print_numbers() была декларирована как статическая функция.
#ifndef PRIVATE_FUNCT_H #define PRIVATE_FUNCT_H struct Contact; struct Contact * create_contact(); static void print_numbers( struct Contact * some_contact ); void delete_contact( struct Contact * my_points ); #endif /* PRIVATE_FUNCT_H */
Основная программа, “main.c”, успешно вызывает print_numbers() опосредовательно через delete_contact() , поскольку обе функции находятся в одном документе. Тем не менее, попытка вызвать print_numbers() из основной программы вызовет ошибку.
#include "private_funct.h" #include int main() < struct Contact * Tony; Tony = create_contact(); // print_numbers( Tony ); // will cause compile time error delete_contact( Tony ); return 0; >
Получение доступа к приватным функциям
Вызвать функцию print_numbers() из основной программы возможно. Для этого можно использовать ключевое слово goto или передавать в main указатель на приватную функцию. Оба способа требуют изменений либо в исходном файле “private_funct.c”, либо непосредственно в теле самой функции. Поскольку эти методы не обходят инкапсуляцию а отменяют её, они выходят за рамки этой статьи.
Заключение
Инкапсуляция существует за пределами ООП языков. Современные ООП языки делают использование инкапсуляции удобным и естественным. Существует множество способов обойти инкапсуляцию и избежание сомнительных практик поможет ее сохранить как в Си, так и в Си++.
- инкапсуляция
- oop concepts
- encapsulation