Какой модификатор доступа можно применить для пакета. Модификаторы в Java: static, final, abstract, synchronized, transient, volatile. Модификаторы доступа public, private, protected

Какой модификатор доступа можно применить для пакета. Модификаторы в Java: static, final, abstract, synchronized, transient, volatile. Модификаторы доступа public, private, protected

Хочу продолжить делиться приобретенными знаниями и своими впечатлениями от подготовки к экзамену. Огромное спасибо всем тем, кто дал рекомендации к нулевой части этой серии! Сегодня я поговорю еще немножко о модификаторах доступа и их взаимоотношениях с наследованием и пакетами, рассмотрю varargs и перечисления, а также массивы и способы их инициализации. Я надеюсь, что хабражители снова откликнутся и дополнят то, о чем я забыл упомянуть или попросту не знал.

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

Методы, поля, локальные переменные и их модификаторы

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

  1. Если метод или поле имеют модификатор public, то они потенциально доступны всей вселенной.
  2. Если метод или поле имеют модификатор доступа private, то они доступны только в рамках класса. Такие члены класса не наследуются, поэтому их невозомжно заместить в подклассах. Помните об этом.
  3. Если метод или поле имеют модификатор доступа по умолчанию, то они доступны только в рамках пакета.
  4. Если метод или поле имеют модификатор доступа protected, то они, прежде всего, доступны самому классу и его наследникам. Кроме того, доступ к этим членам класса могут получить их собратья по пакету.

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

Хочу также обратить внимание на некоторые особенности, которые возникают при использовании доступа по умолчанию и модификатора protected. Рассмотрим следующуий пример. Пусть имеется базовый класс, объявленный в пакете test. Этот класс обладает двумя полями. Первое объявлено с доступом по умолчанию, второе - protected.

Package org.kimrgrey.scjp.test; public class BaseClass { int defaultValue; protected int protectedValue; public BaseClass() { this.defaultValue = 1; this.protectedValue = 1; } }

Если объявить в этом пакете класс SamePackageAccess, который не будет наследоваься от BaseClass, то он все равно получит доступ и к полю defaultValue, и к полю protectedValue. Об этой особенности модификатора protected стоит помнить: члены класса, объявленные как protected, в рамках пакета доступны как через наследование, так и через ссылку. Пример:

Package org.kimrgrey.scjp.test; public class SamePackageAccess { public SamePackageAccess() { BaseClass a = new BaseClass(); a.defaultValue = 2; a.protectedValue = 2; } }

В случае с наследованием в этом пакете доступ по-прежнему сохраняется к обоим полям, причем как по ссылке, так и через наследование.

Package org.kimrgrey.scjp.test; public class SamePackageSubclass extends BaseClass { public SamePackageSubclass() { this.defaultValue = 3; this.protectedValue = 3; BaseClass a = new BaseClass(); a.defaultValue = 3; a.protectedValue = 3; } }

Теперь давайте посмотрим, что будет, если мы выйдем за пределы пакета. Первое, что случится - мы потеряем доступ к полю, объявленному без явного указания модификатора доступа. Его не будут видеть абсолютно все классы вне родного пакета, в том числе и прямые наследники BaseClass. Поле же с модификатором protected будет доступно через наследование всем своим подклассам. Однако даже наследник не сможет его использовать через ссылку. Кроме того, будучи однажды унаследованным классом вне пакета, поле становится закрытым для любых классов, за исключением дальнейших наследников.

Package org.kimrgrey.scjp.main; import org.kimrgrey.scjp.test.BaseClass; public class OtherPackageSubclass extends BaseClass { public OtherPackageSubclass() { this.defaultValue = 10; // Line 8: не получим доступ, потому что другой пакет this.protectedValue = 10; BaseClass a = new BaseClass(); a.protectedValue = 10; // Line 12: по ссылке не могут обращаться даже наследники BaseClass } }

В этом примере содержится также еще одна важная деталь. Предположим, вас спрашивают, что же случиться если скомпилировать приведенный выше код? И дают следующие варианты ответа:

  1. Код будет успешно скомпилирован
  2. Возникнет ошибка компиляции на строке с номером 8
  3. Возникнет ошибка компиляции на строке с номером 12
В этом случае, если явно не указано обратное, выбрать нужно все правильные варианты ответов: 2 и 3, - а не останавливаться на первом подходящем. Внимательно читайте все ответы и проверяйте их на корректность. Именно этот подход работает лучше всего. Прочитав и поняв суть вопроса, проверяйте и анализируйте именно ответы, а не код, приведенный в формулировке.

Среди модификаторов, связанных с наследованием, следует также рассмотреть final. На методы final действует также, как на классы: запрещает их переопределение наследниками. При этом расширять сам класс, в котром находится final метод, по-прежнему можно.

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

Важно помнить, что к локальным переменным неприменимы никакие модификаторы, кроме final. Поэтому, если вы видите в объявлении локальной переменной что-то вроде private int a , то можно смело говорить, что это не скомпилируется. А что же с полями?

  1. К полям, как я уже говорил, применимы все четыре уровня доступа.
  2. Поле может быть помечено как final.
  3. Поле может быть помечено как transient.
  4. Поле может быть помечено как static.
  5. Поле может быть помечено как volatile.
  6. Поле не может быть помечено как abstract.
  7. Поле не может быть помечено как synchronized.
  8. Поле не может быть помечено как strictfp.
  9. Поле не может быть помечено как native.
Некоторые из модификаторов, упомянутых выше, я раньше не описывал. Постараюсь рассмотреть их позже, в соответсвующих темах (transient будет рассмотрен в рамках сериализации, а synchronized и volatile - в многопоточности).

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

  1. Когда вы указываете параметр vararg, то базовым типом может быть любой тип: примитивный или нет.
  2. Чтобы объявить такой параметр, вы пишите тип, потом три точки, пробел, затем имя массива, который будет использоваться в рамках метода: void f (int... a) . Можно также разделить тип, три точки и идентифкаторы пробелами, так: void f(int ... a) . Внимательно следите за точками. Авторы экзамена любят переносить их за идентификатор. Такой подход не работает.
  3. В метод могут передаваться другие параметры, но в этом случае параметр vararg должен быть последним: void f (double x, int... a)
  4. В методе может быть один и только один vararg параметр.
Для наглядности приведу хороший пример вопроса по этой теме. Выберите такое объявление метода doSomething(), чтобы приведенный ниже код был удачно скомпилирован?

Package org.kimrgrey.scjp.main; public class Application { public static void main(String args) { doSomething(1); doSomething(1, 2); } }

  1. static void doSomething(int... values) {}
  2. static void doSomething(int values) {}
  3. static void doSomething(int x, int... values) {}

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

Package org.kimrgrey.scjp.main; public class Application { private static void f (int... a) { for (int i = 0; i < a.length; ++i) { System.out.println(a[i]); } } public static void main(String args) { f(new int {1, 2 ,3}); } }

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

Перечисления

  1. У перечислений могут быть конструкторы.
  2. У перечислений могут быть поля.
  3. У перечислений могут быть методы.
  4. Если перечисление объявляется вне класса, оно может получить только два уровня доступа: public или по умолчанию.
  5. У перечислений есть статический метод values() , который возвращает массив, содержащий все возможные значения перечисления, причем строго в том порядке, в котором они были объявлены.
Для каждого из значений в рамках перечисления вы можете объявить свое собственное «тело» - его специфическое описание. При этом специфичные для значения версии методов перегружают вариант, который используется для всего перечисления в целом. Это позволяет менять поведение членов перечисления в зависимости от нужд приложения. Пример:

Package org.kimrgrey.scjp.main; import static java.lang.System.*; enum Currency { UNKNOWN, USD { public String getStringCode() { return "USD"; } public int getSomethingElse() { return 10; } }, UAH { public String getStringCode() { return "UAH"; } }, RUR { public String getStringCode() { return "RUR"; } }; public String getStringCode() { return ""; } } public class Application { private static void f (int... a) { for (int i = 0; i < a.length; ++i) { out.println(a[i]); } } public static void main(String args) { out.println(Currency.USD.getStringCode()); // out.println(Currency.USD.getSomethingElse()); } }

В результате выполения этого кода в стандартный поток вывода будет помещена строка «USD». Обратите внимание на метод getSomethingElse(). Он объявлен для значения USD, однако не упоминается для всего перечисления. Не смотря на то, что в объявлении стоит public, никто из вне доступ к этому методу получить не сможет. Если строку за номером 44 раскомментировать, то код даже не скомпилируется.

Немного о массивах

В Java допустимы два варианта объявления массивов. Квадратные скобки могут быть размещены после имени типа, так: int a , - или после идентификатора, так: int a . Важно понимать, что оба способа абсолютно равноправны с точки зрения синтаксиса, хотя первый из них и является рекомендуемым. Таким образом, String s - это ни что иное, как двумерный массив строк. Скомпилируется без вопросов.

При объявлении массива нельзя указать его размер, так как память выделяется только в момент создания массива: int a = new int . Поэтому код int a вызовет ошибку компиляции. В случае с массивом ссылок на объекты важно помнить, что при создании массива сами объекты не создаются. К примеру, код Thread threads = new Thread создаст массив из двадцати null"ов, никаких конструкторов вызываться не будет.

При построении многомерных массивов о них нужно думать, как о массивах, каждый элемент которых ссылается снова на массив. Абстрактные конструкции вроде матриц и кубов упрощают программирование, но могут усложнить сдачу экзамена. К примеру, конструкция int a = new int вполне допустима и создаст двумерный массив, элементы которого могут быть проинициализированы позже: a = new int , - причем совсем не обязательно массивами равной длины: a = new int .

Для того, чтобы проинициализировать массив быстро (не элемент за элементом), можно применять синтаксис вроде этого: int x ={1, 2, 3} . В фигурных скобках могут стоять не только константы, но и переменные и даже выражения. Можно также создавать анонимные массивы, что часто используется когда нужно передать строго определенный массив в функцию: f(new int {2, 4, 8}) . Если вы видите на экзамене такую конструкцию, то обязательно присмотритесь внимательнее. Есть вероятность, что будет написано что-то вроде этого: f(new int {2, 4, 8}) . Такой код не будет скомпилирован, так как размер анонимного массива вычисляется исходя из его объявления и не должен указываться явным образом.

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

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

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

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

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

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

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

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

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

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

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

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

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

Public class State { int a; // все равно, что private int a; private int b; // поле доступно только из текущего класса protected int c; // доступно из текущего класса и производных классов internal int d; // доступно в любом месте программы protected internal int e; // доступно в любом месте программы и из классов-наследников public int f; // доступно в любом месте программы, а также для других программ и сборок protected private int g; // доступно из текущего класса и производных классов, которые определены в том же проекте private void Display_f() { Console.WriteLine($"Переменная f = {f}"); } public void Display_a() { Console.WriteLine($"Переменная a = {a}"); } internal void Display_b() { Console.WriteLine($"Переменная b = {b}"); } protected void Display_e() { Console.WriteLine($"Переменная e = {e}"); } }

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

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

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

Class Program { static void Main(string args) { State state1 = new State(); // присвоить значение переменной a у нас не получится, // так как она закрытая и класс Program ее не видит // И данную строку среда подчеркнет как неправильную state1.a = 4; //Ошибка, получить доступ нельзя // то же самое относится и к переменной b state1.b = 3; // Ошибка, получить доступ нельзя // присвоить значение переменной с то же не получится, // так как класс Program не является классом-наследником класса State state1.c = 1; // Ошибка, получить доступ нельзя // переменная d с модификатором internal доступна из любого места программы // поэтому спокойно присваиваем ей значение state1.d = 5; // переменная e так же доступна из любого места программы state1.e = 8; // переменная f общедоступна state1.f = 8; // Попробуем вывести значения переменных // Так как этот метод объявлен как private, мы можем использовать его только внутри класса State state1.Display_f() ; // Ошибка, получить доступ нельзя // Так как этот метод объявлен как protected, а класс Program не является наследником класса State state1.Display_e(); // Ошибка, получить доступ нельзя // Общедоступный метод state1.Display_a(); // Метод доступен из любого места программы state1.Display_b(); Console.ReadLine(); } }

Таким образом, мы смогли установить только переменные d, e и f, так как их модификаторы позволяют использовать в данном контексте. И нам оказались доступны только два метода: state1.Display_a() и state1.Display_b(). Однако, так как значения переменных a и b не были установлены, то эти методы выведут нули, так как значение переменных типа int по умолчанию инициализируются нулями.

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

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

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

  • модификатор доступа
  • Модификатор Non-доступа

Модификатор используется для определения класса, метода или переменной, как правило, на переднем крае заявления. Через следующий пример для иллюстрации:

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 поддерживает четыре различных прав доступа.

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

Частный, чтобы указан частный модификатор, видимый в пределах того же класса.

Есть, для того, чтобы указать общий модификатор, видимый для всех классов.

Защищенный, в защищенный модификатор определяет, что для всех классов и подклассов в пределах того же пакета видимой.

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

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

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

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

Частный доступ модификатор -private

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

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

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

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

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

Пример, переменный формат класса Logger является частной переменной, так что другие классы не могут непосредственно получить и установить значение переменной. Для того, чтобы иметь возможность работать с другой переменной класса определяет два открытых метода: GetFormat () (формат возвращаемого значения) и SetFormat (String) (настройка формата)

Открытый доступ модификатор -публичный

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

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

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

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

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

Защищенные модификаторы доступа охраняемыми

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

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

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

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

Class AudioPlayer { protected boolean openSpeaker(Speaker sp) { // 实现细节 } } class StreamingAudioPlayer { boolean openSpeaker(Speaker sp) { // 实现细节 } }

Если метод openSpeaker () объявлен как частный, то в дополнение к классу AudioPlayer не может получить доступ к методу. Если openSpeaker () объявлена ​​как публичная, то все классы имеют возможность доступа к методу. Если мы хотим, чтобы сделать процесс видимым для подклассов класса, то метод объявлен как защищенный.

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

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

    Родительский класс объявлен как публичные методы в подклассе также должен быть публичным.

    Класс Родитель объявлен как защищенный метод в подклассе или объявлены как защищенные, либо объявлены публично. Вы не можете быть объявлены закрытыми.

    Родительский класс объявлен как частный метод не может быть унаследован.

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

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

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

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

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

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

Статический модификатор

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

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

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

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

Доступ к переменным класса и методы могут быть использованы непосредственно classname.variablename и classname.methodname доступа.

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

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("Starting with " + InstanceCounter.getCount() + " instances"); for (int i = 0; i < 500; ++i){ new InstanceCounter(); } System.out.println("Created " + InstanceCounter.getCount() + " instances"); } }

Примеры приведенных выше результатов операции редактирования следующим образом:

Started with 0 instances Created 500 instances

Окончательный классификатор

Конечные переменные:

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

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

Public class Test{ final int value = 10; // 下面是声明常量的实例 public static final int BOXWIDTH = 6; static final String TITLE = "Manager"; public void changeValue(){ value = 12; //将输出一个错误 } }

Окончательный метод

Методы конечный класс наследуются подклассами, но не может изменять подклассы.

Основная цель метода заключается в том, чтобы предотвратить окончательное заявление этого метода изменяется.

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

Public class Test{ public final void changeName(){ // 方法体 } }

Окончательная категория

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

Public final class Test { // 类体 }

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

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

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

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

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

Abstract class Caravan{ private double price; private String model; private String year; public abstract void goFast(); //抽象方法 public abstract void changeColor(); }

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

Ни один метод не является абстрактным реализация метода, конкретная реализация метода предоставляемых подклассов. Абстрактные методы не могут быть объявлены в качестве окончательного и строгим.

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

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

Абстрактный объявление метода заканчивается точкой с запятой, например: общественный абстрактный образец ();

Public abstract class SuperClass{ abstract void m(); //抽象方法 } class SubClass extends SuperClass{ //实现抽象方法 void m(){ ......... } }

Синхронное модификатор

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

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

Переходный модификатор

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

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

Public transient int limit = 55; // will not persist public int b; // will persist

Летучие Модификаторы

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

Public class MyRunnable implements Runnable { private volatile boolean active; public void run() { active = true; while (active) // 第一行 { // 代码 } } public void stop() { active = false; // 第二行 } }

При нормальных обстоятельствах, поток вызывает метод () Run (в Runnable открытом потоке) в другом потоке вызовов остановить () метод. Если активное значение в первой строке буфера используется, во втором ряду , когда активный цикл ложна не останавливается.

Тем не менее, приведенный выше код, мы используем модифицированный летучий активный, поэтому цикл остановится.

Привет! В сегодняшней лекции мы познакомимся с понятием «модификаторы доступа » и рассмотрим примеры работы с ними. Хотя слово «познакомимся» будет не совсем правильным: с большинством из них ты уже знаком по предыдущим лекциям. На всякий случай освежим в памяти главное. Модификаторы доступа - это чаще всего ключевые слова, которые регулируют уровень доступа к разным частям твоего кода. Почему «чаще всего»? Потому что один из них установлен по умолчанию и не обозначается ключевым словом:) Всего в 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 к полю agent_counter , и тогда получить его значение смогут либо объекты других классов секретных агентов, либо те классы, которые расположены в нашем «секретном» пакете top_secret . public abstract class AbstractSecretAgent { protected static int agent_counter = 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() и т.д.

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; }

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



© 2024 beasthackerz.ru - Браузеры. Аудио. Жесткий диск. Программы. Локальная сеть. Windows