поле private объекта доступно
Приватные поля класса
Синтаксис
Примеры
Приватные статические поля
Приватные поля доступны в конструкторе класса изнутри самой декларации класса.
Ограничение статических переменных, вызываемых только статическими методами, все ещё сохраняется.
Приватные статические поля добавляются в конструктор класса во время обработки класса.
Существует ограничение по происхождению частных статических полей. Только класс, который определяет приватное статическое поле, может получить доступ к этому полю.
Это может привести к неожиданному поведению при использовании this.
Приватные поля экземпляров
Инкапсуляция обеспечивается языком. Обращение к # именам вне области видимости является синтаксической ошибкой.
Приватные методы
Приватные статические методы
Приватные статические методы
Как и их публичный эквивалент, приватные статические методы вызываются на самом классе, а не на экземплярах класса. Как и приватные статические поля, они доступны только изнутри объявления класса.
Приватные статические методы могут быть генераторами, асинхронными функциями и асинхронными функциями-генераторами.
Приватные методы экземпляров(instance)
Приватные методы экземпляров это методы, доступные у экземпляров класса, доступ к которым запрещён также, как у приватных полей класса.
Приватные методы экземпляров могут быть генератором, async, или функциями async генератора. Приватные геттеры и сеттеры также возможны:
JavaScript: Публичные и приватные поля классов
Несколько предложений расширяют существующий синтаксис классов в JavaScript новой функциональностью. Эта статья объясняет новый синтаксис публичных полей классов в V8 v7.2 и Chrome 72, а также грядущих приватных полей.
Вот пример кода, который создает экземпляр класса IncreasingCounter:
Отметим, что обращение к value выполняет некоторый код (вывод сообщения в лог) перед тем, как вернуть значение. Теперь спросите себя: как бы Вы реализовали этот класс на JavaScript?
Классы ES2015
Ниже пример того, как класс IncreasingCounter может быть реализован с помощью синтаксиса ES2015:
Класс предоставляет геттер value и метод для инкремента значения в прототипе. Более любопытно, что класс имеет конструктор, который инициирует свойство _count и выставляет его начальное значение в 0. Сейчас мы используем префикс подчеркивания, чтобы обозначить, что _count не должен использоваться напрямую вне класса, но это просто соглашение; в действительности это не приватное свойство, а эта семантика не определена в самом языке.
Публичные поля классов
Новый синтаксис для публичных полей позволяет упростить определение класса:
Свойство _count теперь лаконично объявлено в начале класса. Нам больше не нужен конструктор только для того, чтобы определить некоторые поля. Отлично!
Тем не менее, _count — все еще публичное свойство. А в этом конкретном примере мы хотим предотвратить обращение к этому полю напрямую.
Приватные поля классов
Именно здесь на помощь приходят приватные поля. Новый синтаксис для приватных полей схож с синтаксисом публичных полей, за исключением того, что Вы помечаете их как приватные, используя символ #. Вы можете думать, что # — это просто часть имени поля:
Приватные поля недоступны вне тела класса:
Статические свойства
Синтаксис полей классов может быть использован для создания публичных и приватных статических свойств и методов, как показано ниже:
Упрощение работы с подклассами
Преимущества нового синтаксиса полей классов становятся более очевидны при работе с подклассами, которые вводят дополнительные поля. Представим следующий базовый класс Animal:
Чтобы создать подкласс Cat, который добавляет новое свойство для экземпляра, ранее требовалось обратиться к super(), чтобы вызвать конструктор базового класса Animal перед тем, как создать это свойство:
Здесь много шаблонного кода только для того, чтобы указать, что коты не очень любят принимать ванну. К счастью, новый синтаксис полей классов избавляет от необходимости определения этого конструктора с неуклюжим вызовом super():
Итого
Публичные поля классов доступны, начиная с V8 v7.2 и Chrome 72. Скоро планируется релиз и приватных полей классов.
Чтение значений полей “private” из другого класса в Java
Узнайте, как получить доступ к закрытым полям другого класса и прочитать их значения с помощью API отражения Java.
1. Обзор
В этом кратком руководстве мы обсудим, как мы можем получить доступ к значению поля private из другого класса в Java.
2. Пример
Давайте определим пример класса Person с некоторыми частными полями:
3. Обеспечение Доступа к частным Полям
Чтобы сделать любое частное поле доступным, мы должны вызвать метод Field#setAccessible :
4. Доступ к закрытым примитивным полям
Мы можем получить доступ к полям private , которые являются примитивами, используя методы Field#getXXX .
4.1. Доступ к целочисленным полям
Также можно выполнить автобокс с примитивными типами:
То getXXX методы для примитивных типов данных также поддерживают расширение :
4.2. Доступ к Полям Плавающего Типа
4.3. Доступ к символьным Полям
4.4. Доступ к логическим полям
Аналогично, мы можем использовать метод getBoolean для доступа к полю boolean :
5. Доступ К закрытым Полям, Которые Являются Объектами
6. Исключения
6.1. Исключение незаконных аргументов
6.2. Исключение IllegalAccessException
6.3. Исключение NoSuchFieldException
6.4. Исключение NullPointerException
Наконец, как и следовало ожидать, JVM выдает исключение NullPointerException , если мы передаем имя поля как null :
7. Заключение
В этом уроке мы рассмотрели, как мы можем получить доступ к полям private класса в другом классе. Мы также видели исключения, которые может создавать JVM, и то, что их вызывает.
Модификаторы private, protected, public в Java
Модификаторы доступа private, protected, public ставятся перед именем класса, метода или поля и ограничивают доступ к нему. К локальным переменным модификаторы доступа не применимы.
Помимо этих трех явных модификаторов, есть еще так называемый default-модификатор, или модификатор по умолчанию, иначе говоря — это отсутствие всякого модификатора. Но это отсутствие тоже подразумевает свои правила доступа (видимость только внутри пакета).
Зачем нужны модификаторы доступа
Модификаторы доступа существуют для того, чтобы сделать код надежнее и защищеннее. Нужно максимально ограничивать видимость своих классов, методов и полей, и открывать их только там, где это действительно необходимо. Если вы откроете что-то лишнее, то другой разработчик (или даже вы сами) может по ошибке воспользоваться открытым классом/методом. Чем это чревато? А тем, что если в дальнейшем вы исправите свой код (отвечающий за внутреннюю реализацию, но открытый для пользования извне), то код другого программиста перестанет работать, так как опирается на ваш код. Открывать нужно только то, что вы планируете поддерживать и что будет стабильно работать (без изменения контракта) во всех последующих версиях. Все остальное — внутренняя реализация, которая касается только вас и может меняться, ее никто не должен использовать.
Правила доступа
На картинке показаны правила доступа к полю или методу с конкретным модификатором (последний столбец — про модули, они появились в Java 9):
Модификаторы доступа в Java
Модификатор private
Это самый ограничивающий модификатор. К полям и методам, помеченным ключевым словом private, можно обратиться только из того же класса, где они находятся.
Допустим у нас есть класс A с private полем privateVar и с private методом privateMethod(). Из класса A мы можем обращаться к полю, см. обращение this.privateVar:
А теперь попробуем обратиться к этому полю и методу из класса B, код не скомпилируется:
Вышеприведенный код выдает ошибки компиляции:
Иногда возникает вопрос
Может ли объект A получить доступ к private методам и полям другого объекта A?
Да, может. Обратите внимание на функцию main() из вышеприведенного класса A, в которой создается новый объект A и идет обращение к его методам и полям (не через this):
Как показано выше, мы обращаемся в методе main() к private полю privateVar другого объекта A, и это законно. Все потому, что в Java ограничения доступа применимы на уровне класса, а не на уровне объекта (не обязательно, чтоб обращение шло к тому же экземпляру, главное, что он в том же классе).
Можно ли переопределить private метод?
Нельзя, метод в подклассе не будет иметь никакого отношения к методу в суперклассе, так как private метод нигде не виден. Давайте попытаемся унаследоваться от класса A и «переопределить» private метод privateMethod():
Попробуем создать объект SubA и вызвать privateMethod() на A:
Как видите, срабатывает метод privateMethod() класса A, то есть переопределения не происходит:
Это происходит потому, что метод privateMethod() класса SubA не переопределяет метод privateMethod() класса A, а является независимым методом.
Модификатор default
Если мы не ставим никакого модификатора доступа перед методом, полем или классом, то этот метод/поле/класс видимы из кода только внутри пакета, в котором они находятся.
Давайте продемонстрируем это. Создадим снова класс A в пакете .def:
И создадим в этом же пакете класс B, из которого будем пытаться получить доступ к полям и методам A, как и раньше:
В этот раз код компилируется, все в порядке — доступ есть.
Если бы класс B находится в другом пакете (отличном от ru.sysout.accessmodifiers.def, в том числе в подпакете), то доступа бы не было.
Модификатор protected
Следующий по строгости — модификатор protected. Он также разрешает доступ к помеченным с помощью него полям и методам из кода внутри того же пакета. Но помимо этого, он дает поблажки подклассам, находящимся в другом пакете. Подкласс может обращаться к protected полям и методам суперкласса, даже если подкласс находится в другом пакете.
Снова создадим класс A с protected полем и методом:
Создадим в другом пакете класс C — наследника класса A и попытаемся получить доступ к полям методам класса A из класса C:
Как показано выше, обращение к полю и методу через this работает из другого пакета.
Также работает обращение ко всем другим экземплярам типа C, но к другим экземплярам типа A обращение не работает.
Модификатор public
Тут все просто — к полю и методу с модификатором public имеет доступ любой код. Давайте еще раз перепишем класс A:
И обратимся к его полю и методу из класса B, который находится в другом пакете и никакого отношения к классу A не имеет:
Все получилось, обращение работает.
Какой модификатор выбрать?
Правило выбора модификатора такое — надо по возможности выбирать:
То есть надо максимально ограничивать видимость члена класса. Сначала надо попробовать сделать все private, и при необходимости открывать видимость.
Мы рассмотрели тонкости использования модификаторов доступа. Код примеров можно посмотреть на GitHub.
Методы класса, сеттеры и геттеры, public, private, protected
На предыдущих занятиях мы с вами объявляли классы с набором переменных и указывали конструкторы. Пришло время узнать как добавлять функции в класс. По общепринятой терминологии, функции внутри класса называются методами и объявляются согласно следующему синтаксису:
[модификаторы] тип имя_метода([аргументы]) <
// тело метода
>
Например, запишем класс для представления прямоугольника и в нем пропишем метод для вычисления площади прямоугольника:
Здесь square – это обычная функция, объявленная внутри класса Rect и благодаря этому имеет доступ ко всем полям экземпляра этого класса. То есть, если в функции main() создать два таких объекта:
а, затем, вызвать метод square:
то первый вызов будет оперировать данными первого объекта r1, а второй – данными второго объекта r2:
В результате, при выводе в консоль:
мы увидим разные значения.
Метод, как и любая Java-функция, может иметь самый разный тип данных и любое число входных аргументов. Например, добавим еще один метод, который будет задавать координату верхнего левого угла:
Здесь тип метода void, т.к. он не возвращает никаких данных и прописаны два аргумента x, y. По аналогии можно добавлять в класс любое число самых разных методов.
Модификаторы доступа
Теперь, когда мы научились объявлять классы и создавать объекты, пришла пора поближе познакомиться с китом ООП по имени инкапсуляция.
В рамках этого занятия мы с вами подробно познакомимся с режимами public и private, а о модификаторе protected поговорим после знакомства с механизмом наследования классов.
Геттеры и сеттеры
Давайте вернемся к классу Rect и сделаем так, чтобы поля x1, y1, x2, y2 были скрыты от внешнего пользователя класса и были доступны только изнутри. Для этого нам нужно добавить модификатор private перед типом этих переменных:
Что в итоге изменилось? Смотрите, если теперь попытаться выполнить вот такую команду:
то возникнет ошибка доступа: к полю private нельзя обращаться напрямую через ссылку на объект, то есть, извне. А если убрать этот модификатор в классе Rect, то ошибки не будет. В этом отличие между закрытым (private) полем и общедоступным, который определяется модификатором по умолчанию. Также открытое (публичное) поле можно определять с помощью модификатора public:
Здесь также не будет ошибок, при обращении к переменной x1 напрямую через ссылку на экземпляр класса. В чем же тогда разница между модификатором по умолчанию и public? На уровне одного пакета, то есть, когда файлы программы находятся в одном каталоге, разницы нет. Но, когда два класса расположены в разных пакетах (разных каталогах), то поля с модификатором public будут доступны всюду, а без него (по умолчанию) только в пределах одного пакета (каталога). Во всем остальном они схожи.
Давайте вернем для полей x1, y1, x2, y2 модификатор private и будем полагать, что изменение координат возможно только через конструкторы и методы класса. Для этого определим еще один метод setCoords:
И, так как у этого метода не указан никакой модификатор, то используется модификатор по умолчанию и он может быть вызван напрямую через ссылку на класс:
То есть, мы сначала создаем объект, а потом определяем координаты прямоугольника. Причем, напрямую обратиться к полям x1, y1, x2, y2 нельзя, мы это можем сделать только через метод setCoords(). Такие методы получили название сеттеры. От префикса set, который обычно записывают в названиях таких методов. Но спрашивается: зачем все так усложнять и не использовать обращение к полям x1, y1, x2, y2 напрямую? Дело в том, что у сеттеров есть одно важное преимущество: они позволяют не только записывать данные в заданные поля, но и выполнять необходимую проверку на корректность переданных данных. Например, мы требуем от пользователя, чтобы координаты прямоугольника были положительными и варьировались в пределах:
Чтобы гарантировать наличие координат в этих пределах, в сеттере достаточно прописать такую проверку:
Добавим закрытый метод isCorrect для проверки корректности значения координаты:
И в самом начале класса пропишем константу MAX_COORD:
Здесь используется ключевое слово static, о котором мы еще будем говорить. Все, теперь мы уверены, что координаты прямоугольника будут находиться в указанных пределах. И это стало возможно использованию закрытых полей и публичному сеттеру setCoords. Также этот пример показывает, что методы класса также можно делать закрытыми (private) и функция isCorrect доступна только внутри класса и не доступна извне. Что вполне логично для нашей текущей реализации.
Нам здесь не хватает еще одного важного метода – для получения текущих координат прямоугольника. Чтобы сейчас не усложнять программу, я запишу четыре таких метода – по одному для каждого значения:
Здесь используется модификатор public для указания общедоступности этих методов, а также префикс get, от которого пошло название – геттеры. То есть, геттеры – это методы, служащие для получения информации из закрытых полей экземпляра класса.
Давайте воспользуемся этими методами и выведем значения координат в консоль:
Вот так реализуется механизм инкапсуляции в классах языка Java.
Подвиг 1. Объявить класс Person для описания сотрудника с полями: Ф.И.О., возраст, вес, номер разряда (целое число от 1 до 5). Прописать конструктор(ы), сеттер(ы) и геттер(ы) для записи значений по сотруднику и считывания данных. Обеспечить корректность представления данных: возраст и вес – положительные числа в пределах [30; 200]; разряд в диапазоне [1; 5]; в Ф.И.О. могут использоваться только буквенные символы, пробел и дефис. Создать несколько таких объектов и убедиться в их корректной работе.
для вычисления суммы и разности двух векторов класса Vec2. Эти методы не должны менять значений векторов, участвующих в операциях сложения и вычитания, а создавать новый с соответствующими значениями.
Подвиг 3. Объявить первый класс Book для представления книги с полями: название, автор, год издания, число страниц. Определить необходимые конструкторы, сеттеры и геттеры для записи и считывания данных (данные должны быть с очевидными ограничениями по диапазону значений). Объявить второй класс Lib, который будет хранить ссылки на книги Book в виде массива:
Book lib[] = new Book[MAX_BOOKS];
где MAX_BOOKS – константа, определяющая максимальное число книг. Обеспечить возможность добавления, удаления и вывода списка книг посредством методов класса Lib. Прямого доступа извне к массиву lib быть не должно.
Видео по теме
#11 Концепция объектно-ориентированного программирования (ООП)