Модификаторы Java

Язык Java предоставляет множество модификаторов, которые в основном делятся на следующие две категории:

  • Модификаторы доступа
  • Модификаторы, не связанные с доступом

Модификаторы используются для определения классов, методов или переменных и обычно размещаются в самом начале инструкции. Проиллюстрируем это на следующем примере:

public class ClassName { // ... } private boolean myFlag; static final double weeks = 9.5; protected static final int BOXWIDTH = 42; public static void main(String[] arguments) { //Тело метода }

Модификаторы управления доступом

В Java модификаторы управления доступом можно использовать для защиты доступа к классам, переменным, методам и конструкторам. Java поддерживает 4 различных уровня доступа.

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

  • private: виден в пределах того же класса. Применяется к: переменным, методам.Примечание: нельзя применять к классам (внешним классам)

  • public: виден всем классам. Применяется к: классам, интерфейсам, переменным, методам

  • protected: виден классам в том же пакете и всем подклассам. Применяется к: переменным, методам.Примечание: нельзя применять к классам (внешним классам)。

Уровни доступа можно проиллюстрировать следующей таблицей:

Управление доступом
Модификатор Текущий класс Тот же пакет Подклассы (тот же пакет) Подклассы (другой пакет) Другие пакеты
public Y Y Y Y Y
protected Y Y Y Y/N(Описание) N
default Y Y Y N N
private Y N N N N

Модификатор доступа по умолчанию — без использования каких-либо ключевых слов

Если в определении класса, переменной, метода или конструктора не указан модификатор доступа, то по умолчанию они будут иметь модификатор доступа по умолчанию.

Уровень доступа модификатора доступа по умолчанию — уровень пакета, то есть к нему могут обращаться только другие классы в том же пакете.

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

Пример

// MyClass.java class MyClass { //Модификатор доступа по умолчанию int x = 10; //Модификатор доступа по умолчанию void display() { //Модификатор доступа по умолчанию System.out.println("Значение x равно: " + x); } } // MyOtherClass.java class MyOtherClass { public static void main(String[] args) { MyClass obj = new MyClass(); obj.display(); //Обращение к переменным и методам с модификатором доступа по умолчанию в MyClass } }

В приведённом выше примере класс MyClass, его переменная-член x и метод display() определены с использованием модификатора доступа по умолчанию. Класс MyOtherClass находится в том же пакете, поэтому он может обращаться к классу MyClass и его переменным-членам и методам.

Модификатор доступа private - private

Модификатор доступа private — самый строгий уровень доступа, поэтому методы, переменные и конструкторы, объявленные какprivateметоды, переменные и конструкторы могут быть доступны только классу-владельцу, а классы и интерфейсы не могут быть объявлены какprivate。

Переменные, объявленные с типом доступа private, могут быть доступны внешним классам только через public getter-методы в классе.

Использование модификатора доступа private в основном предназначено для скрытия деталей реализации класса и защиты данных класса.

Следующий класс использует модификатор доступа private:

public class Logger { private String format; public String getFormat() { return this.format; } public void setFormat(String format) { this.format = format; } }

В примере переменная format в классе Logger является private-переменной, поэтому другие классы не могут напрямую получить или задать значение этой переменной. Чтобы позволить другим классам управлять переменной, определены два public-метода: getFormat() (возвращает значение format) и setFormat(String) (устанавливает значение format)

Модификатор доступа public - public

Классы, методы, конструкторы и интерфейсы, объявленные как public, доступны любому другому классу.

Если несколько public-классов, обращающихся друг к другу, распределены по разным пакетам, необходимо импортировать пакет, содержащий соответствующие public-классы. Благодаря наследованию классов все public-методы и переменные класса могут наследоваться его подклассами.

В следующей функции используется модификатор доступа public:

public static void main(String[] аргументы) { // ... }

Метод main() программы на Java должен быть объявлен как public, иначе интерпретатор Java не сможет запустить класс.

Модификатор доступа protected - protected

protected нужно проанализировать и объяснить с двух следующих точек зрения:

  • Подкласс и базовый класс находятся в одном пакете:: Переменные, методы и конструкторы, объявленные как protected, могут быть доступны любому другому классу в том же пакете;

  • Подкласс и базовый класс не находятся в одном пакете:: Тогда в подклассе экземпляр подкласса может получать доступ к protected-методам, унаследованным от базового класса, но не может получать доступ к protected-методам экземпляра базового класса.

protected может модифицировать элементы данных, конструкторы и методы.Не может модифицировать классы (кроме внутренних классов)。

Интерфейсы и их переменные-члены и методы не могут быть объявлены как protected. Иллюстрацию можно увидеть ниже:

Подклассы могут получать доступ к методам и переменным, объявленным с модификатором protected, таким образом предотвращая использование этих методов и переменных несвязанными классами.

Следующий родительский класс использует модификатор доступа protected, а подкласс переопределяет метод openSpeaker() родительского класса.

class AudioPlayer { protected boolean openSpeaker(Speaker sp) { //Детали реализации } } class StreamingAudioPlayer extends AudioPlayer { protected boolean openSpeaker(Speaker sp) { //Детали реализации } }

Если метод openSpeaker() объявлен как private, то ни один класс, кроме AudioPlayer, не сможет получить доступ к этому методу.

Если openSpeaker() объявлен как public, то все классы смогут получить доступ к этому методу.

Если мы хотим, чтобы метод был виден только подклассам его класса, объявите метод как protected.

protected — один из наиболее сложных для понимания модификаторов доступа к членам класса Java. Для получения дополнительных сведений см.Подробное объяснение ключевого слова protected в Java。

Контроль доступа и наследование

Обратите внимание на следующие правила наследования методов:

  • Методы, объявленные как public в родительском классе, также должны быть public в подклассе.

  • Методы, объявленные как protected в родительском классе, должны быть объявлены как protected или public в подклассе и не могут быть объявлены как private.

  • Методы, объявленные как private в родительском классе, не могут быть унаследованы подклассом.


Модификаторы, не связанные с доступом

Для реализации некоторых других возможностей Java также предоставляет множество модификаторов, не связанных с доступом.

Модификатор static используется для изменения методов класса и переменных класса.

Модификатор final используется для изменения классов, методов и переменных. Классы, изменённые с помощью final, не могут быть унаследованы, методы, изменённые с помощью final, не могут быть переопределены классами-наследниками, а переменные, изменённые с помощью final, являются константами и не могут быть изменены.

Модификатор abstract используется для создания абстрактных классов и абстрактных методов.

Модификаторы synchronized и volatile в основном используются в многопоточном программировании.

Модификатор static

  • Статические переменные:

    Ключевое слово static используется для объявления статических переменных, независимых от объектов. Независимо от того, сколько объектов создаёт класс, его статическая переменная имеет только одну копию. Статические переменные также называют переменными класса. Локальные переменные не могут быть объявлены как статические переменные.

  • Статические методы:

    Ключевое слово static используется для объявления статических методов, которые не зависят от объектов. Статические методы не могут использовать нестатические переменные класса. Статические методы получают данные из списка параметров, а затем вычисляют данные.

Доступ к переменным и методам класса можно осуществлять с помощьюclassname.variablenameиclassname.methodname— метод доступа.

Как показано в примере ниже, модификатор static используется для создания методов класса и переменных класса.

public class InstanceCounter { private static int numInstances = 0; protected static int getCount() { return numInstances; } private static void addInstance() { numInstances++; } InstanceCounter() { InstanceCounter.addInstance(); } public static void main(String[] arguments) { System.out.println("Начиная с " + InstanceCounter.getCount() + " экземпляров"); for (int i = 0; i < 500; ++i){ new InstanceCounter(); } System.out.println("Создано " + InstanceCounter.getCount() + " экземпляров"); } }

Вывод при запуске приведённого выше примера выглядит следующим образом:

Starting with 0 instances
Created 500 instances

Модификатор final

переменные final:

final означает "последний" или "окончательный". После присваивания переменной значения её нельзя переприсвоить. Переменные экземпляра, изменённые с помощью final, должны явно задавать начальное значение.

Модификатор final обычно используется вместе с модификатором static для создания констант класса.

Пример

public class Test{ final int value = 10; //Ниже приведён пример объявления констант public static final int BOXWIDTH = 6; static final String TITLE = "Менеджер"; public void changeValue(){ value = 12; //выведет ошибку } }

final-методы

final-методы в родительском классе могут наследоваться подклассами, но не могут быть переопределены подклассами.

Основная цель объявления final-метода — предотвратить изменение содержимого метода.

Как показано ниже, объявите метод с помощью модификатора final.

public class Test{ public final void changeName(){ //Тело метода } }

final-класс

final-класс не может быть унаследован, и никакой класс не может наследовать какие-либо характеристики final-класса.

Пример

public final class Test { //Тело класса }

Модификатор abstract

Абстрактный класс:

Абстрактный класс нельзя использовать для создания объектов; единственная цель объявления абстрактного класса — расширить класс в будущем.

Класс не может быть одновременно модифицирован как abstract и final. Если класс содержит абстрактные методы, то класс должен быть объявлен как абстрактный класс, иначе возникнет ошибка компиляции.

Абстрактный класс может содержать как абстрактные, так и неабстрактные методы.

Пример

abstract class Caravan{ private double price; private String model; private String year; public abstract void goFast(); //Абстрактный метод public abstract void changeColor(); }

Абстрактный метод

Абстрактный метод — это метод без какой-либо реализации; конкретная реализация предоставляется подклассами.

Абстрактные методы нельзя объявлять как final или static.

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

Если класс содержит несколько абстрактных методов, то класс должен быть объявлен как абстрактный класс. Абстрактный класс не обязан содержать абстрактные методы.

Объявление абстрактного метода заканчивается точкой с запятой, например:public abstract sample();。

Пример

public abstract class SuperClass{ abstract void m(); //Абстрактный метод } class SubClass extends SuperClass{ //Реализация абстрактных методов void m(){ ......... } }

synchronized Модификатор

Метод, объявленный с ключевым словом synchronized, может быть доступен только одному потоку одновременно. Модификатор synchronized можно применять к четырём модификаторам доступа.

Пример

public synchronized void showDetails(){ ....... }

transient Модификатор

Когда сериализованный объект содержит переменные экземпляра, изменённые с помощью transient, виртуальная машина Java (JVM) пропускает эту конкретную переменную.

Этот модификатор включается в инструкцию, определяющую переменную, и используется для предварительной обработки типов данных классов и переменных.

Пример

public transient int limit = 55; //Не сохраняется public int b; //Persisted

Модификатор volatile

Переменная-член, модифицированная volatile, заставляет потоки перечитывать значение этой переменной-члена из разделяемой памяти при каждом обращении к ней. Более того, когда переменная-член изменяется, потоки вынуждены записывать изменённое значение обратно в разделяемую память. Таким образом, в любой момент два разных потока всегда видят одно и то же значение для данной переменной-члена.

Ссылка на объект volatile может быть null.

Пример

public class MyRunnable implements Runnable { private volatile boolean active; public void run() { active = true; while (active) //Первая строка { //код } } public void stop() { active = false; //Вторая строка } }

Обычно в одном потоке вызывается метод run() (в потоке, запущенном Runnable), а в другом потоке вызывается метод stop(). ЕслиПервая строкаиспользуется значение active в буфере, тоВторая строкакогда значение active равно false, цикл не остановится.

Но в приведённом выше коде мы использовали volatile для изменения active, поэтому цикл остановится.

Другие расширения