Field java что это
Полное руководство по Java Reflection API. Рефлексия на примерах
В этой статье мы познакомимся со всеми элементами и функциональными возможностями Java Reflection API.
Рефлексия в Java — это механизм, с помощью которого можно вносить изменения и получать информацию о классах, интерфейсах, полях и методах во время выполнения, при этом не зная имен этих классов, методов и полей. Кроме того, Reflection API дает возможность создавать новые экземпляры классов, вызывать методы, а также получать или устанавливать значения полей.
Начинающие Java-программисты часто путают рефлексию с интроспекцией. Интроспекция — проверка кода и возможность видеть типы объектов во время выполнения. Рефлексия дает возможность вносить изменения во время выполнения программы путем использования интроспекции. Здесь важно понимать различие, поскольку некоторые языки поддерживают интроспекцию, но не поддерживают рефлексию, например, C++.
В этом руководстве мы рассмотрим не только базовые, но и более продвинутые возможности Reflection API.
Java Reflection API
Рефлексия — мощная концепция, которая лежит в основе большинства современных Java/Java EE фреймворков и библиотек. Например, для Java классическими примерами являются:
Список можно продолжать бесконечно: от веб-контейнеров до решения задач объектно-реляционного отображения (ORM). Их всех объединяет одно: они используют Java рефлексию, потому что не имеют доступа и представления к определенных пользователем классах, методах, интерфейсах и т.д.
Ограничения при работе с рефлексией в Java
Почему мы не должны использовать рефлексию в обычном программировании, когда уже есть доступ к интерфейсам и классам. Причин несколько:
Рефлексия кода, reflection
Java Reflection API позволяет получать информацию о конструкторах, методах и полях классов и выполнять следующие операции над полями и методами объекта/класса :
Примечание : в тексте используется объект/класс. При работе с объектом (реализацией класса) можно обращаться к полям и методам класса напрямую, если они доступны (не private). При работе с классом можно обращаться к методам класса с использованием Java Reflection API. Но класс необходимо получить из объекта.
Определение свойств класса
В работающем приложении для получения класса необходимо использовать метод forName (String className). Следующий код демонстрирует возможность создания класса без использования и с использованием Reflection :
Метод класса forName(className) часто используется для загрузки JDBC-драйвера.
Методом getName() объекта Class можно получить наименование класса, включающего пакет (package) :
Для получения значения модификатора класса используется метод getModifiers(). Класс java.lang.reflect.Modifier содержит статические методы, возвращающие логическое значения проверки модификатора класса :
Для получения суперкласса рефлексированного объекта (класса) необходимо использовать метод getSuperclass() :
Поскольку в Java отсутствует множественное наследование, то для получения всех предков следует рекурсивно вызвать метод getSuperclass() в цикле, пока не будет достигнут Object, являющийся родителем всех классов. Object не имеет родителей, поэтому вызов его метода getSuperclass() вернет null.
Определение интерфейсов и конструкторов класса
Для получения в режиме run-time списка реализующих классом интерфейсов, необходимо получить Class и использовать его метод getInterfaces(). В следующем примере извлекается список интерфейсов класса ArrayList :
Чтобы IDE (Eclipse) не предупреждала о необходимости определения типа класса
Class is a raw type. References to generic type Class should be parameterized
в коде были использованы generic’и. В консоль выводятся следующие интерфейсы, реализуемые классом ArrayList :
Метод класса getConstructors() позволяет получить массив открытых конструкторов типа java.lang.reflect.Constructor. После этого, можно извлекать информацию о типах параметров конструктора и генерируемых исключениях :
Определение полей класса
Метод getFields() объекта Class возвращает массив открытых полей типа java.lang.reflect.Field, которые могут быть определены не только в данном классе, но также и в его родителях (суперклассе), либо интерфейсах, реализованных классом или его родителями. Класс Field позволяет получить имя поля, тип и модификаторы :
Если известно наименование поля, то можно получить о нем информацию с помощью метода getField() объекта Class.
Методы getField() и getFields() возвращают только открытые члены данных класса. Чтобы получить все поля класса, включая закрытые и защищенные, необходимо использовать методы getDeclaredField() и getDeclaredFields(). Данные методы работают точно так же, как и их аналоги getField() и getFields().
Определение значений полей класса
Класс Field содержит специализированные методы для получения значений примитивных типов: getInt(), getFloat(), getByte() и др. Для установки значения поля, используется метод set(). Для примитивных типов имеются методы setInt(), setFloat(), setByte() и др.
Ниже приведен пример изменения значения закрытого поля класса в режиме run-time.
Определение методов класса
Метод getMethods() объекта Class возвращает массив открытых методов типа java.lang.reflect.Method. Эти методы могут быть определены не только в классе, но также и в его родителях (суперклассе), либо интерфейсах, реализованных классом или его родителями. Класс Method позволяет получить имя метода, тип возвращаемого им значения, типы параметров метода, модификаторы и генерируемые исключения.
Если известно имя метода и типы его параметров, то можно получить отдельный метод класса :
Пример изменения значения закрытого поля класса
Чтобы изменить значение закрытого (private) поля класса необходимо получить это поле методом getDeclaredField () и вызвать метод setAccessible (true) объекта Field, чтобы открыть доступ к полю. После этого значение закрытого поля можно изменять, если оно не final. В следующем примере определен внутренний класс PrivateFinalFields с набором закрытых полей; одно из полей final. При создании объекта класса поля инициализируются. В методе main примера поочередно в закрытые поля вносятся изменения и свойства объекта выводятся в консоль.
В результате выполнения примера в консоль будут выведены следующие сообщения :
Из приведённого примера видно что поля private можно изменять. Для этого необходимо получить объект типа java.lang.reflect.Field с помощью метода getDeclaredField (), вызвать его метод setAccessible (true) и с помощью метода set () установить требуемое значение поля. Необходимо иметь в виду, что наличие модификатора final в закрытом текстовом поле не вызывает исключений при изменении значений, а само значение поля остаётся прежним, т.е. final поля остаются неизменные. Если не вызвать метод открытия доступа к полю setAccessible (true), то будет вызвано исключение java.lang.IllegalAccessException.
Пример вызова метода, invoke
Java Reflection Api позволяет вызвать метод класса. Рассмотрим пример, в котором определим класс Reflect, включающий поля и методы управления ими. В режиме run-time с помощью метода данного класса будем изменять значения полей и распечатывать их.
Листинг класса Reflect
Класс Reflect включает два закрытых поля (id, name) и методы управления их значениями set/get. Дополнительно в класс включим метод setData, который будем вызывать для изменения значений полей, и метод toString для печати их значений.
Для тестирования объекта типа Reflect с помощью Java Reflection Api создадим класс ReflectionTest. В этот класс включим две процедуры getClassFields и getClassMethods, которые в режиме run-time распечатают всю информацию (описание полей и методов) о классе. Методы получают класс в качестве параметра. В процедурах сначала определяются массивы полей и методы; после этого их параметры распечатываются :
В конструкторе класса ReflectionTest сначала вызываются процедуры определения полей и методов объекта/класса Reflect. После этого вызываются методы изменения значений и печати значений с использованием Reflection API. Для определения метода setData используется массив типов параметров. Вызов метода setData выполняется с передачей ему массива новых значений.
В результате выполнения примера в консоль будут выведены представленные ниже сообщения. Методы setData и toString(), вызываемые с помощью Java Reflection API, вносят измнения в закрытые поля класса и распечатываются их значения.
Скачать пример
Исходный код рассмотренного примера вызова метода invoke с использованием Java Reflection API можно скачать здесь (989 байт).
Получение полей из класса Java с помощью отражения
Узнайте, как получить поля класса с помощью отражения, включая унаследованные поля
1. Обзор
Этот учебник будет посвящен извлечению полей класса Java, включая частные и унаследованные поля.
2. Извлечение полей из класса
Давайте сначала рассмотрим, как извлекать поля класса, независимо от их видимости. Позже мы увидим, как получить унаследованные поля.
Мы хотим получить оба поля Фамилия и Имя с помощью отражения. Мы достигнем этого с помощью метода Class::getDeclaredFields . Как следует из его названия, он возвращает все объявленные поля класса в виде массива Field :
3. Получение Унаследованных Полей
Теперь давайте посмотрим, как получить унаследованные поля класса Java.
3.1. Получение унаследованных полей в простой иерархии классов
Конечно, мы могли бы использовать метод getDeclaredFields() для классов Person и Employee и объединить их результаты в один массив. Но что, если мы не хотим явно указывать суперкласс?
Давайте соберем результаты getDeclaredFields() on Employee.class и Employee.class.getSuperclass() и объединить их в один массив:
3.2. Фильтрация открытых и защищенных полей
Затем можно выполнить побитовое и между этим значением и значением определенного модификатора, чтобы увидеть, есть ли в этом поле этот модификатор. Если операция возвращает что-то другое, чем 0, то модификатор применяется, в противном случае нет.
3.3. Получение унаследованных полей в Глубокой иерархии классов
В приведенном выше примере мы работали над единой иерархией классов. Что нам теперь делать, если у нас более глубокая иерархия классов и мы хотим собрать все унаследованные поля?
Мы можем достичь этого, создав служебный метод, который проходит через иерархию, создавая для нас полный результат:
Давайте проиллюстрируем это небольшим тестом на новом Месячном сотруднике классе, расширяя Сотрудника :
Давайте вызовем метод getAllFields() на сотруднике месяца :
4. Заключение
Сначала мы узнали, как извлекать объявленные поля класса. После этого мы увидели, как получить его поля суперкласса. Затем мы научились отфильтровывать не общедоступные и не защищенные поля.
Наконец, мы увидели, как применить все это для сбора унаследованных полей иерархии нескольких классов.
Posted by: Mary Zheng in Core Java December 12th, 2019 1 Comment Views
1. Introduction
Java is an object-oriented programming language which uses “object” concept to group data and methods in a class. A variable defined in a class is called a field. A field is declared by specifying its type and name.
In this example, I will demonstrate:
2. Technologies Used
The example code in this article was built and run using:
3. Maven Project
In this step, I will create a Java maven project which has two packages:
3.1 Dependencies
3.1.1 Enum Example
In this step, I will create an EnumExample which is used in an ObjectFields class.
3.2 Field Modifier
Java supports three types of modifiers:
In this step, I will create three classes to demonstrate how to use these modifiers on fields.
3.2.1 Access Modifier
Java provides four access modifiers:
In this step, I will create an AccessModifiers class which has four fields, one for each access modifier.
3.2.2 Instance Modifier
In this step, I will create an InstanceModifiers which has four static final variables and two final variables.
3.2.3 Run-time Modifier
In this step, I will create a RuntimeModifiers which has transient volatile variables and two final variables.
3.3 Primitive Data Type
In this step, I will create a PrimitiveFields class which has eight fields, one for each primitive type.
3.4 Object
Java provides java.lang.Object class which is the parent class of all classes.
In this step, I will create an ObjectFields class which has fields belong to object types. It’s a good practice to initialize an object field to avoid the NullPointerException.
3.5 Collection
In this step, I will create a CollectionFields class which has collection fields. It’s a good practice to initialize the collection object to avoid the NullPointerException.
3.6 Inheritance
4. JUnit Test
4.1 PrimitiveFieldsTest
In this step, I will create a PrimitiveFieldsTest class to test the primitive data type fields.
4.2 ObjectFieldsTest
In this step, I will create an ObjectFieldsTest class to initialize and read the object fields.
4.3 CollectionFieldsTest
In this step, I will create a CollectionFieldsTest class to initialize and add an element to a collection field.
4.4 AccessModifiersTest
4.5 ChildExampleTest
In this step, I will create a ChildExampleTest class which shows the child object inherits the public and protected fields from the parent class.
4.6 InstanceModifiersTest
In this step, I will create an InstanceModifiersTest class which shows final fields are not assignable.
4.7 RuntimeModifersTest
In this step, I will create a Junit test to show the transient fields are not serialized.
5. Access Field via Reflection
In this step, I will create a FieldReflectionDemo to show how to read and write the fields via java.lang.reflect package.
Execute it as a Java application java jcg.zheng.demo.FieldReflectionDemo and capture output here.
6. Summary
In this example, I explained that a field is a building block of a Java object. It is defined by its type and name. I also demonstrated how to use Java modifiers to manage the availability, instance, and runtime behavior.
7. Download the Source Code
This example consists of a Maven project which demonstrates a Field in Java.
Initializing Fields
As you have seen, you can often provide an initial value for a field in its declaration:
This works well when the initialization value is available and the initialization can be put on one line. However, this form of initialization has limitations because of its simplicity. If initialization requires some logic (for example, error handling or a for loop to fill a complex array), simple assignment is inadequate. Instance variables can be initialized in constructors, where error handling or other logic can be used. To provide the same capability for class variables, the Java programming language includes static initialization blocks.
Static Initialization Blocks
A static initialization block is a normal block of code enclosed in braces, < >, and preceded by the static keyword. Here is an example:
A class can have any number of static initialization blocks, and they can appear anywhere in the class body. The runtime system guarantees that static initialization blocks are called in the order that they appear in the source code.
There is an alternative to static blocks you can write a private static method:
The advantage of private static methods is that they can be reused later if you need to reinitialize the class variable.
Initializing Instance Members
Normally, you would put code to initialize an instance variable in a constructor. There are two alternatives to using a constructor to initialize instance variables: initializer blocks and final methods.
Initializer blocks for instance variables look just like static initializer blocks, but without the static keyword:
The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.
A final method cannot be overridden in a subclass. This is discussed in the lesson on interfaces and inheritance. Here is an example of using a final method for initializing an instance variable:
This is especially useful if subclasses might want to reuse the initialization method. The method is final because calling non-final methods during instance initialization can cause problems.