Какие модификаторы доступа существуют в java. Модификаторы доступа. Модификаторы strictfp, transient, volatile, synchronized, native

Последнее обновление: 20.04.2018

Все члены класса в языке 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; public Person(String name, int age){ this.name = name; this.age = 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), так как с их помощью мы получаем значение поля.

Причем в эти методы мы можем вложить дополнительную логику. Например, в данном случае при изменении возраста производится проверка, насколько соответствует новое значение допустимому диапазону.

Существует возможность управлять тем, какие части программы могут получать доступ к членам класса. Управление доступом позволяет предотвращать злоупотребления. Не всегда желательно, чтобы имелся доступ к отдельной переменной или методу класса, которые должны работать только внутри самого класса.

Способ доступа определяется модификатором доступа , который добавляется при объявлении. Всего их четыре:

  • private (закрытый)
  • public (открытый)
  • protected (защищённый)
  • доступ по умолчанию, когда никакой модификатор не присутствует

Примеры объявление модификаторов (он всегда должен быть первым):

Public int i; private double j, k; private int createMethod(int a) {...}; public class Cat{}

Как видите, модификатор применим к переменной, методу, классу.

public

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

Предположим, что класс объявлен как public , и в нём имеются два метода. Один private , второй - public . У вас будет доступ к классу и ко второму методу, но не к первому, несмотря на то, что сам класс открыт.

private

Ключевое слово private означает, что доступ к члену класса не предоставляется никому, кроме методов этого класса. Другие классы того же пакета также не могут обращаться к private-членам.

Все вспомогательные методы классов стоит объявить как private , чтобы предотвратить их случайные вызовы в пакете. Тоже относится и к private-полям внутри класса.

protected

Ключевое слово protected связано с понятием наследования, при котором к уже существующему классу (базовому) добавляются новые члены, причем исходная реализация остается неизменной. Также можно изменять поведение уже существующих членов класса. Для создания нового класса на базе существующего используется ключевое слово extends .

Если при создании нового пакета используется наследование от класса, находящемся в другом пакете, новый класс получает доступ только к открытым (public) членам из исходного пакета. Иногда создателю базового класса необходимо предоставить доступ к конкретному методу производным классам, но закрыть его от всех остальных. В этих случаях используется ключевое слово protected . Спецификатор protected также предоставляет доступ в пределах пакета, т.е. члены с этим спецификатором доступны для других классов из того же пакета.

По умолчанию при отсутствии модификатора члена класса считается открытым внутри своего собственного пакета, но не доступен для кода, расположенного вне этого пакета. Если все классы вашего проекта находятся в одном пакете, то по существу переменная без модификатора является открытой (public ).

Рассмотрим вымышленный класс SillySensor

Public class SillySensor { private int sensorData; public SillySensor() { sensorData = 0; } private void calibrate(int iSeed) { // код для калибровки } protected void seedCalibration(int iSeed) { calibrate(iSeed); } public int getSensorData() { // Check sensor here return sensorData; } }

Класс объявлен как public и доступен в других классах. У класса есть переменная sensorData , которая доступна только в своём классе (private). Конструктор доступен в других классах (public ). Метод calibrate() работает только внутри класса (private ). Метод seedCalibration() доступен в своем классе или в подклассе (protected ). Метод getSensorData() доступен в других классах (public ).

Привет! В сегодняшней лекции мы познакомимся с понятием «модификаторы доступа » и рассмотрим примеры работы с ними. Хотя слово «познакомимся» будет не совсем правильным: с большинством из них ты уже знаком по предыдущим лекциям. На всякий случай освежим в памяти главное. Модификаторы доступа - это чаще всего ключевые слова, которые регулируют уровень доступа к разным частям твоего кода. Почему «чаще всего»? Потому что один из них установлен по умолчанию и не обозначается ключевым словом:) Всего в Java есть четыре модификатора доступа. Перечислим их в порядке от самых строгих до самых «мягких»:

  • private;
  • protected;
  • default (package visible);
  • public.
Давай рассмотрим каждый из них, определимся, когда они могут нам пригодиться и приведем примеры:)

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


Private - наиболее строгий модификатор доступа. Он ограничивает видимость данных и методов пределами одного класса. Этот модификатор тебе известен из лекции про геттеры и сеттеры. Помнишь этот пример? public class Cat { public String name; public int age; public int weight; public Cat (String name, int age, int weight) { this . name = name; this . age = age; this . weight = weight; } public Cat () { } public void sayMeow () { System. out. println ("Мяу!" ) ; } } public class Main { public static void main (String args) { Cat cat = new Cat () ; cat. name = "" ; cat. age = - 1000 ; cat. weight = 0 ; } } Мы рассматривали его в одной из статей раньше. Здесь мы допустили серьезную ошибку: открыли наши данные, в результате чего коллеги-программисты получили доступ напрямую к полям класса и изменению их значения. Более того, эти значения присваивались без проверок, в результате чего в нашей программе можно создать кота с возрастом -1000 лет, именем «» и весом 0. Для решения этой проблемы мы использовали геттеры и сеттеры , а также ограничили доступ к данным с помощью модификатора private . public class Cat { private String name; private int age; private int weight; public Cat (String name, int age, int weight) { this . name = name; this . age = age; this . weight = weight; } public Cat () { } public void sayMeow () { System. out. println ("Мяу!" ) ; } public String getName () { return name; } public void setName (String name) { this . name = name; } public int getAge () { return age; } public void setAge (int age) { this . age = age; } public int getWeight () { return weight; } public void setWeight (int weight) { this . weight = weight; } } Собственно, ограничение доступа к полям и реализация геттеров-сеттеров - самый распространенный пример использования private в реальной работе. То есть реализация инкапсуляции в программе - главное предназначение этого модификатора. Это касается не только полей, кстати. Представь, что в твоей программе существует метод, который реализует какую-то ОЧЕНЬ сложную функциональность. Что бы придумать такого для примера… Скажем, твой метод readDataFromCollider() принимает на вход адрес с данными, считывает данные из Большого Адронного Коллайдера в байтовом формате, преобразует эти данные в текст, записывает в файл и распечатывает его. Даже описание метода выглядит жутковато, что уж говорить про код:) Чтобы повысить читаемость кода, было бы хорошо не писать сложную логику метода в одном месте, а наоборот - разбить функциональность на отдельные методы. Например, метод readByteData() отвечает за считывание данных, convertBytesToSymbols() конвертирует считанные с коллайдера данные в текст, saveToFile() сохраняет полученный текст в файл, а printColliderData() - распечатывает наш файл с данными. Метод readDataFromCollider() в итоге стал бы намного проще: public class ColliderUtil { public void readDataFromCollider (Path pathToData) { byte colliderData = readByteData (pathToData) ; String textData = convertBytesToSymbols (colliderData) ; File fileWithData = saveToFile (textData) ; printColliderData (fileWithData) ; } public byte readByteData (Path pathToData) { // считывает данные в байтах } public String convertBytesToSymbols (byte colliderDataInBytes) { } public File saveToFile (String colliderData) { } public void printColliderData (File fileWithColliderData) { // печатает данные из файла } } Однако, как ты помнишь из лекции про интерфейсы, пользователь получает доступ только к конечному интерфейсу. А наши 4 метода не являются его частью. Они вспомогательные : мы создали их, чтобы улучшить читаемость кода и не засовывать четыре разные задачи в один метод. Давать доступ пользователю к этим методам не нужно. Если у пользователя при работе с коллайдером появится доступ к методу convertBytesToSymbols() , он скорее всего просто не поймет, что это за метод и зачем нужен. Какие байты конвертируются? Откуда они взялись? Зачем их конвертировать в текст? Логика, которая выполняется в этом методе, не является частью интерфейса для пользователя. Только метод readDataFromCollider() - часть интерфейса. Что же делать с этими четырьмя «внутренними» методами? Правильно! Ограничить доступ к ним модификатором private . Так они смогут спокойно выполнять свою работу внутри класса и не вводить в заблуждение пользователя, которому логика каждого из них по отдельности не нужна. public class ColliderUtil { public void readDataFromCollider (Path pathToData) { byte colliderData = readByteData (pathToData) ; String textData = convertBytesToSymbols (colliderData) ; File fileWithData = saveToFile (textData) ; printColliderData (fileWithData) ; } private byte readByteData (Path pathToData) { // считывает данные в байтах } private String convertBytesToSymbols (byte colliderDataInBytes) { // конвертирует байты в символы } private File saveToFile (String colliderData) { // сохраняет считанные данные в файл } private void printColliderData (File fileWithColliderData) { // печатает данные из файла } }

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

Следующий по строгости модификатор доступа - protected .
Поля и методы, обозначенные модификатором доступа protected , будут видны:
  • в пределах всех классов, находящихся в том же пакете, что и наш;
  • в пределах всех классов-наследников нашего класса.
Сходу трудно представить, когда это может понадобиться. Не удивляйся: случаев применения protected гораздо меньше, чем private , и они специфические. Представь, что у нас есть абстрактный класс AbstractSecretAgent , обозначающий секретного агента какой-то спецслужбы, а также пакет top_secret , в котором лежит этот класс и его наследники. От него наследуются конкретные классы - FBISecretAgent , MI6SecretAgent , MossadSecretAgent и т.п. Внутри абстрактного класса мы хотим реализовать счетчик агентов. При создании где-то в программе нового объекта-агента он будет увеличиваться. package top_secret; public abstract class AbstractSecretAgent { public static int agentCount = 0 ; } Но агенты-то у нас секретные! А значит, об их числе должны знать только они и никто другой. Мы легко можем добавить модификатор protected к полю agentCount , и тогда получить его значение смогут либо объекты других классов секретных агентов, либо те классы, которые расположены в нашем «секретном» пакете top_secret . public abstract class AbstractSecretAgent { protected static int agentCount = 0 ; } Вот для таких специфических задач и нужен модификатор protected:)

Модификатор package visible

Дальше у нас по списку идет модификатор default или, как его еще называют, package visible . Он не обозначается ключевым словом, поскольку установлен в Java по умолчанию для всех полей и методов. Если написать в твоем коде - int x = 10 … у переменной x будет этот самый package visible доступ. Запомнить, что он делает, легко. По сути, default = protected -наследование:) Случаи его применения ограничены, как и у модификатора protected . Чаще всего default -доступ используется в пакете, где есть какие-то классы-утилиты, не реализующие функциональность всех остальных классов в этом пакете. Приведем пример. Представь, что у нас есть пакет «services ». Внутри него лежат различные классы, которые работают с базой данных. Например, есть класс UserService , считывающий данные пользователей из БД, класс CarService , считывающий из этой же БД данные об автомобилях, и другие классы, каждый из которых работает со своим типом объектов и читает данные о них из базы. package services; public class UserService { } package services; public class CarService { } Однако легко может случиться ситуация, когда данные в базе данных лежат в одном формате, а нам они нужны в другом. Представь, что дата рождения пользователя в БД хранится в формате TIMESTAMP WITH TIME ZONE... 2014 - 04 - 04 20 : 32 : 59.390583 + 02 ...нам вместо этого нужен самый простой объект - java.util.Date . Для этой цели можем создать внутри пакета services специальный класс Mapper . Он будет отвечать за конвертацию данных из базы в привычные нам Java-объекты. Простой вспомогательный класс. Обычно мы создаем все классы как public class ClassName , но это не обязательно. Мы можем объявить наш вспомогательный класс просто как class Mapper . В таком случае он все равно делает свою работу, но не виден никому за пределами пакета services ! package services; class Mapper { } package services; public class CarService { Mapper mapper; } А это, по сути, правильная логика: зачем кому-то за пределами пакета видеть вспомогательный класс, работающий только с классами этого же пакета?

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

И последний по списку, но не по значимости - модификатор public ! С ним ты познакомился в первый день учебы на JavaRush, впервые в жизни запустив public static void main(String args) .
Теперь, когда ты изучил лекции об интерфейсах, для тебя очевидно его предназначение:) Ведь public создан для того, чтобы отдавать что-то пользователям. Например, интерфейс твоей программы. Допустим, ты написал программу-переводчик, и она умеет переводить русский текст в английский. Ты создал метод translate(String textInRussian) , внутри которого реализована необходимая логика. Этот метод ты отметил словом public , и теперь он станет частью интерфейса: public class Translator { public String translate (String textInRussian) { // переводит текст с русского на английский } } Можно связать вызов этого метода с кнопкой «перевести» на экране программы - и все! Кто угодно может этим пользоваться. Части кода, помеченные модификатором public , предназначаются для конечного пользователя. Если привести пример из жизни, private - это все процессы, происходящие внутри телевизора, когда он работает, а public - это кнопки на пульте телевизора, с помощью которых пользователь может им управлять. При этом ему не нужно знать как устроен телевизор и за счет чего он работает. Пульт - это набор public -методов: on() , off() , nextChannel() , previousChannel() , increaseVolume() , decreaseVolume() и т.д.

Для начала разберемся с модификаторами доступа. Их всего четыре:

  • private члены класса доступны только внутри класса
  • package-private или default (по умолчанию) члены класса видны внутри пакета
  • protected члены класса доступны внутри пакета и в классах-наследниках
  • public члены класса доступны всем

Во время наследования возможно изменение модификаторов доступа в сторону БОЛЬШЕЙ видимости.

Модификатор доступа у конструкторов, методов и полей может быть любой, а вот с классами и их блоками не так все просто. Класс может быть только либо public, либо default, причем в одном файле может находиться только один public класс. У блока может быть только один модификатор – default.

Модификаторы static, abstract и final

Static

  • Применяется к внутренним классам, методам, переменным и логическим блокам
  • Статические переменные инициализируются во время загрузки класса
  • Статические переменные едины для всех объектов класса (одинаковая ссылка)
  • Статические методы имеют доступ только к статическим переменным
  • К статическим методам и переменным можно обращаться через имя класса
  • Статические блоки выполняются во время загрузки класса
  • Не static методы не могут быть переопределены как static
  • Локальные переменные не могут быть объявлены как static
  • Абстрактные методы не могут быть static
  • Static поля не сериализуются (только при реализации интерфейса Serializable)
  • Только static переменные класса могут быть переданы в конструктор с параметрами, вызывающийся через слово super(//параметр//) или this(//параметр//)

Abstract

  • Применяется только для методов и классов
  • У абстрактных методов нет тела метода
  • Является противоположностью final: final класс не может наследоваться, abstract класс обязан наследоваться
  • Класс должен быть объявлен как abstract если:
  1. он содержит хотя бы один абстрактный метод
  2. он не предоставляет реализацию наследуемых абстрактных методов
  3. он не предоставляет реализацию методов интерфейса, реализацию которого он объявил
  4. необходимо запретить создание экземпляров класса

Final

  • Поля не могут быть изменены, методы переопределены
  • Классы нельзя наследовать
  • Этот модификатор применяется только к классам, методам и переменным (также и к локальным переменным)
  • Аргументы методов, обозначенные как final, предназначены только для чтения, при попытке изменения будет ошибка компиляции
  • Переменные final не инициализируются по умолчанию, им необходимо явно присвоить значение при объявлении или в конструкторе, иначе – ошибка компиляции
  • Если final переменная содержит ссылку на объект, объект может быть изменен, но переменная всегда будет ссылаться на тот же самый объект
  • Также это справедливо и для массивов, потому что массивы являются объектами, – массив может быть изменен, а переменная всегда будет ссылаться на тот же самый массив
  • Если класс объявлен final и abstract (взаимоисключающие понятия), произойдет ошибка компиляции
  • Так как final класс не может наследоваться, его методы никогда не могут быть переопределены
Конструктор не может быть static, abstract или final

Модификаторы strictfp, transient, volatile, synchronized, native

Strictfp

  • Применяется для методов и классов
  • Обеспечивает выполнение операций над числами типа float и double (с плавающей запятой) по стандарту IEEE 754

Transient

  • Применяется только для переменных уровня класса (локальные переменные не могут быть объявлены как transient)
  • Transientпеременные могут не быть final или static.
  • Transientпеременные не сериализуются

Volatile

  • Используется только с переменными
  • Может использоваться со static переменными
  • Не используется с final переменными - Значение переменной, объявленной как volatile, измененное одним потоком, асинхронно меняется и для других потоков
  • Применяется в многопоточных приложениях

Synchronized

  • Применяется только к методам или частям методов
  • Используется для контроля доступа к важным частями кода в многопоточных программах

Native

  • Используется только для методов
  • Обозначает, что метод написан на другом языке программирования
  • Классы в Java используют много native методов для повышения производительности и доступа к аппаратным средствам
  • Можно предавать/возвращать Java объекты из native методов
  • Сигнатура метода должна заканчиваться “;”, фигурные скобки вызовут ошибку компиляции

Особенности в интерфейсах

  • Методы всегда public и abstract, даже если это не объявлено
  • Методы не могут быть static, final, strictfp, native, private, protected
  • Переменные только public static final, даже если это не объявлено
  • Переменные не могут быть strictfp, native, private, protected
  • Может только наследовать (extends) другой интерфейс, но не реализовывать интерфейс или класс (implements).

Соберем все модификаторы вместе:

Класс

Внутренний класс

Переменная

Метод

Конструктор

Логический блок

public

Да

Да

Да

Да

Да

Нет

protected

Нет

Да (кроме локальных и анонимных классов)

Да

Да

Да

Нет

default

Да

Да

Да

Да

Да

private

Нет

Да (кроме локальных и анонимных классов)

Да

Да

Да

Нет

final

Да

Да (и для локальной переменной)

Да

Нет

Нет

abstract

Да

Да (кроме анонимных классов)

Нет

Да

Нет

Нет

static

Нет

Да (кроме локальных и анонимных классов)

Да

Да

Нет

Да

native

Нет

Нет

Нет

Да

Нет

Нет

transient

Нет

Нет

Да

Нет

Нет

Нет

synchronized

Нет

Нет

Нет

Да

Нет

Да (только как часть метода)

volatile

Нет

Нет

Да

Нет

Нет

Нет

strictfp

Да

Да

Нет

Да

Нет

Нет

Которые Вы добавляете при инициализации для изменения значений. Язык 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 предоставляет ряд модификаторов доступа, чтобы задать уровни доступа для классов, переменных, методов и конструкторов. Существует четыре доступа:

  • Видимый в пакете (стоит по умолчанию и модификатор не требуются).
  • Видимый только для класса (private).
  • Видимый для всех (public).
  • Видимый для пакета и всех подклассов (protected).

Модификатор доступа по умолчанию - без ключевого слова

Модификатор доступа по умолчанию - означает, что мы явно не объявляем модификатор доступа в Java для класса, поля, метода и т.д.

Переменная или метод, объявленные без модификатора контроля доступа доступны для любого другого класса в том же пакете. Поля в интерфейсе неявно являются public, static, final, а методы в интерфейсе по умолчанию являются public.

Пример

Переменные и методы могут быть объявлены в Java без каких-либо модификаторов, как показано в следующем примере:

String version = "1.5.1"; boolean processOrder() { return true; }

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

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

Модификатор доступа private является наиболее ограничивающим уровенем доступа. Класс и интерфейсы не могут быть private.

Переменные, объявленные как private, могут быть доступны вне класса, если получающие их открытые (public) методы присутствуют в классе (ниже смотрите пример и пояснения).

Использование модификатора private в Java является основным способом, чтобы скрыть данные.

Пример

Следующий класс использует контроль доступа 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) , который устанавливает её значение.

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

Модификатор public - класс, метод, конструктор, интерфейс и т.д. объявленные как public могут быть доступны из любого другого класса. Поэтому поля, методы, блоки, объявленные внутри public класса могут быть доступны из любого класса, принадлежащего к "вселенной" Java.

Тем не менее, если к public классу в другом пакете мы пытаемся получить доступ, то public класс приходится импортировать.

Благодаря наследованию классов, в Java все публичные (public) методы и переменные класса наследуются его подклассами.

Пример

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

Public static void main(String arguments) { // ... }

Метод main() должен быть публичным (public). В противном случае, он не может быть вызван с помощью java-интерпретатора, чтобы запустить класс.

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

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

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

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

Пример

Следующий родительский класс использует контроля доступа protected, чтобы его дочерний класс переопределил метод openSpeaker() :

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

При этом, если мы определим метод openSpeaker() как protected, то он не будет доступен из любого другого класса, кроме AudioPlayer. Если мы определим его как public, то он станет доступным всем. Но наше намерение состоит в том, чтобы раскрыть этот метод только подклассу, вот почему мы использовали модификатор protected.

Правила контроля доступа и наследования

Следующие правила в Java применяются для унаследованных методов:

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

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

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

  • модификатор static применяется для создания методов и переменных класса;
  • модификатор final используется для завершения реализации классов, методов и переменных;
  • модификатор abstract необходим для создания абстрактных классов и методов;
  • модификаторы synchronized и volatile используются в Java для потоков.

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

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

Переменные static

Ключевое слово static используется для создания переменных, которые будут существовать независимо от каких-либо экземпляров, созданных для класса. Только одна копия переменной static в Java существует вне зависимости от количества экземпляров класса.

Статические переменные также известны как переменные класса. В Java локальные переменные не могут быть объявлены статическими (static).

Методы static

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

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

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

Пример

Модификатор static в Java используется для создания методов классов и переменных, как показано в следующем примере:

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

Будет получен следующий результат:

Начиная с 0 экземпляра Создано 500 экземпляров

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

Модификатор final - используется для завершения реализации классов, методов и переменных.

Переменные final

Переменная final может быть инициализирована только один раз. Ссылочная переменная, объявленная как final, никогда не может быть назначен для обозначения другого объекта.

Однако данные внутри объекта могут быть изменены. Таким образом, состояние объекта может быть изменено, но не ссылки.

С переменными в Java модификатор 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 не может быть переопределен любым подклассом. Как упоминалось ранее, в Java модификатор final предотвращает метод от изменений в подклассе.

Главным намерение сделать метод final будет то, что содержание метода не должно быть изменено стороне.

Пример

Объявление метода, использующего модификатор final в объявление класса, показано в следующем примере:

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

Класс final

Основная цель в Java использования класса объявленного в качестве final заключается в предотвращении класс от быть подклассом. Если класс помечается как final, то ни один класс не может наследовать любую функцию из класса final.

Пример

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

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

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

Класс abstract

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

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

Класс abstract может содержать как абстрактные методы, а также и обычные.

Пример

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

Метод abstract

Метод abstract является методом, объявленным с любой реализацией. Тело метода (реализация) обеспечивается подклассом. Методы abstract никогда не могут быть final или strict.

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

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

Абстрактный метод заканчивается точкой с запятой. Пример: public abstract sample();

Пример

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

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

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

Ключевое слово synchronized используется для указания того, что метод может быть доступен только одним потоком одновременно. В Java модификатор synchronized может быть применен с любым из четырех модификаторов уровня доступа.

Пример

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

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

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

Этот модификатор включён в оператор, что создает переменную, предшествующего класса или типа данных переменной.

Пример

public transient int limit = 55; // не будет сохраняться public int b; // будет сохраняться

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

Модификатор volatile - используются в Java для потоков.

В Java модификатор volatile используется, чтобы позволить знать JVM, что поток доступа к переменной всегда должен объединять свою собственную копию переменной с главной копией в памяти.

Доступ к переменной volatile синхронизирует все кэшированные скопированные переменные в оперативной памяти. Volatile может быть применен только к переменным экземпляра, которые имеют тип объект или private. Ссылка на объект volatile может быть null.

Пример

public class MyRunnable implements Runnable{ private volatile boolean active; public void run(){ active = true; while (active){ // линия 1 // здесь какой-нибудь код } } public void stop(){ active = false; // линия 2 } }

Как правило, run() вызывается в одном потоке (впервые начинаете использовать Runnable в Java), а stop() вызывается из другого потока. Если в линии 1 используется кэшированное значение active, то цикл не может остановиться, пока Вы не установите active false в линии 2.

В следующем уроке обсудим основные операторы, используемые в языке Java. Этот раздел даст Вам обзор того, как можно использовать их во время разработки приложения.