Что означает модификатор public
Модификаторы 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.
8. Java — Модификаторы доступа и класса
Модификаторы — ключевые слова, которые Вы добавляете при инициализации для изменения значений. Язык Java имеет широкий спектр модификаторов, основные из них:
Чтобы использовать модификатор в Java, нужно включить его ключевое слово в определение класса, метода или переменной. Модификатор должен быть впереди остальной части оператора, как показано в следующих примерах:
Содержание
Модификаторы доступа
Java предоставляет ряд модификаторов доступа, чтобы задать уровни доступа для классов, переменных, методов и конструкторов. Существует четыре доступа:
Модификатор доступа по умолчанию — без ключевого слова
Модификатор доступа по умолчанию — означает, что мы явно не объявляем модификатор доступа в Java для класса, поля, метода и т.д.
Переменная или метод, объявленные без модификатора контроля доступа доступны для любого другого класса в том же пакете. Поля в интерфейсе неявно являются public, static, final, а методы в интерфейсе по умолчанию являются public.
Пример
Переменные и методы могут быть объявлены в Java без каких-либо модификаторов, как показано в следующем примере:
Модификатор доступа private
Модификатор private — методы, переменные и конструкторы, которые объявлены как private в Java могут быть доступны только в пределах самого объявленного класса.
Модификатор доступа private является наиболее ограничивающим уровенем доступа. Класс и интерфейсы не могут быть private.
Переменные, объявленные как private, могут быть доступны вне класса, если получающие их открытые (public) методы присутствуют в классе (ниже смотрите пример и пояснения).
Использование модификатора private в Java является основным способом, чтобы скрыть данные.
Пример
Следующий класс использует контроль доступа private:
Здесь переменная format класса Logger является private, так что нет никакого способа для других классов, чтобы получить и установить её значение напрямую.
Таким образом, чтобы эта переменная была доступна для всего, мы определили два открытых (public) метода: getFormat(), который возвращает значение format, и setFormat(String), который устанавливает её значение.
Модификатор доступа public
Модификатор public — класс, метод, конструктор, интерфейс и т.д. объявленные как public могут быть доступны из любого другого класса. Поэтому поля, методы, блоки, объявленные внутри public класса могут быть доступны из любого класса, принадлежащего к «вселенной» Java.
Тем не менее, если к public классу в другом пакете мы пытаемся получить доступ, то public класс приходится импортировать.
Благодаря наследованию классов, в Java все публичные (public) методы и переменные класса наследуются его подклассами.
Пример
Следующая функция использует контроль доступа public:
Метод main() должен быть публичным (public). В противном случае, он не может быть вызван с помощью java-интерпретатора, чтобы запустить класс.
Модификатор доступа protected
Модификатор protected — переменные, методы и конструкторы, которые объявляются как protected в суперклассе, могут быть доступны только для подклассов в другом пакете или для любого класса в пакете класса protected.
Модификатор доступа protected в Java не может быть применен к классу и интерфейсам. Методы и поля могут быть объявлены как protected, однако методы и поля в интерфейсе не могут быть объявлены как protected.
Доступ protected дает подклассу возможность использовать вспомогательный метод или переменную, предотвращая неродственный класс от попыток использовать их.
Пример
Следующий родительский класс использует контроля доступа protected, чтобы его дочерний класс переопределил метод openSpeaker():
При этом, если мы определим метод openSpeaker() как protected, то он не будет доступен из любого другого класса, кроме AudioPlayer. Если мы определим его как public, то он станет доступным всем. Но наше намерение состоит в том, чтобы раскрыть этот метод только подклассу, вот почему мы использовали модификатор protected.
Правила контроля доступа и наследования
Следующие правила в Java применяются для унаследованных методов:
Модификаторы класса, метода, переменной и потока, используемые не для доступа
Java предоставляет ряд модификаторов не для доступа, а для реализации многих других функциональных возможностей:
Модификатор static
Модификатор static — применяется для создания методов и переменных класса.
Переменные static
Ключевое слово static используется для создания переменных, которые будут существовать независимо от каких-либо экземпляров, созданных для класса. Только одна копия переменной static в Java существует вне зависимости от количества экземпляров класса.
Статические переменные также известны как переменные класса. В Java локальные переменные не могут быть объявлены статическими (static).
Методы static
Ключевое слово static используется для создания методов, которые будут существовать независимо от каких-либо экземпляров, созданных для класса.
В Java статические методы или методы static не используют какие-либо переменные экземпляра любого объекта класса, они определены. Методы static принимают все данные из параметров и что-то из этих параметров вычисляется без ссылки на переменные.
Переменные и методы класса могут быть доступны с использованием имени класса, за которым следует точка и имя переменной или метода.
Пример
Модификатор static в Java используется для создания методов классов и переменных, как показано в следующем примере:
Будет получен следующий результат:
Модификатор final
Модификатор final — используется для завершения реализации классов, методов и переменных.
Переменные final
Переменная final может быть инициализирована только один раз. Ссылочная переменная, объявленная как final, никогда не может быть назначен для обозначения другого объекта.
Однако данные внутри объекта могут быть изменены. Таким образом, состояние объекта может быть изменено, но не ссылки.
С переменными в Java модификатор final часто используется со static, чтобы сделать константой переменную класса.
Пример
Методы final
Метод final не может быть переопределен любым подклассом. Как упоминалось ранее, в Java модификатор final предотвращает метод от изменений в подклассе.
Главным намерение сделать метод final будет то, что содержание метода не должно быть изменено стороне.
Пример
Объявление метода, использующего модификатор final в объявление класса, показано в следующем примере:
Класс final
Основная цель в Java использования класса объявленного в качестве final заключается в предотвращении класс от быть подклассом. Если класс помечается как final, то ни один класс не может наследовать любую функцию из класса final.
Пример
Модификатор abstract
Модификатор abstract — используется для создания абстрактных классов и методов.
Класс abstract
Класс abstract не может создать экземпляр. Если класс объявлен как abstract, то единственная цель для него быть расширенным.
Класс не может быть одновременно abstract и final, так как класс final не может быть расширенным. Если класс содержит абстрактные методы, то он должен быть объявлен как abstract. В противном случае будет сгенерирована ошибка компиляции.
Класс abstract может содержать как абстрактные методы, а также и обычные.
Пример
Метод abstract
Метод abstract является методом, объявленным с любой реализацией. Тело метода (реализация) обеспечивается подклассом. Методы abstract никогда не могут быть final или strict.
Любой класс, который расширяет абстрактный класс должен реализовать все абстрактные методы суперкласса, если подкласс не является абстрактным классом.
Если класс в Java содержит один или несколько абстрактных методов, то класс должен быть объявлен как abstract. Абстрактный класс не обязан содержать абстрактные методы.
Абстрактный метод заканчивается точкой с запятой. Пример: public abstract sample();
Пример
Модификатор synchronized
Модификатор synchronized — используются в Java для потоков.
Ключевое слово synchronized используется для указания того, что метод может быть доступен только одним потоком одновременно. В Java модификатор synchronized может быть применен с любым из четырех модификаторов уровня доступа.
Пример
Модификатор transient
Переменная экземпляра отмеченная как transient указывает виртуальной машине Java (JVM), чтобы пропустить определённую переменную при сериализации объекта, содержащего её.
Этот модификатор включён в оператор, что создает переменную, предшествующего класса или типа данных переменной.
Пример
Модификатор volatile
Модификатор volatile — используются в Java для потоков.
В Java модификатор volatile используется, чтобы позволить знать JVM, что поток доступа к переменной всегда должен объединять свою собственную копию переменной с главной копией в памяти.
Доступ к переменной volatile синхронизирует все кэшированные скопированные переменные в оперативной памяти. Volatile может быть применен только к переменным экземпляра, которые имеют тип объект или private. Ссылка на объект volatile может быть null.
Пример
Как правило, run() вызывается в одном потоке (впервые начинаете использовать Runnable в Java), а stop() вызывается из другого потока. Если в линии 1 используется кэшированное значение active, то цикл не может остановиться, пока Вы не установите active false в линии 2.
В следующем уроке обсудим основные операторы, используемые в языке Java. Этот раздел даст Вам обзор того, как можно использовать их во время разработки приложения.
ООП. Часть 3. Модификаторы доступа, инкапсуляция
Классы, методы и поля не всегда могут постоять за себя. Рассказываем, как быть защитником в объектно-ориентированном программировании.
Инкапсуляция (от лат. in capsule — в оболочке) — это заключение данных и функционала в оболочку. В объектно-ориентированном программировании в роли оболочки выступают классы: они не только собирают переменные и методы в одном месте, но и защищают их от вмешательства извне (сокрытие).
Важно! Инкапсуляция не является сокрытием. Сокрытие — это часть инкапсуляции.
Это может быть достаточно сложной концепцией для понимания. Поэтому, чтобы быстрее разобраться, в этой статье мы рассмотрим инкапсуляцию на примере уровней доступа.
Все статьи про ООП
Пишет о разработке сайтов, в свободное время создает игры. Мечтает открыть свою студию и выпускать ламповые RPG.
Модификатор доступа public
Первый уровень, с которым сталкиваются все разработчики, — публичный. Чтобы сказать компилятору, что что-то должно быть доступно для всех, используется ключевое слово public.
Рассмотрим на примере класса Item:
Объявив экземпляр этого класса, можно обращаться к любым его полям в любом месте программы, где доступен сам объект (речь о локальных и глобальных переменных).
Так как поля публичные, в консоли они отобразятся без каких-либо проблем:
Это удобно, потому что можно в любой момент выполнить любое действие над объектом и его данными. Но в этом и кроется проблема: объект становится беззащитен перед любым вмешательством. Например, можно просто взять и изменить его цену:
Из-за того, что поле публичное, оно изменится:
Это плохо по нескольким причинам:
Разумеется, это не лучшее, что может случиться с приложением.
Модификатор доступа private
Чтобы поля были защищены от вмешательства, используется ключевое слово private — оно делает члены класса доступными только внутри самого класса.
Теперь эти поля нельзя будет изменить нигде, кроме как в методах этого класса. Но и получить их значение извне тоже не получится, а попытка вывести приведёт к ошибке:
Есть два способа сделать поле доступным только для чтения. Первый — использовать ключевое слово readonly, но оно запрещает менять значение вообще.
Второй способ заключается в том, чтобы передавать значения приватного члена класса через публичный. Например, с помощью методов:
К такой практике прибегают Java-разработчики, но в C# есть более элегантный способ — свойства.
Теперь, чтобы получить данные, нужно обратиться к свойству, а не к полю:
Преимущество этого в том, что можно разрешить получать данные, но запретить их менять. То есть прописать только геттер:
Обратите внимание, что можно просто написать set; или get; если не требуется дополнительная логика. Это сработает, если у поля и свойства одинаковые имена и если это примитивный тип (int, float, char, double и другие). Со ссылочными типами (объекты и строки) это не работает.
Также можно менять логику работы со значением:
Здесь поле будет изменено только в том случае, если ему пытаются указать значение, которое выше нуля.
То есть если запустить вот такой код:
Также можно создавать свойства без поля:
Это свойство вернёт true, если цена выше 5000, и false, если ниже.
Ключевое слово private можно также применять и к методам. Это делает их доступными только внутри класса.
Также приватным можно сделать сам класс, если он находится внутри другого класса:
Модификатор доступа internal
Иногда нужно сделать компонент доступным только внутри одного файла — например, в Program.cs, Item.cs или любом другом. Для этого используется ключевое слово internal.
Класс Backpack можно будет использовать только внутри файла Program.cs, и попытка объявить его внутри другого файла приведёт к ошибке.
Ключевое слово static
Статичность относится не совсем к уровням доступа, но тоже помогает заключить реализацию функционала в оболочку класса. Статичность позволяет обращаться к методам или полям, не создавая объект.
Метод Sum () используется в классе Program, хотя экземпляр класса Calc не создавался. При этом можно сделать статичным как отдельный метод или свойство, так и весь класс. В этом случае все поля и методы тоже должны быть статичными.
Это может быть нужно, чтобы создать набор инструментов, который будет использоваться в других частях программы. Хороший пример — класс Console, который тоже является статичным.
Другой пример — класс Math. Его можно использовать, чтобы выполнять различные математические операции (получение квадратного корня, модуляция, получение синуса, косинуса и так далее). У него много методов, а также он хранит различные константы вроде числа пи.
Домашнее задание
Напишите класс GameObject, в котором будут храниться координаты объекта. Координаты должны быть доступны для чтения, а их изменение должно происходить в методе Move ().
Заключение
Есть и другие ключевые слова:
Они будут рассмотрены в статье о наследовании.
Большая часть курса «Профессия С#-разработчик» посвящена именно ООП —
не только теории, но и практике. Вы научитесь писать программы, подбирая нужные инструменты — от инкапсуляции до полиморфизма. К концу курса у вас будет портфолио из нескольких проектов, а также все знания и навыки, которые нужны для получения первой работы.
Модификаторы методов
1. Модификаторы доступа
Эти «модификаторы доступа» позволяют ограничивать доступ к методу из других классов.
Всего таких модификаторов 3, а типов доступа к методу — 4, ведь отсутствие модификатора доступа тоже что-то значит.
Доступ из. | ||||
---|---|---|---|---|
Модификаторы | Любого класса | Класса-наследника | Своего пакета | Своего класса |
public | Есть | Есть | Есть | Есть |
protected | Нет | Есть | Есть | Есть |
без модификатора | Нет | Нет | Есть | Есть |
private | Нет | Нет | Нет | Есть |
3. Без модификатора (модификатор по умолчанию).
Зачем нужны модификаторы доступа?
Все дело в больших проектах, которые пишут десятки и сотни программистов одновременно.
Иногда бывают ситуации, когда программист хочет разделить слишком большой метод своего класса на части и вынести часть кода во вспомогательные методы. Но вместе с тем он не хочет, чтобы другие программисты вызывали эти вспомогательные методы, т.к. тогда код его класса может работать неправильно.
Вот и придумали такие модификаторы доступа. Пометил вспомогательный метод словом private, и никакой код кроме вашего класса не сможет увидеть ваш вспомогательный метод.
Модификаторы доступа, переопределение методов, реализация абстрактных методов
— Я расскажу тебе про « модификаторы доступа ». Когда-то я уже рассказывал про них, но повторение – мать учения.
Ты можешь управлять доступом (видимостью) методов и переменных твоего класса из других классов. Модификатор доступа отвечает на вопрос «Кто может обращаться к данному методу/переменной?». Каждому методу или переменной можно указывать только один модификатор.
1) Модификатор « public ».
2) Модификатор « private ».
3) «Модификатор « по умолчанию ».
Если переменная или метод не помечены никаким модификатором, то считается, что они помечены «модификатором по умолчанию». Переменные и методы с таким модификатором видны всем классам пакета, в котором они объявлены, и только им. Этот модификатор еще называют « package » или « package private », намекая, что доступ к переменным и методам открыт для всего пакета, в котором находится их класс
4) Модификатор « protected ».
Таблица с пояснением:
Тип видимости | Ключевое слово | Доступ | |||
---|---|---|---|---|---|
Свой класс | Свой пакет | Класс — наследник | Все классы | ||
Закрытый | private | Есть | Нет | Нет | Нет |
Пакет | (нет модификатора) | Есть | Есть | Нет | Нет |
Защищенный | protected | Есть | Есть | Есть | Нет |
Открытый | public | Есть | Есть | Есть | Есть |
Есть способ, чтобы легко запомнить эту таблицу. Представь себе, что ты составляешь завещание и делишь все вещи на четыре категории. Кто может пользоваться твоими вещами?
Кто имеет доступ | Модификатор | Пример |
---|---|---|
Только я сам | private | Личный дневник |
Семья | (нет модификатора) | Семейные фотографии |
Семья и наследники | protected | Фамильное поместье |
Все | public | Мемуары |
— Если представить, что классы, лежащие в одном пакете, – это одна семья, то очень даже похоже.
— Хочу также рассказать тебе несколько интересных нюансов насчет переопределения методов.
1) Неявная реализация абстрактного метода.
Допустим, у тебя есть код:
И ты решил унаследовать от него класс тигр и добавить новому классу интерфейс
Если ты просто реализуешь все недостающие методы, которые тебе подскажет Intellij IDEA, то можешь потом долго искать ошибку.
Оказывается, что в классе Tiger есть унаследованный от Cat метод getName, который и будет считаться реализацией метода getName для интерфейса HasName.
— Не вижу в этом ничего страшного.
— Это не очень плохо, это скорее потенциальное место для ошибок.
Но может быть еще хуже:
Оказывается, ты не всегда можешь унаследоваться от нескольких интерфейсов. Вернее унаследоваться можешь, а вот корректно их реализовать – нет. Посмотри на пример, оба интерфейса требуют, чтобы ты реализовал метод getValue(), и не ясно, что он должен возвращать: вес(weight) или размер(size). Это довольно-таки неприятная вещь, если тебе придется с ней столкнуться.
— Да, согласен. Хочешь реализовать метод, а не можешь. Вдруг ты уже унаследовал метод с таким же именем от базового класса. Обломись.
— Но есть и приятные новости.
2) Расширение видимости. При переопределении типа разрешается расширить видимость метода. Вот как это выглядит:
Если бы этого сделать было нельзя, всегда можно было бы объявить метод в Tiger:
public String getPublicName()
<
super.getName(); //вызов protected метода
>
— Не уверен, что понял полностью, но то, что так можно делать, запомню.
3) Сужение типа результата.
«Старый код» как работал так и работает.
Если бы этого сделать было нельзя, всегда можно было бы объявить метод в Tiger:
public Tiger getMyTigerParent()
<
return (Tiger) this.parent;
>
Т.е. ни о каком нарушении безопасности и/или контроля приведения типов нет речи.
Объекты Tiger можно смело хранить как в переменных класса Tiger, так и в переменных класса Cat.
— Ага. Я понял. Надо при переопределении методов беспокоиться о том, как все это будет работать, если мы передадим наши объекты в код, который умеет обращаться только с базовым классом, и ничего о нашем классе не знает.
— Именно! Тогда вопрос на засыпку, почему нельзя расширить тип результата при переопределении метода?
— Это же очевидно, тогда перестанет работать код в базовом классе:
Код на Java | Пояснение проблемы |
---|---|
Мы переопределили метод getMyParent и расширили тип его результата. Тут все отлично. | |
Тогда у нас перестанет работать этот код. Метод getMyParent может вернуть любой объект типа Object, т.к. на самом деле он вызывается у объекта типа Tiger. А у нас нет проверки перед присваиванием. Тогда вполне возможно, что переменная myParent типа Cat будет хранить ссылку на строку. |
— Отличный пример, Амиго!
В Java перед вызовом метода не проверяется, есть ли такой метод у объекта или нет. Все проверки происходят во время выполнения. И [гипотетический] вызов отсутствующего метода, скорее всего, приведет к тому, что программа начнет выполнять байт-код там, где его нет. Это, в конце концов, приведет к фатальной ошибке, и операционная система принудительно закроет программу.