Reflection

Часто разработчики не знают с какими классами будут работать.

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

Центральное место в рефлексии занимает класс с названием Class пакета java.lang.Class, объекты класса Class содержат информацию о классах для которых они созданы. С помощью объекта класса Class можно получить информацию о полях, методах, конструкторах других классов. У самого класса Class, конструктора открытого нету. Классы создаются виртуальной машиной и получить доступ к информации о классах можно с помощью статического метода forName.

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

С одним параметром (по умолчанию) класс инициализируется и использует загрузчик классов родителя. Может быть исключение если класс не найден.

Метаинформацию о классе можно получить и другими способами. Например, у каждого класса есть поле .class, напримет int.class или Integer.TYPE или Class c = MyClass.class, (но это только если на этапе компиляции класс известен).

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

Не для всех классов можно создать экземляр, при создании экземпляра статического класса будет exception

Пример: public class RefTest1{ ...   Class c = Class.forName("org.academy.model.Bool"); try { Book b = (Book) c.newInstance; }   catch (Excpetion e) { } } Этот пример просто чтобы показать, но так обычно не делают.

У класса Class есть нестатические методы getFields - возвращает поля класса getConstructors - возвращает конструторы getMethods - возвращает все методы getDeclardedMethods - возвращает только объявленные методы (не вернет родительские)

C помощью этих методов можно получать доступ к методам класса на котором идет работа. public Method getDeclaredMethos(String name, список параметров) name- имя метода,

Есть два способа передачи параметров для вызова метода. Java до 1.5 не поддерживала множественные параметры. Class[] args1 = new Class[1]; args1[0] = Double.TYPE; Method m1 = c.getDeclaredMethod("setPrice", args); Сейчас же все параметры в getDeclaredMethods можно перечислить после запятой, а не массивом.

Дальше можно использовать m1.invoke (obj, параметры) для вызыва метода объекта obj и invoke возращает объект и дальше уже задача программиста преобразовать его к вашему классу (можно использовать getReturnType для этого, если на этапе компилляции не известен ) Class c = Class.formName(className); Object obj = c.newInstance; Method m1 = c.getDeclaredMethod("setPrice", double.class); m1.invoke( obj, new Double(4.1)); autoboxing: быдает что функция требует указатель на объект и можно сделать new Double, но autoboxing позволяет автоматически создавать нужные объекты и передавать указатели: m1.invoke( obj, 4.1);

Обратите внимание что у объекта m1 нельзя вызвать m1.setPrice так как у Object нет других методов кроме страндартных.

Еще одна полезаня функция getParametersType - возвращает типы параметров. m.getDeclaredClass; Class[] parTps = m.getParametersType; и можно m.getReturnType;

Можно получить конструкторы

Constructor[] cArr - c.getDeclaredConstructors; for { .. // перебираем все конструкторы } Если узнали какие параметры конструкторы принимает, то можно в getInstance через запятую указывать параметры конструкторов.

Может также понадобиться динамическое изменение полей (их получаем черзе getFields и )

Field[] fields = c.getDeclaredFields; for (Field f: fields) { String name - f.getName; if (name.equals("intVar") {       f.setInt (obj1, 45);                // объект в который устанавливаем поле и что именно устанавливаем.        }    }

Работа с массивами: В Java - массивы это особая конструкция. Для того чтобы создать экземпляр массива, надо указать из каких он элементов и размерность массива. Если размерность = 1, то указывается только число элемнтов

Class c = Class.forName(className); Object arr = Array.newInstacne (c,4); Array.set( arr, 0, "First); Array.set( arr, 1, "Second");

String s = (String) Array.get(arr,2); // получение третьего элемента массива

При работе с многомерными важно помнить что двухмерный массив - это ссылки на одномерные массивы.