Ростелеком

Особенности применения модификаторов в Java. Модификаторы в Java: static, final, abstract, synchronized, transient, volatile Модификаторы класса, метода, переменной и потока, используемые не для доступа

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

Модификаторы в Java – это ключевые слова, которые придают классу, полю класса или методу определенные свойства.

Для обозначения видимости класса его методов и полей есть 4 модификатора доступа:

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

Если Вы помните , то в конце, когда мы уже импортировали класс Cat, у нас все равно была ошибка компиляции.

Все дело в том, что мы не прописали никаких модификаторов доступа к нашим полям и методам и они имеют свойство по умолчанию (члены класса видны внутри пакета). Чтобы исправить ошибку компиляции для нашего кода и наконец то запустить его, нужно сделать наш конструктор и методы public. Тогда их можно будет вызывать с других пакетов.

Вы можете начать задаваться вопросом: а для чего все это нужно? Почему не сделать видимость кода из любого пакета или класса, а нужно разграничить доступ? Эти вопросы сами пропадут, когда придет время писать сложные и громоздкие проекты. Сейчас, когда мы пишем приложения, у которых функционал ограничен одним или двумя классами, то смысла что либо ограничить вроде как не видно.

Представьте, что у Вас есть класс который отображает объект некоего продукта. Например машина. У машины может быть цена. Вы создали поле цена и еще множество других полей, кучу методов которые отвечают за функционал. Все вроде хорошо. Ваш класс машина является частью огромного проекта и все довольны. Но допустим, что кто-то по ошибке или специально создал экземпляр класса автомобиль и поставил отрицательную цену. Разве может товар иметь отрицательную цену? Это очень примитивный пример и вряд ли такое может случиться в реальной жизни, но думаю, идея понятна. Иногда нужно дать доступ не напрямую, а через определенные методы. Может быть, что код отвечает за функционал другого кода, и Вы не хотите, чтобы кто-то изменял и редактировал часть Вашего. Для этого всего и есть ограничение доступа.

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

Пока об модификаторах доступа будет достаточно. В статье «Объектно ориентированное программирование» мы о них поговорим подробнее, а сейчас давайте поговорим о других модификаторах которых, к стати, немало.

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

static модификатор перед методом или полем говорит о том, что они не принадлежат к экземпляру данного класса. Что это означает для нас? Когда мы описали поле класса или метод как static, его можно вызвать без использования экземпляра класса. То есть вместо такой конструкции: Cat cat = new Cat(); cat.method(), можно написать просто Cat.method(). При условии, что метод объявлен как static. Статические переменные едины для всех объектов класса. У них одна ссылка.

    public class Modificators {

    static int anotherStaticField = 5 ;

    public static void myStaticMethod() {

    someField = "My field" ;

    //nonStaticField = ""; ошибка компиляции

    //нельзя использовать нестатические поля

    //в статических методах

    public void myNonStaticMethod() {

    anotherStaticField = 4 ; //ститические поля можно использовать

    //в нестатических методах

    //main метод тоже имеет модификатор static

    new Modificators() .myNonStaticMethod () ;

    Modificators.myStaticMethod () ; //вызов статических методов и полей

    //через имяКласса.метод

Еще одно важное замечание, которое нужно сказать по поводу static модификаторов: статические поля инициализируются во время загрузки класса. Часто в разного рода тестах по Java можно встретить такой код:

Вопрос: что будет выведено на консоль? Нужно помнить, что static блок будет выведен первым при любом раскладе. Далее будет идти блок по умолчанию. Далее смотрите на скрин консоли:

Следующий модификатор, который мы рассмотрим будет final.

Думаю, слово final говорит само за себя. Применяя final модификатор Вы говорите, что поля не могут быть изменены, методы переопределены, а классы нельзя наследовать (о наследовании будет отдельная статья). Этот модификатор применяется только к классам, методам и переменным (также и к локальным переменным).

С модификатором final к методам и классам мы будем говорить в статье ООП.

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

Модификатор synchronized — говорит о том, что метод может быть использован только одним потоком одновременно. Хотя, возможно, это Вам ни о чем не говорит, полезность этого модификатора будет видно, когда мы будем изучать многопоточность.

Модификатор transient — говорит о том, что во время сериализации объекта некоторое поле нужно игнорировать. Как правило, такие поля хранят промежуточные значения.

Модификатор volatile — используется при многопоточности. Когда поле с модификатором volatile будет использоваться и изменяться несколькими потоками, данный модификатор гарантирует, что поле будет изменяться по очереди и путаницы с ним не возникнет.

Модификатор native перед объявлением метода указывает что метод написан на другом языке программирования. Обычно на языке C.

Модификатор strictfp — Обеспечивает выполнение операций над числами типа float и double (с плавающей запятой) по стандарту IEEE 754. Или говоря проще, гарантирует что в пределах метода результаты вычислений будут одинаковыми на всех платформах.

Я еще не говорил о модификаторе abstract . О нем скажу вкратце, так как без знаний основ объектно ориентированного программирования говорить о нем не вижу смысла.

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

Подробнее о модификаторе abstract будем говорить в статье ООП.

На этом можно и закончить статью о модификаторах. Многое о них не было сказано. Но это из-за того, что у нас еще нет понятий ООП. Через несколько статей, мы дополним знания о модификаторах и заполним пробелы.

5

Я видел некоторые дискуссии в StackOverflow об этой теме, но я не вижу что-то, что помогло мне понять следующий пункт:

я происхожу из C++ фона и в последнее время Я начал изучать Java. В C++, когда защищен , используется только подкласс, который может получить доступ к члену (аналог поля в Java).

В C++ есть также классы «друг», которые могут иметь доступ к частным/защищенным камерам класса, которые дают «дружбу». Это немного похоже на модификатор поля «package» в Java (модификатор поля по умолчанию), за исключением того, что в C++ дружба дает доступ ко всем закрытым членам, но в Java доступ из классов в одном пакете специфичен для поля класса,

Что я не могу понять, предполагая, что хочу предоставить доступ только к подклассам, это то, что я могу сделать на C++, объявив членов, защищенных в классе, который не «дает» дружеские отношения.

Но на Java я не знаю, как это сделать, поскольку с помощью «защищенного» модификатора поля - я также предоставляю доступ ко всем классам в пакете. Единственный способ, которым я нахожу это, - объявить защищенное поле и изолировать класс в своем пакете.

Отсюда я заключаю, что группировка классов в один пакет должна выполняться на основе «дружбы» между классами. Действительно ли это является ведущим фактором при группировании пакетов?

Еще одна вещь, которую я не понимаю, В Java, предполагая, что у меня есть два поля в классе A: b, c. Я хочу дать B доступ к b, но не к, и я хочу дать C доступ к c, но не b. и к «Миру» я хочу b, c, чтобы скрыть. Как это можно сделать? Я предполагаю, что B, C должны быть в том же пакете, что и A. , но путем объявления b, c с пакетом модификатором Я разрешаю B, C доступ как к b, так и к. Есть ли способ в Java, чтобы это сделать?

Надежда для некоторого объяснения этого вопроса

11

Лучший вопрос, если менее полезным для вас будет более узким и конкретным. Общий вопрос «все о конфиденциальности в Java и C++ и о том, как они отличаются», более чем слишком широк. Можете ли вы задать более конкретный вопрос о более конкретной проблеме? - Yakk 04 мар. 15 2015-03-04 16:38:58

  • 4 ответа
  • Сортировка:

    Активность

2

В C++, когда используется защита, только подкласс может получить доступ к элементу (аналог поля в Java).

Спецификаторы доступа также предназначены для функций-членов/методов, а не только для переменных-членов.

В C++ есть также «друг» классы, которые могут иметь доступ к частным/защищаемому mambers класса, что дает «дружбу». Этот немного похож на модификатор поля «package» в Java (по умолчанию модификатор поля), за исключением того, что в C++ дружба дает доступ ко всем частным членам, но в Java доступ из классов в том же пакете специфичен для поле класса.

Существует не только friend классы, но и функции.

Верно, что доступ к частным частям Java аналогичен, но это не полная замена. Лучше сказать, что эти две функции имеют подмножество проблем, которые они решают. Есть проблемы, которые могут быть решены friend , но не пакетом-частным, и наоборот.

То, что я не мог понять, если предположить, что я хочу, чтобы предоставить доступ только к подклассам, это то, что я могу сделать в C++, объявив пользователей защищенных в классе, который не «дает» дружба.

Но в Java, я не знаю, как я могу это сделать,

Ответ: Вы не можете.

так как с помощью «защищенного» модификатора поля - я также предоставляю доступ к всем классам в пакете.

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

Технически, да. Но это создает другие проблемы. Ваш класс больше не сможет получить доступ к частным частям пакета своего предыдущего пакета. Допустим, ваш BaseClass был в com.example.one . Вы переместите его на com.example.two . Теперь он больше не сможет получить доступ к другим пакетам-частным классам com.example.one .

Действительно ли это является ведущим фактором при группировании пакетов?

Да, Java спроектирован таким образом. Вы можете попробовать бороться с правилами языка , но это проигрышная битва на любом языке программирования.

Еще одна вещь, которую я не понимаю, в Java, предполагая, что у меня есть два поля в классе A: b, c. Я хочу дать B доступ к b, но не к, и я хочу предоставить C доступ к c, но не b. и в «Мир» я хочу b, c , чтобы скрыть. Как это можно сделать?

Это не может быть сделано чистым способом (чистым я имею в виду: без каких-либо взломов, которые потребуют от вас проверки стека вызовов во время выполнения и исключения исключений).

Если вы обеспокоены этим сценарием, поскольку вы разрабатываете публичный API, низкотехнологичное решение, которое обычно прекрасно работает, - это создать один или несколько пакетов *.internal и четко документировать тот факт, что они не должны использоваться в клиентский код.

1

Это довольно куча вопросов вместе...

Но в Java, я не знаю, как я могу это сделать, так как в силу используя «защищенный» модификатор поля - я также предоставляю доступ ко всем классам в пакете.

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

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

Это технически правильно, хотя это будет мало использовать. Упаковка классов предназначена для группировки связанных классов, где «родственные» означает «классы, которые выполняют конкретное отношение», т. Е. Они принадлежат одному и тому же варианту использования, принадлежат к одному и тому же архитектурному уровню, находятся в одной и той же сущности, и т.д.

Отсюда я заключаю, что группировка классов в один пакет должна выполняться на основе «дружбы» между классами. Действительно ли это является ведущим фактором при группировании пакетов?

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

Для вашего A, B и C классов, например, с атрибутами:

Я думаю, B, C должно быть как в том же пакете, А. а объявляющего б, с модификатором упаковки I пусть В, C доступ как к b, так и к. Есть ли способ в Java сделать это?

Ответ нет, нет простого и чистого способа сделать это. Вы могли бы добиться этого с помощью некоторых хаков или более продвинутых техник, но, опять же, это было частью решений, принятых разработчиками языка давным-давно...

0

Короткий ответ: нет никакого способа сделать это.

Если вы беспокоитесь о вторжении от клиентов инъекционного класса в пакете, чтобы получить несанкционированный доступ, вы можете перемещать чувствительный код в отдельном пакете, и сделать пакет запечатанного в банке вы доставить его в: http://docs.oracle.com/javase/tutorial/deployment/jar/sealman.html

1

Неявно предполагается, что все классы в пакете «знают» друг друга (потому что они были написаны одним и тем же лицом/компанией/организацией). Таким образом, они либо не получают доступа к полям protected , либо, если они это делают, они знают, как это сделать должным образом.

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

Итак, я думаю, вам не стоит беспокоиться о том, как классы в одном пакете могут обращаться к полям друг друга. В общем, я просто не использую эту функцию, за исключением случаев, когда я пишу итераторы.

Если у вас есть два поля, вы можете сделать их внутренними классами, чтобы они имели доступ к закрытым полям (опять же, логика: если класс находится внутри другого класса, он знает о семантике этого класса) и могут предоставлять этот доступ к их производным классам через защищенные методы.

Конечно, вы можете придумать сложный протокол обмена токенами, чтобы сделать это поле доступным только для экземпляров B/C, но это было бы замечательным накладным расходами, а другой объект все равно может использовать отражение, чтобы получить доступ ко всем частным членов, если вы не отключите его с помощью политик безопасности, что обычно не так, но опять же, политики безопасности в конечном итоге решаются владельцем JVM.

Итак, в конечном итоге предпочтительный способ сделать то, что вы говорите на Java, - либо поместить их в один и тот же пакет, либо написать B и C как внутренние классы A, чтобы они могли напрямую обращаться к закрытым членам A и подвергать их их производным классам.

Public class A { public static abstract class B { protected Whatever getWhatever(A a) { return a.b; } protected void setWhatever(A a, Whatever value) { a.b = value; } } public static abstract class C { protected Whatever getWhatever(A a) { return a.c; } protected void setWhatever(A a, Whatever value) { a.c = value; } } private Whatever b; private Whatever c; }

еще раз, вы всегда считаете, что классы в одном пакете никогда не сделают ничего плохого.

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

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

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

  • 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 ).

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

Все члены класса - поля, методы, свойства - все они имеют модификаторы доступа . Модификаторы доступа позволяют задать допустимую область видимости для членов класса. То есть модификаторы доступа определяют контекст, в котором можно употреблять данную переменную или метод. В предыдущих темах мы уже с ним сталкивались, когда объявляли поля класса публичными (то есть с модификатором public).

В C# применяются следующие модификаторы доступа:

    public : публичный, общедоступный класс или член класса. Такой член класса доступен из любого места в коде, а также из других программ и сборок.

    private : закрытый класс или член класса. Представляет полную противоположность модификатору public. Такой закрытый класс или член класса доступен только из кода в том же классе или контексте.

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

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

    protected internal : совмещает функционал двух модификаторов. Классы и члены класса с таким модификатором доступны из текущей сборки и из производных классов.

    private protected : такой член класса доступен из любого места в текущем классе или в производных классах, которые определены в той же сборке.

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

Private protected class State { internal int a; protected void Print() { Console.WriteLine($"a = {a}"); } }

Либо можем не указывать:

Class State { int a; void Print() { Console.WriteLine($"a = {a}"); } }

Если для полей и методов не определен модификатор доступа, то по умолчанию для них применяется модификатор private .

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

Все классы и структуры, определенные напрямую в пространствах имен и не являющиеся вложенными в другие классы, могут иметь только модификаторы public или internal.

Посмотрим на примере и создадим следующий класс State:

Public class State { // все равно, что private int defaultVar; int defaultVar; // поле доступно только из текущего класса private int privateVar; // доступно из текущего класса и производных классов, которые определены в этом же проекте protected private int protectedPrivateVar; // доступно из текущего класса и производных классов protected int protectedVar; // доступно в любом месте текущего проекта internal int internalVar; // доступно в любом месте текущего проекта и из классов-наследников в других проектах protected internal int protectedInternalVar; // доступно в любом месте программы, а также для других программ и сборок public int publicVar; // по умолчанию имеет модификатор private void defaultMethod() => Console.WriteLine($"defaultVar = {defaultVar}"); // метод доступен только из текущего класса private void privateMethod() => Console.WriteLine($"privateVar = {privateVar}"); // доступен из текущего класса и производных классов, которые определены в этом же проекте protected private void protectedPrivateMethod() => Console.WriteLine($"protectedPrivateVar = {protectedPrivateVar}"); // доступен из текущего класса и производных классов protected void protectedMethod()=> Console.WriteLine($"protectedVar = {protectedVar}"); // доступен в любом месте текущего проекта internal void internalMethod() => Console.WriteLine($"internalVar = {internalVar}"); // доступен в любом месте текущего проекта и из классов-наследников в других проектах protected internal void protectedInternalMethod() => Console.WriteLine($"protectedInternalVar = {protectedInternalVar}"); // доступен в любом месте программы, а также для других программ и сборок public void publicMethod() => Console.WriteLine($"publicVar = {publicVar}"); }

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

Также имеются шесть методов, которые будут выводить значения полей класса на экран. Обратите внимание, что так как все модификаторы позволяют использовать члены класса внутри данного класса, то и все переменные класса, в том числе закрытые, у нас доступны всем его методам, так как все находятся в контексте класса State.

Теперь посмотрим, как мы сможем использовать переменные нашего класса в программе (то есть в методе Main класса Program), если классы State и Program находятся в одном проекте :

Class Program { static void Main(string args) { State state1 = new State(); // присвоить значение переменной defaultVar у нас не получится, // так как она имеет модификатор private и класс Program ее не видит // И данную строку среда подчеркнет как неправильную state1.defaultVar = 5; //Ошибка, получить доступ нельзя // то же самое относится и к переменной privateVar state1.privateVar = 5; // Ошибка, получить доступ нельзя // присвоить значение переменной protectedPrivateVar не получится, // так как класс Program не является классом-наследником класса State state1.protectedPrivateVar =5; // Ошибка, получить доступ нельзя // присвоить значение переменной protectedVar тоже не получится, // так как класс Program не является классом-наследником класса State state1.protectedVar = 5; // Ошибка, получить доступ нельзя // переменная internalVar с модификатором internal доступна из любого места текущего проекта // поэтому спокойно присваиваем ей значение state1.internalVar = 5; // переменная protectedInternalVar так же доступна из любого места текущего проекта state1.protectedInternalVar = 5; // переменная publicVar общедоступна state1.publicVar = 5; } }

Таким образом, мы смогли установить только переменные internalVar, protectedInternalVar и publicVar, так как их модификаторы позволяют использовать в данном контексте.

Аналогично дело обстоит и с методами:

Class Program { static void Main(string args) { State state1 = new State(); state1.defaultMethod(); //Ошибка, получить доступ нельзя state1.privateMethod(); // Ошибка, получить доступ нельзя state1.protectedPrivateMethod(); // Ошибка, получить доступ нельзя state1.protectedMethod(); // Ошибка, получить доступ нельзя state1.internalMethod(); // норм state1.protectedInternalMethod(); // норм state1.publicMethod(); // норм } }

Здесь нам оказались доступны только три метода: internalMethod, protectedInternalMethod, publicMethod, которые имееют соответственно модификаторы internal, protected internal, public.

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

Несмотря на то, что модификаторы public и internal похожи по своему действию, но они имеют большое отличие. Классы и члены класса с модификатором public также будут доступны и другим программам, если данных класс поместить в динамическую библиотеку dll и потом ее использовать в этих программах.