Java protected что дает. Модификаторы доступа. Private, protected, default, public. Открытый доступ модификатор -публичный

Java protected что дает. Модификаторы доступа. Private, protected, default, 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 и потом ее использовать в этих программах.

Здесь мы постараемся рассмотреть почти все случаи применения модификаторов доступа. Исключение составят лишь их применение для вложенных (nested ) и внутренних (inner ) классов, а так же для интерфейсов, так как эти темы мы еще пока не рассматривали.

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

Модификаторы доступа могут применяться как к классам, так и их членам – полям и методам. Всего существует четыре модификатора доступа и тут приведем их краткое описание, потом рассмотрим каждый подробно.

  • public – любой компонент, объявленный как public , доступен из любого кода
  • protected – разрешает доступ к компоненту в пределах пакета и классам наследникам
  • private – разрешает доступ к компоненты в пределах класса
  • по умолчанию (нет ключевого слова) – разрешает доступ к компонентам в пределах пакета

Классы наследники – это классы унаследованные от какого-либо класса. Наследование мы пока еще не изучали .

Доступ к классам

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

Доступ к членам класса

Члены класса всегда доступны внутри тела класса. По умолчанию члены класса также доступны в пакете, в котором класс определен .

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

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

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

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

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

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

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

protected .

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

Это самый жесткий по ограничению доступа модификатор. Элементы объявленные как private доступны только внутри этого же класса и ни кому вне класса.

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

Классы и интерфейсы верхнего уровня не могут быть объявлены как private .

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

Я создал классы Mod02.java, DefMod.java, ProMod.java и PrvMod.java которые принадлежат пакету pro.java.pkg002, а так же класс PubMod.java, принадлежащий пакету pro.java.pkg003. Далее приведу просто скрины этих классов и результат работы программы:

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

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

Класс Modifier
Класс Modifier кодирует все модификаторы,
используемые в объявлениях типа, в виде
констант:
ABSTRACT, FINAL, INTERFACE, NATIVE,
PRIVATE, PROTECTED, PUBLIC, STATIC,
STRICT, SYBCHRONIZED, TRANSIDENT,
VOLATILE.
Каждой из констант отвечает метод запрос вида
isMod(int modifier) (тут Mod одно из выше
приведенных имен, например, isPublic),
который возвращает true, если модификатор
mod присутствует в объявлении типа.

Рассмотрим пример. Пусть имеется
объявление поля
public static final int s=10;
тогда значение возвращаемое методом
getModifiers соответствующего объекта
класса Field будет иметь вид
Modifier.PUBLIC | Modifier.STATIC |
Modifier.FINAL
Модификатор strictfp представляется
константой STRICT.
Методы- запросы можно использовать в
следующей форме

Modifier.isPrivate(field.getModifiers());
это эквивалентно следующему условию
(field.getModifiers()&Modifier.PRIVATE)!=0
Класс Field
В составе класса Field реализованы методы,
позволяющие запрашивать информацию о
типе поля, а также считывать и задавать его
значение.
Рассмотрим некоторые методы класса Field
1. getType() – возвращает объект класса
Class, отвечающий типу текущего поля.
Например, для поля типа int, получим
int.class.

2. Методы set и get – позволяют считывать
текущее значение поля, а также задавать новое.
Рассмотрим пример:
public static void printField(Object o,
String name) throws
NoSuchFieldException,
IllegalAccessException{
Field field = o.getClass().getField(name);
Short value = (Short) field.get(o);
System.out.println(value);
}
Т.е. метод get возвращает значение, на которое
ссылается соответствующее поле или объект
класса –оболочки.
Пример использования метода set имеет вид:

public static void setField(Object o, String name,
short nv) throws
NoSuchFieldException,
IllegalAccessException{
Field field = o.getClass().getField(name) ;
field.set(o,new Short(nv));
}
Для сохранения nv в поле данного объекта
необходимо использовать классы оболочки.
Существуют также методы имеющие вид
getPrimitiveType (например, getInt) и
setPrimitiveType. Эти методы можно
использовать для изменения полей в классе,
имеющих примитивный тип. Например,
field.setShort(o,nv);

Класс Method
Средства класса Method - позволяют получать
полную информацию, касающуюся
объявлений методов определенного класса,
и при необходимости вызывать эти методы в
контексте заданных объектов.
Рассмотрим методы класса Method.
1. public Class getReturnType() - возвращает
объект Class, соответствующий типу
значения, возвращаемого текущим методом.
Если вместо типа возвращаемого значения в
объявлении метода указано служебное
слово void, рассматриваемый метод вернет
объект void.class.

2. public Class getParameterTypes() - возвращает

параметров, которые заданы в объявлении
текущего метода. Объекты заносятся в массив в
том порядке, в каком параметры перечислены в
объявлении метода. Если метод не имеет
параметров, возвращается пустой массив.
3. public Class getExceptionTypes() - возвращает
массив объектов Class, соответствующих типам
исключений, которые заданы в предложении
throws объявления текущего метода. Объекты
заносятся в массив в том порядке, в каком
наименования типов исключений перечислены в
объявлении метода.

4. public Object invoke(Object onThis, Object args)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
Вызывает метод, определяемый текущим объектом
Method, в контексте объекта onThis с заданием
значений аргументов, передаваемых массивом args.
Для нестатических методов выбор реализации
осуществляется на основании фактического типа
объекта, определяемого параметром onThis. Для
статических методов onThis не принимается во
внимание и может быть равен null.
Длина массива args должна совпадать с числом
параметров в объявлении метода, а типы объектовэлементов массива должны допускать присваивание
соответствующим типам параметров метода - в
противном случае будет выброшено исключение
IIlegalArgumentException.

10.

Если в составе объекта, определяемого
параметром onThis, нет типа, членом
которого является текущий метод,
выбрасывается исключение
IllegalArgumentException.
Если значение onThis равно null и метод не
статический, генерируется исключение типа
NullPointerException.
Если выполнение вызываемого метода
завершается аварийно, выбрасывается
исключение типа InvocationTargetException.

11.

Рассмотрим пример. Вызовем средствами
рефлексии метод return str.indexOf(".", 8)
тогда имеем
try {
Сlass strClass = str.getClass();
Method indexM = strClass.getMethod("indexOf",
new Class { string.class, int.class });
Object result = indexM.invoke(str, new object {
".", new lnteger(8)});
return ((Integer) result).intValue();
}
catch (NoSuchMethodException e) { …….. }
catch (invocationTargetException e) {…….. }
catch (illegalAccessException e) {……}

12.

Класс Constructor
Для создания новых экземпляров (объектов)
типа может быть использован метод
newlnstance объекта Class,
соответствующего этому типу.
Метод вызывает конструктор без аргументов,
принадлежащий типу, и возвращает ссылку
на вновь созданный объект класса Object,
который должен быть явно преобразован к
требуемому типу.
Рассмотрим пример.

13.

static double testData = { 0.3,1.3e-2, 7.9, 3.17 };

try {
for(int arg = 0; arg < args.length; arg++){
String name = args;
Class classFor = Class.forName(name);
SortDouble sorter =
(SortDouble)classFor.newInstance();
SortMetrics metrics = sorter.sort(testData);
System.out.println(name + ": " + metrics);
for(int i =0; i < testData.length; i++)
System.out.println(“ " + testData[i]); } }
catch(Exception e) { System.err.println(e); } }

14.

Метод newlnstance при некорректном
применении способен выбрасывать большое
число объектов исключений различных
типов.
InstantiationException-если класс, объект
которого должен быть создан, не обладает
конструктором без аргументов, либо
определен как абстрактный, либо в
действительности является интерфейсом,
либо выполнение процедуры создания
объекта прерывается по каким-либо иным
причинам.
IllegalAccessException - если класс либо его
конструктор без аргументов недоступны.

15.

SecurityException - если действующая политика
безопасности запрещает создание новых объектов
ExceptionInInitializerError –выбрасывается при
инициализации класса.
В классе Constructor определены и другие методы.
public Сlass getParameterTypes()

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

16.

public Object newlnstance(Object args)
throws InstantiationException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
Использует конструктор, представляемый текущим
объектом Constructor, для создания и инициализации
нового экземпляра класса, в котором конструктор
объявлен, с передачей заданных аргументов.
Возвращает ссылку на вновь созданный и
инициализированный объект. Длина массива args
должна совпадать с числом параметров в
объявлении конструктора, а типы объектовэлементов массива должны допускать присваивание
соответствующим типам параметров конструктора -
в противном случае будет выброшено исключение
IllegalArgumentException.

17.

Рассмотрим пример:
class Myclass {
private int a;
public Myclass(int k){a=k;}
public int func(int a,int b){return a+b;}
}
public class Main{
public static void main(String args){
try{
String name="Myclass";
Class mycl=Class.forName(name);
Class d={int.class};
Constructor c=mycl.getConstructor(d);
Myclass ob=(Myclass)c.newInstance(new Object{
new Integer(10)});
System.out.println(ob.func(3,5)); }
catch(Exception e){};
}}

18.

Класс AccessibleObject
Классы Field, Constructor и Method являются
производными от класса AccessibleObject,
который дает возможность разрешать или
запрещать проверку признаков доступа уровня
языка, таких как public и private.
Класс AccessibleObject имеет методы
1. public void setAccessible(boolean flag)
Устанавливает флаг доступа к объекту в
соответствии со значением аргумента: true
означает, что объект больше не подчиняется
правилам доступа, устанавливаемым на уровне
языка (и будет всегда доступен), a false
вынуждает объект поддерживать заданный
уровень доступа.
Если полномочий по изменению флага доступа
недостаточно, выбрасывается исключение типа
SecurityException

19.

2. public static
void setAccessible(AccessibleObject array,
boolean flag)
Позволяет установить флаг доступа к
объектам, передаваемым в виде массива.
Если в процессе обработки очередного
объекта выбрасывается исключение типа
SecurityException, объекты, расположенные
в массиве ранее, сохраняют вновь заданные
значения уровня доступа, а все остальные
объекты остаются в прежнем состоянии.
3. public boolean isAccessible()
Возвращает текущее значение флага доступа
к объекту

20.

Класс Array
Класс Array используется для создания массива
средствами рефлексии.
Для создания массивов используются две формы метода
newInstance.
public Object newlnstance(Class compType, int length)
Возвращает ссылку на новый массив типа compType
заданной длины length.
public Object newInstance(Class compType, int dim)
Возвращает ссылку на новый многомерный массив типа
compType, размерности которого заданы значениями
элементов массива-параметра dim.
Если массив dim пуст или обладает длиной, превышающей
допустимое число размерностей (обычно 255),

llegalArgumentException.

21.

Рассмотрим примеры.
Пример1. Сформируем массив типа byte
byte ba = (byte)
Array.newlnstance(byte.class,13);
Это равнозначно
byte ba = new byte;
Пример2.
int dims = {4, 4};
double matrix =(double)
Array.newlnstance(double.class, dims);
Это равнозначно
double matrix = new double;

22.

Класс Array обладает методами get и set.
Пусть задан массив ха значений типа int; тогда
выражению xa[i] будет соответствовать:
Integer n=Array.get(xa, i)
Присвоить значение элементу массива можно так:
xa[i] = 23; - это то же самое, что
Array.set(xa, i, new Integer(23));
Класс Package
Вызов метода getPackage класса Class позволяет
получить объект класса Package, содержащий
описание пакета, в составе которого определен
класс (сам класс Package размещен в пакете
java.lang).
Метод getName() объекта Package возвращает
полное имя текущего пакета.

23.

Класс Proxy
Класс Proxy позволяет динамически создавать
классы, реализующие один или несколько
интерфейсов.
Предположим, что имеется класс A,
реализующий некоторые интерфейсы.
Java-машина во время исполнения может
сгенерировать прокси-класс для данного
класса A, т.е. такой класс, который
реализует все интерфейсы класса A, но
заменяет вызов всех методов этих
интерфейсов на вызов метода invoke,
интерфейса InvocationHandler,для
которого можно определять свои
реализации.

24.

Создается прокси-класс с помощью вызова метода
Proxy.getProxyClass, который принимает ClassLoader и
массив интерфейсов (interfaces), а возвращает объект
класса java.lang.Class, который загружен с помощью
переданного ClassLoader и реализует переданный массив
интерфейсов.
На передаваемые параметры есть ряд ограничений:
1. Все объекты в массиве interfaces должны быть
интерфейсами. Они не могут быть классами или
примитивами.
2. В массиве interfaces не может быть двух одинаковых
объектов.
3. Все интерфейсы в массиве interfaces должны быть
загружены тем ClassLoader, который передается в метод
getProxyClass.
4. Все не публичные интерфейсы должны быть определены
в одном и том же пакете, иначе генерируемый прокси-класс
не сможет их все реализовать.

25.

5. Ни в каких двух интерфейсах не может быть
метода с одинаковым названием и
сигнатурой параметров, но с разными
типами возвращаемого значения.
6. Длина массива interfaces ограничена
65535-ю интерфейсами. Никакой Java-класс
не может реализовывать более 65535
интерфейсов.

26.

Свойства динамического прокси-класса
1. Прокси-класс является публичным, снабжен
модификатором final и не является абстрактным.
2. Имя прокси-класса по-умолчанию не
определено, однако начинается на Proxy. Все
пространство имен, начинающихся на Proxy
зарезервировано для прокси-классов
последних версиях Java это не обязательно).
3. Прокси-класс наследуется от
java.lang.reflect.Proxy.
4. Прокси-класс реализует все интерфейсы,
переданные при создании, в порядке передачи.

27.

5. Если прокси-класс реализует непубличный
интерфейс, то он будет сгенерирован в том пакете,
в котором определен этот самый непубличный
интерфейс. В общем случае пакет, в котором
будет сгенерирован прокси-класс неопределен.
6. Метод Proxy.isProxyClass возвращает true для
классов, созданных с помощью
Proxy.getProxyClass и для классов объектов,
созданных с помощью Proxy.newProxyInstance и
false в противном случае.
Данный метод используется подсистемой
безопасности Java и нужно понимать, что для
класса, просто унаследованного от
java.lang.reflect.Proxy он вернет false.

28.

Свойства созданного экземпляра прокси-класса следующие:
1. Объект прокси-класса приводим ко всем интерфейсам,
переданным в массиве interfaces. Если IDemo - один из
переданных интерфейсов, то операция proxy instanceof
IDemo всегда вернет true, а операция (IDemo) proxy
завершится корректно.
2. Статический метод Proxy.getInvocationHandler
возвращает обработчик вызовов, переданный при создании
экземпляра прокси-класса. Если переданный в данный
метод объект не является экземпляром прокси-класса, то
будет выброшено IllegalArgumentException исключение.
3. Класс-обработчик вызовов реализует интерфейс
InvocationHandler, в котором определен метод invoke,
имеющий следующую сигнатуру:
public Object invoke(Object proxy, Method method,
Object args) throws Throwable

29.

Рассмотрим пример:
package javaapplication3;
interface Account {
double getBalance();
void changeBalance(int sum);
void percents(double per);}
class MyAccount implements Account{
private double balance;
public MyAccount(){ balance=0.0; }
public double getBalance(){ return balance; }
public void changeBalance(int sum){
balance+=sum;}
public void percents(double per){
balance+=balance*per/100; }; }

30.

class MyAccountProxy implements
InvocationHandler{
private Account ac;
public MyAccountProxy(Account acc){ ac=acc; }
public static Account newInstance(Account da){
return (Account)Proxy.newProxyInstance(
da.getClass().getClassLoader(),
da.getClass().getInterfaces(),
new MyAccountProxy(da));
}

31.

public Object invoke(Object proxy,
Method method, Object args)
throws Throwable{
if(method.getName()=="percents"){
double d=((Double)args).doubleValue();
if (d<0) d=0;
if(d>30) d=30;
args=new Double(d);

else{
return method.invoke(ac, args); }
}
}

32.

public class Main{
public static void main(String args){
MyAccount ma=new MyAccount();
Account
a=(Account)MyAccountProxy.newInstance(ma);
a.changeBalance(150);

a.percents(20);
System.out.println(a.getBalance());
a.percents(35);
System.out.println(a.getBalance());} }

33.

Загрузка классов
Исполняющая система загружает классы по мере
возникновения необходимости в них.
Функциональные особенности процедур загрузки
классов существенным образом зависят от
реализации виртуальных машин Java, но в
большинстве случаев для отыскания классов,
адресуемых приложением, но не загруженных
исполняющей системой, применяется механизм
просмотра пути поиска классов.
Чтобы создать приложение, которое в состоянии
загружать классы способами, отличными от
предусмотренных по умолчанию, следует
воспользоваться объектом класса ClassLoader,
способным получить байт-код реализации нужного
класса и загрузить его в среду исполняющей
системы.

34.

Класс ClassLoader является абстрактным классом.
Для создания собственного загрузчика классов,
необходимо создать класс – наследник от
ClassLoader и переопределить метод
protected Class findClass(String name) throws
ClassNotFoundException
Который находит байт-код класса с заданным
именем name и загружает данные в среду
виртуальной машины, возвращая объект Class,
представляющий найденный класс.
Объект-загрузчик способен делегировать
полномочия по загрузке классов "родительскому"
загрузчику классов (parent class loader).
"Родительский" загрузчик классов может быть
задан в качестве аргумента конструктора класса
ClassLoader.

35.

protected ClassLoader()
Создает объект ClassLoader, неявно
используя в качестве "родительского"
загрузчика классов системный загрузчик
(который может быть получен посредством
вызова метода getSystemClassLoader).
protected ClassLoader(ClassLoader parent)
Создает объект ClassLoader, используя
заданный "родительский" загрузчик классов.
Основным в составе класса ClassLoader
является метод loadClass

36.

public Сlass loadClass(String name) throws
ClassNotFoundException
возвращает объект Class для класса с заданным
именем и при необходимости загружает этот
класс. Если класс не может быть загружен,
выбрасывается исключение типа
ClassNotFoundException.
Схема загрузки классов, предлагаемая методом
loadClass по умолчанию и обычно не
переопределяемая, выглядит так:
1. проверить посредством вызова метода
findLoadedClass класса ClassLoader, не
загружался ли заданный класс раньше; в составе
ClassLoader предусмотрена таблица объектов
Class для всех классов, загруженных средствами
текущего загрузчика классов; если класс был
загружен прежде, метод findLoadedClass
возвратит ссылку на существующий объект Class;

37.

2. если класс не загружался, вызывается
loadClass "родительского" загрузчика
классов; если текущий загрузчик не
обладает "родителем", используется
системный загрузчик классов;
3. если класс все еще не загружен,
вызывается метод findClass, выполняющий
поиск и загрузку класса.
Таким образом, необходимо реализовать
собственные версии следующих методов
ClassLoader:

38.

protected synchronized Class
loadClass(String name,boolean resolve)

protected Class findClass(String name)
throws ClassNotFoundException
protected java.net.URL findResource(String name)
protected java.util.Enumeration
findResources(String name) throws IOException
(Абстрактный класс ClassLoader представляет
только реализацию метода loadClass, основанную
на protected-методах – findLoadedClass и findClass).

39.

Рассмотрим пример.
class PlayerLoader extends ClassLoader {
public Class findClass(String name) throws
ClassNotFoundException {
try {
byte buf = bytesForClass(name);
return defineClass(name, buf, 0, buf.length);
}
catch (IOException e) {
throw new ClassNotFoundException(e.toString());
}
}
// ... Объявления метода bytesForClass и других
методов
}

40.

Метод findClass обычно выполняет две
функции.
Во-первых, он должен обнаружить байт-код
заданного класса и сохранить его в массиве
типа byte - эта обязанность в примере
возложена на метод bytesForСlass.
Во-вторых, он использует прикладной метод
defineСlass, чтобы выполнить фактическую
загрузку класса, определяемого байт-кодом.
Метод defineСlass имеет вид

41.

protected final Class defineClass(String name,
byte data, int offset, int length) throws
ClassFormatError
Возвращает объект Class для класса с заданным именем
name; бинарное представление класса передается в
виде массива data.
Для загрузки класса используются только байты,
содержащиеся в элементах массива data с индексами
от offset до offset+length. Если байты из указанного
промежутка не удовлетворяют требуемому формату
описания класса, выбрасывается объект исключения
типа ClassFormatError.
Метод ответствен за сохранение ссылки на объект
Class для загруженного класса в таблице загруженных
классов, просматриваемой методом findLoadedClass.

42.

Рассмотрим метод bytesForClass.
protected byte bytesForClass(String name) throws
lOException, ClassNotFoundException{
FileInputStream in = null;
try {


if (length == 0) throw new ClassNotFoundException(name);
byte buf = new byte;

return buf;
}
finally {
if (in!=null) in.close();
}
}

43.

Таким образом полный код имеет вид:
import java.lang.reflect.*;
import java.io.*;
class MyClassLoader extends ClassLoader{
public Class findClass(String name) throws
ClassNotFoundException {
byte buf=ReadFromBuffer(name);
if(name.equals("MyInterface1")){

} else if(buf==null) {
return findSystemClass(name);
} else {
return defineClass(name,buf,0,buf.length);
}
}

44.

protected byte ReadFromBuffer(String name) throws
ClassNotFoundException {
FileInputStream in = null;
try {
in = new FileInputStream(name + ".class");
int length = in.available(); // число доступных байтов
if (length == 0) throw
new ClassNotFoundException(name);
byte buf = new byte;
in.read(buf); // Считывание байтов
return buf;
}
catch(FileNotFoundException e){ return null;}
catch(IOException e){ return null;}
finally{
try{ if (in!=null) in.close(); }
catch(IOException e){ }
}
}

45.

protected synchronized Class
loadClass(String name,boolean resolve) throws
ClassNotFoundException{
Class result= findClass(name);
if (resolve) resolveClass(result);
return result;
}
}

46.

public class Main1 {
public static void main(String args) {
try{
String name="Myclass";
ClassLoader ld=new MyClassLoader();
Class cl=Class.forName(name, true, ld);
Constructor s=cl.getConstructor(int.class);
MyInterface1
ob=(MyInterface1)s.newInstance(
new Integer(8));
System.out.println(ob.func(3,5));
}catch(Exception e){ };
}
}

47.

public interface MyInterface1{
public int func(int a,int b);
}
public class Myclass implements MyInterface1 {
private int a;
public Myclass(int k) { a=k; }
public int func(int a,int b){ return a+b; }

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

Модификаторы в 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 будем говорить в статье ООП.

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