Document 7206085

Download Report

Transcript Document 7206085

Объектно-ориентированный анализ
и программирование
Лекция 8.
Информация о типах
к.т.н. Гринкруг Е.М. (email: [email protected])
20-May-16
Software Engineering
1
Runtime Type Information
• Механизм получения и использования информации о типах во
время исполнения программы – важный механизм ООП.
• Рассмотрим пример:
– Абстрактный класс Shape c методом draw();
– Три конкретных производных класса (м.б. и другие разновидности):
20-May-16
Software Engineering
2
Пример реализации
20-May-16
Software Engineering
3
Как это работает? Что будет выведено?
•
•
•
•
•
•
•
•
Сам класс Shape не может инстанциироваться;
Метод draw() базового класса Shape неявно использует метод toString() для вывода
«названия» контретной фигуры;
Для этого методу System.out.println() передается ссылка this;
Метод toString() в Shape – абстрактный. Он:
– Переопределяет метод toString() из java.lang.Object;
– Обязывает производные от Shape классы определить toString().
Когда this встречается в выражении конкатенации строк, автоматически вызывается
его toString();
При помещении экземпляров конкретных форм в массив абстрактных форм
происходит восходящее преобразование типа; массив хранит просто объекты Shape.
Далее – работает полиморфизм: для каждой фигуры вызывается ее метод draw() и ее
метод toString();
Выводится результат:
Circle.draw()
Square.draw()
Triangle.draw()
•
Как быть, если все-таки хочется узнать, с каким точно типом Shape мы работаем
(например, чтобы покрасить треугольники в красный цвет)? Как узнать тип
объекта, имея ссылку базового типа?
20-May-16
Software Engineering
4
Объект Class
• Каждый класс, задействованный в программе, представлен
своим объектом Class:
– При написании и компиляции нового класса для него создается
объект Class, который сохраняется в одноименном файле с
расширением .class:
– Этот объект загружается загрузчиком классов (ClassLoader’ом);
• Загрузка классов может выполняться разными реализациями
загрузчиков классов, которые могут организовывать древовидную
структуру;
• Основной (корневой) загрузчик является частью реализации JVM;
• Именно этот загрузчик загружает доверенные классы, включая Java
API, с локального диска;
• Дополнительные загрузчики классов могут подгружать классы с вебсервера, по сети или даже помогать «сочинять их на лету»...
– Все классы загружаются в JVM динамически, при первом
использовании;
• Загруженный байт-код проверяется JVM на корректность.
20-May-16
Software Engineering
5
Объект Class
• Объект Class – это тоже объект, представленный ссылкой, и
которым можно манипулировать в программе, располагая ссылкой
на него.
• Всякий объект имеет метод из класса java.lang.Object:
public final Class getClass();
- Возвращает сылку на класс объекта (класс, создавший данный объект);
- Ссылка всегда доступна и не может быть сфальсифицирована;
Например:
void myMethod ( Object parameter ) {
Class parameterClass = parameter.getClass(); // …
}
- испольуем getClass() для получения класса фактического параметра во
время исполнения (at runtime)...
20-May-16
Software Engineering
6
Класс Class
•
Все объекты Class принадлежат public final классу Class:
Object о = new Object();
Class oc = o.getClass();
Class cc = oc.getClass();
(cc.getClass() == cc) --> true;
// или new Triаngle(), и т.п. и т.д.
// все классы – суть экземпляры класса Class !!!
// и сам класс Сlass – это тоже класс !!!
// его класс – это он сам !!!
Класс Class – это «метакласс, определяющий операции, которые можно производить с объектами Class» (кто
укажет - какова аналогия с C# ?)
•
Как и для любых объектов, имея ссылку на объект, можно выполнить над этим
объектом операцию, определенную в классе объекта (т.е. инстанс-метод):
– Имея ссылку на конкретный класс, можно вызывать (нестатические) методы класса
Class для данного конкретного класса.
•
Как и любой класс, класс Class имеет статические методы, не требующие
наличия экземпляра (объекта Class) для их вызова.
•
Cостав и принципы реализации методов класса Class являются основой
реализации принципов объектно-ориентированного программирования в Java,
наряду с методами класса Object.
20-May-16
Software Engineering
7
Основные методы класса Class
• Любой объект Class является immutable-объектом (что это
означает?); все методы класса Class «добывают» информацию из
объектов Class’ов, а не меняют ее.
• Получение имени класса:
– String getName (); // дает полное имя класса (с jdk 1.0)
• Например, “com.grinkrug.rtti.Triangle”
– String getSimpleName (); // дает короткое имя класса (c jdk1.5)
• Например, “ Triangle”
– String getCanonicalName (); // дает каноническое имя класса (с
jdk1.5)
• Например, “com.grinkrug.rtti.Triangle”
• В отличие от getName() возвращает полные имена вложенных
классов через ‘.’ (точку), а не знак ‘$’, null для локальных и
анонимных классов...(сравните их результаты для массивов и разных
внутренних классов, включая локальные и анонимные!);
20-May-16
Software Engineering
8
Еще раз об именовании классов
•
•
•
Полное имя top-level класса / интерфейса – это имя пакета+простое имя класса:
сom.grinkrug.rtti.Triangle
Полное имя примитивного типа – это соответствующее ключевое слово:
int, byte, float …
Исторически имя класса массива представляется как символы ‘[‘ (количество их
подряд соответственно размерности массива) + имя типа элементов,
где примитивные типы элементов кодируются символами, а ссылочные –
символом L+ <имя типа> + ’;’
boolean
Z
float
byte
B
int
char
C
long
double
D
short
Класс или интерфейс L
F
I
J
S
Например: [ [ F – двумерный массив float и [Ljava.lang.Object; – массив Object’ов.
Канонические имена появились в jdk1.5(+), они выглядят лучше, но не заменяют
«полные имена» (fully qualified names) из прежних jdk.
20-May-16
Software Engineering
9
• Получение класса по имени (static - метод):
public static Class forName ( String className )
throws СlassNotFoundException;
– получает ена вход полное имя требуемого класса (fully qualified name);
– возвращает ссылку на объект Class, соответствующий указанному
имени (подгружая нужный класс при необходимости, со всеми
другими, нужными для него...).
• Получение класса по класс-литералу:
– Если нужный класс статически известен, ссылку на него можно
получить из класс-литерала: Class c = Triangle.class;
– Используется каноническое имя (в отличие от fully qualified name для
метода forName()): Object[].class;
– Получение ссылки обеспечивается компилятором (а не в динамике,
при вызове метода) и инициализация откладывается до первого
использования класса при исполнении – как можно позже.
В Java нет структурной эквивалентности типов, то есть тождественность
типов определяется их именами, а не тем, что они одной структуры,
т.е. «совпадают при наложении». Поэтому, имена типов – важны.
20-May-16
Software Engineering
10
Методы класса Сlass для анализа представляемого классом типа
По объекту Class можно узнать практически все, что может
потребоваться знать о типе.
•
Является ли данный класс интерфейсом?
public boolean isInterface ( );
•
Является ли данный класс классом массива?
public boolean isArray ( );
- и если является, то:
public Class getComponentType ( );
•
Является ли даный класс Enum-ом?
public boolean isEnum ( );
•
Представляет ли данный класс примитивный тип?
public boolean isPrimitive ( );
•
Является ли даный класс анонимным?
public boolean isAnonimousClass ( );
•
Является ли даный класс локальным?
public boolean isLocalClass();
•
Является ли даный класс классом-членом (вложенным)
public boolean isMemberClass ( );
•
Какой класс декларировал данный класс?
public Class getDeclaringClass ( );
20-May-16
Software Engineering
11
•
•
•
•
•
•
Какие интерфейсы реализуются данным классом или интерфейсом?
public Class[] getInterfaces();
Какой суперкласс у данного класса?
public Class getSuperclass();
Представляет ли данный класс суперкласс / суперинтерфейс другого?
public boolean isAssignableFrom (Class another);
Каким загрузчиком классов был получен данный класс?
public ClassLoader getClassLaoder();
Какому пакету принадлежит данный класс?
public Package getPackage();
Является ли переданный объект инстансом данного класса?
public boolean isInstance(Object o);
это – динамический эквивалент оператора instanceof:
if(shape instanceof Triangle ){
Triangle t = (Triangle)shape;
}
Приведите пример, когда нужен такой динамический эквивалент ? Чем по сути
отличаются метод isInstance() и оператор instanceof ?
20-May-16
Software Engineering
12
Reflection – динамическая работа с классом
•
Как быть, если мы хотим работать в такой ситуации:
– Мы пишем программу, которая работает с некоторыми классами;
– Нам передали какие-то классы (без исходного кода), и сказали –
используйте их.
•
Эта ситуация – типичная для компонентного программирования:
– Кто-то делает компоненты разного назначения;
– Мы используем из «по мере поступления», как детали нашего изделия, без
«переплавки», как есть (т.е. без перекомпиляции вообще);
•
Подобная компонентность может быть полезна и на уровне
межкомпьютерного (сетевого) взаимодействия:
– Для удаленных вызовов методов (Remote Method Invocation, RMI), где мы
можем работать с классами на другой машине, про существовании которых
не знали при компиляции нашей программы.
– Для универсальной сериализации / десериализации объектов, и. др.
20-May-16
Software Engineering
13
Класс Class и reflection
• Класс Class поддерживает концепцию Reflection (как в переводе?)
• Дополнительная поддержка обеспечивается пакетом java.lang.reflect.
• В библиотеке java.lang.reflect есть классы, объекты которых
создаются JVM для педставления членов класса в динамике
выполнения программы. Основными из них являются:
– Constructor
– Method
– Field
• Класс Class имеет методы, позволяющие получить эти объекты для
заданного экземпляра класса и использовать их в динамике. Кроме
того, в самом классе Class есть методы для анализа его вложенных
классов, и т.д.
20-May-16
Software Engineering
14
Извлечение информации о конструкторах класса
(продолжение обзора методов класса Class)
• Получение всех public конструкторов класса:
public Constructor [ ] getConstructors ( ) throws SecurityException;
• Получение всех конструкторов класса (включая приватные):
public Constructor [ ] getDeclaredConstructors ( ) throws SecurityException;
• Получение заданного public - конструктора класса:
public Constructor getConstructor (Class… paramTypes)
throws NoSuchMethodException, SecurityException;
• Получение заданного конструктора, декларированного в классе:
public Constructor getDeclaredConstructor (Class… paramTypes)
throws NoSuchMethodException, SecurityException;
20-May-16
Software Engineering
15
Инстанциирование класса
• Имеющийся класс сам может создавать свои экземпляры (при
наличии конструктора без аргументов):
public Object newInstance() throws
InstantiationException,IllegalAccessException
Объект конструктор (java.lang.reflect.Constructor) позволяет:
– Выполнить дальнейший анализ (узнать все про данный
конструктор), т.е. -типы параметров, исключений, ...
– Выполнить создание и инициализацию нового объекта класса,
которому принадлежит конструктор (класса, где конструктор был
декларирован), с заданными параметрами; например:
static Object createInstance(Constructor c, Object[ ] params) throws Exception{
return c.newInstance(params);
}
20-May-16
Software Engineering
16
Извлечение информации о методах класса
(продолжение обзора методов класса Class)
• Получение всех public методов класса:
public Method[ ] getMethods ( ) throws SecurityException;
• Получение всех методов класса (включая приватные, но исключая
все унаследованные):
public Method[ ] getDeclaredMethods ( ) throws SecurityException;
• Получение заданного public - метода класса:
public Method getMethod (String name, Class… paramTypes)
throws NoSuchMethodException, SecurityException;
• Получение заданного метода, декларированного в классе:
public Method getDeclaredMethod (String name, Class… paramTypes)
throws NoSuchMethodException, SecurityException;
20-May-16
Software Engineering
17
Использование объекта Method
• Как и объект Constructor, объект Method может показать
информацию о себе (типы параметров, возвращаемого
значения, принимает ли он переменное число аргуменотов, и
пр.)
• Основное применение – определенная классом Method
операция вызова метода:
public Object invoke (Object obj, Object … args)
throws IllegalAccessException, AllegalArgumentException,
InvocationTargetException;
• Например:
static Object callMethod (Object o, Method m,
Object…params)
throws Exception {
return m.invoke (o, params);
}
20-May-16
Software Engineering
18
Работа с полями класса
(продолжение обзора методов класса Class)
• Получение всех public полей класса:
public Field[ ] getFields ( ) throws SecurityException;
• Получение всех полей класса (включая приватные, но исключая все
унаследованные):
public Field[ ] getDeclaredFields ( ) throws SecurityException;
• Получение заданного public - поля класса по имени:
public Field getField (String name)
throws NoSuchFieldException, SecurityException;
• Получение заданного поля, декларированного в данном классе:
public Field getDeclaredField (String name)
throws NoSuchFieldException, SecurityException;
20-May-16
Software Engineering
19
Работа с полями класса
•
Класс Field используется для доступа к значению поля класса у конкретного объекта;
•
Если поле в классе – статическое, то конкретный объект в опрециях доступа
игнорируется и может быть null;
•
Для доступа к значению поля в классе Field есть набор методов
чтения:
public Object get (Object concreteObject)
throws IllegalArgumentException, IllegalAccessExpubliction;
public int getInt (Object concreteObject)
throws IllegalArgumentException, IllegalAccessExpubliction;
// и для других примитивных типов;
и записи:
public void set (Object concreteObject, Object newValue)
throws IllegalArgumentException, IllegalAccessExpubliction;
public void setInt (Object concreteObject, int newValue)
throws IllegalArgumentException, IllegalAccessExpubliction;
// и для дргих примитивных типов
20-May-16
Software Engineering
20
Reflection и массивы
•
•
В библиотеке reflection есть утилитный класс для динамического
создания массивов и доступа к ним – java.lang.reflect.Array.
В этом классе:
– Опрерации создания массива:
public static Object newInstance(Class componentType, int length)
throws NegativeArraySizeException;
public static Object newInstance(Class componentType, int… dimensions)
throws IllegalArgumentException, NegativeArraySizeException;
– Операции доступ к элементам массива:
public static Object get (Object array, int index)
throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
public static void set (Object array, int index, Object newValue)
throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
и их аналоги для примитивных типов элементов массива...
•
При каких ситуациях полезна динамическая работа с массивами?
20-May-16
Software Engineering
21
Недостатки динамических средств reflection
• Эти недостатки – обратная сторона достоинств:
– Нет статического контоля, все откладывается на runtime;
– Нет защиты (без специальных динамических средств) от
обращений к приватным полям (проверьте это!);
– Динамические вызовы происходят медленнее (хотя этот аспект
реализации постоянно оптимизируется);
20-May-16
Software Engineering
22
Усовершенствования reflection
• С внедрением новых средств в JDK 5(+) появились
соответствующие дополнения в reflection-библиотеке и в самом
классе Class;
• Они касаются новых способов определения и работы с типами,
добавленными в Java;
• Мы рассмотрим такие усовершенствования и средства reflection
для них в дальнейшем.
20-May-16
Software Engineering
23
Q&A
20-May-16
Software Engineering
24