java.lang.reflect.Field клас
Класът Field предоставя информация за и динамичен достъп до едно поле на клас or интерфейс. Field също позволява преобразуване на разширяващ се тип по време на операция за получаване or задаване на достъп, но хвърля IllegalArgumentException , ако се получи стесняване.
За да получим Field обект, първо ще напишем клас:
public class Person {
private String name;
private int age;
public boolean isMale;
protected String address;
public static final int MAX_AGE = 120;
public static final int MIN_AGE = 0;
}
И ето нашия code за работа с този клас:
public class Main {
public static void main(String[] args) {
Field[] fields = Person.class.getDeclaredFields();
List<Field> actualFields = getFieldNames(fields);
System.out.println(actualFields);
}
static List<Field> getFieldNames(Field[] fields) {
return List.of(fields);
}
}
Така получаваме списъка с полетата от нашия клас, с които ще работим по-късно. Ето резултата:
Сега нека разберем Howво можем да направим с тези данни. Нека поговорим за методите на класа Field :
Метод | Описание |
---|---|
getType() | Връща обект Class, който идентифицира декларирания тип на полето, представено от thisПолеобект. |
getAnnotatedType() | Връща anAnnotatedTypeобект, който представлява използването на тип за указване на декларирания тип на полето, представено от това поле. |
getGenericType() | Връща aТипобект, който представлява декларирания тип на полето, представено от thisПолеобект. |
getName() | Връща името на полето, представено от товаПолеобект. |
getModifiers() | Връща int, codeиращ модификаторите на езика Java за полето, представено от товаПолеобект. |
getAnnotations() | Връща анотациите за това поле. Ако няма анотации, връща празен масив. |
методи getType(), getName() и getModifiers().
Можем да използваме метода getType() , за да получим типа на нашето поле. Нека напишем метод:
static void printTypes(List<Field> fields){
fields.forEach(e -> System.out.println(e.getType()));
}
И получаваме този резултат:
int
булев
клас java.lang.String
int
int
Сега нека добавим метод към нашия клас, за да получим името на поле. Това ще улесни навигацията в полетата на нашия клас.
static void printTypesAndNames(List<Field> fields){
fields.forEach(e -> System.out.printf("Field type - %s\nField name - %s\n\n", e.getType(), e.getName()));
}
Сега резултатът е по-разбираем:
Име на поле - име
Тип поле - int
Име на поле - възраст
Тип поле - boolean
Име на поле - isMale
Тип поле - клас java.lang.String
Име на поле - address
Тип поле - int
Име на поле - MAX_AGE
Тип поле - int
Име на поле - MIN_AGE
Страхотен! Нека променим нашия метод още малко! Тук ще добавим модификатори за достъп
static void printFieldInfo(List<Field> fields){
fields.forEach(e -> System.out.printf("Field type - %s\nField name - %s\nModifiers - %s\n\n", e.getType(), e.getName(), Modifier.toString(e.getModifiers())));
}
И нека да разгледаме Howво връща e.getModifiers() . Този метод връща int , което ни позволява да определим състоянието на модификаторите за достъп на нашето поле. Класът Modifier съдържа статични променливи, отговорни за всеки конкретен модификатор на полето.
Нека увием нашата върната стойност в Modifier.toString() и веднага да получим нейната стойност като текст:
Име на поле - име
Модификатори - private
Тип поле - int
Име на поле - възраст
Модификатори - частно
Тип поле - boolean
Име на поле - isMale
Модификатори - public
Тип поле - клас java.lang.String
Име на поле - address
Модификатори - защитено
Тип поле - int
Име на поле - MAX_AGE
Модификатори - публичен статичен финал
Тип поле - int
Име на поле - MIN_AGE
Модификатори - публичен статичен финал
Ето How изглежда без Modifier.toString() :
Име на поле - име
Модификатори - 2
Тип поле - int
Име на поле - възраст
Модификатори - 2
Тип поле - boolean
Име на поле - isMale
Модификатори - 1
Тип поле - клас java.lang.String
Име на поле - address
Модификатори - 4
Тип поле - int
Име на поле - MAX_AGE
Модификатори - 25
Тип поле - int
Име на поле - MIN_AGE
Модификатори - 25
методи getAnnotations(), getAnnotatedType() и getGenericType()
Нека модифицираме класа Person , за да работи с тези методи. Ще напишем наша собствена анотация и ще я приложим към нашите полета. И ще добавим още няколко полета.
Нека създадем две анотации. Ще предадем името на променливата на свинска латиница на едната и ще използваме втората за елементи:
@Target(value=ElementType.FIELD)
@Retention(value= RetentionPolicy.RUNTIME)
public @interface Name {
String name();
}
@Target({ ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Number {
}
И ще променим нашия основен клас и класа Person :
public class Person {
@Name(name = "Ame-nay")
private String name;
@Name(name = "User nicknames")
List<String> nicknames;
private final Class<Object> type;
private int @Number[] number;
public Person(Class<Object> type) {
this.type = type;
}
}
public static void main(String[] args) {
Field[] fields = Person.class.getDeclaredFields();
List<Field> actualFields = getFieldNames(fields);
printAdditionalInfo(actualFields);
}
static void printAdditionalInfo(List<Field> fields) {
System.out.println("\ngetAnnotatedType:");
fields.forEach(e -> System.out.println(e.getAnnotatedType()));
System.out.println("\ngetGenericType:");
fields.forEach(e -> System.out.println(e.getGenericType()));
System.out.println("\ngetAnnotations:");
fields.forEach(e -> System.out.println(Arrays.toString(e.getAnnotations())));
}
Време е да разгледаме резултатите от нашите методи и да разберем за Howво служат:
java.lang.Class<java.lang.Object>
java.util.List<java.lang.String>
java.lang.String
int @Number()[]
getGenericType:
java.lang.Class<java.lang. Object>
java.util.List<java.lang.String>
клас java.lang.String
клас [I
getAnnotations:
[]
[@Name(name="\u0055\u0073\u0065\u0072\u0020\u006e\u0069\u0063 \u006b\u006e\u0061\u006d\u0065\u0073")]
[@Име(име="\u0041\u006d\u0065\u002d\u006e\u0061\u0079")] [
]
-
getAnnotatedType връща анотацията за даденото поле, ако има такава. Получаваме анотацията за полето и я виждаме перфектно.
-
getGenericType ви позволява да показвате правилно параметризиран тип.
-
getAnnotations връща анотациите, приложени към нашия обект.
Ето How можем лесно да получим всички данни за всяко поле в нашия клас, Howто и неговите модификатори за достъп, анотации и типове данни.
клас java.lang.reflect.Method
Супер! Говорихме за полетата на нашия клас. Сега е време да поговорим за методите.
За да получим обект Method , извикваме метода getMethod , като му предаваме името на нашия метод. Това е основният начин за получаване на обект Method :
Method getNameMethod = Person.class.getMethod("getName");
Ще продължим да работим с нашия клас. Нека добавим гетери и сетери, Howто и методи hashCode, equals и toString :
public class Person {
private String name;
private int age;
public boolean isMale;
protected String address;
public static final int MAX_AGE = 120;
public static final int MIN_AGE = 0;
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 boolean isMale() {
return isMale;
}
public void setMale(boolean male) {
isMale = male;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", isMale=" + isMale +
", address='" + address + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && isMale == person.isMale && Objects.equals(name, person.name) && Objects.equals(address, person.address);
}
@Override
public int hashCode() {
return Objects.hash(name, age, isMale, address);
}
}
Сега нека подготвим набор от методи, които ще изследваме с помощта на класа Method . Ето списък на най-важните методи:
Метод | Описание |
---|---|
getName() | Връща името на метода. |
getModifiers() | Връща модификатора за достъп на този метод. |
getReturnType() | Връща типа връщане на метода. |
getGenericReturnType() | Връща типа връщане на метода, отчитайки общите методи. |
getParameterTypes() | Връща масив от параметри на метода. |
getGenericParameterTypes() | Връща масив от параметри на метода, отчитайки генеричните методи. |
getExceptionTypes() | Връща изключенията, които методът може да генерира. |
getGenericExceptionTypes() | Връща изключенията, които методът може да генерира, като отчита параметризираните типове. |
getAnnotations() | Връща анотациите за метода, включително родителските анотации. |
getDeclaredAnnotations() | Връща анотациите за метода, с изключение на родителските анотации. |
За да получим масив от методите на нашия клас ще, можем да извикаме този метод:
Method[] methods = Person.class.getDeclaredMethods();
Ще ни даде всички методи в нашия клас.
методи getName() и getModifiers().
Можем да използваме getName , за да получим името на всеки метод:
static List<String> getMethodsName(Method[] methods) {
return Arrays.asList(methods)
.stream()
.map(Method::getName)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
Сега, за да получим модификаторите, нека напишем метод, който използва getModifiers :
static List<String> getModifiers(Method[] methods) {
return Arrays
.stream(methods)
.map(Method::getModifiers)
.map(String::valueOf)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
Ето нашия основен метод:
public static void main(String[] args) {
Method[] methods = Person.class.getDeclaredMethods();
System.out.println(getMethodsName(methods));
System.out.println(getModifiers(methods));
}
Нашият резултат:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Всички наши методи имат публичен модификатор, така че последният метод връща масив от единици. Ако променим codeа си, ще видим самите модификатори:
public static void main(String[] args) {
Method[] methods = Person.class.getDeclaredMethods();
System.out.println(getMethodsName(methods));
System.out.println(modifyModifiers(getModifiers(methods)));
}
, публичен, обществен, обществен]
getReturnedType()
Този метод ни позволява да получим връщания тип на метода:
static void getReturnedType(Method[] methods) {
Arrays.stream(methods)
.map(Method::getReturnType)
.forEach(System.out::println);
}
boolean
клас java.lang.String
int
void
клас java.lang.String
boolean
int
void
void
void
getGenericReturnType()
Нека дадем на нашия клас Person метод, който връща типа, обвит в параметризиран тип, и да се опитаме да получим върнатата му стойност:
public List<String> someMethod() {
// Very useful and important method
return null;
}
И ние ще актуализираме нашия основен метод:
static void getGenericReturnType(Method[] methods) {
Arrays.stream(methods)
.map(Method::getGenericReturnType)
.forEach(System.out::println);
}
Резултат от нашия метод:
boolean
клас java.lang.String
int
void
class java.lang.String
boolean
int
void
void
void
java.util.List<java.lang.String>
методи getParameterTypes() и getGenericParameterTypes().
Продължаваме да променяме нашия клас Person , добавяйки още два метода:
public List<String> someMethod(List<String> list, String s) {
// Very useful and important method
return null;
}
Първият ще ни позволи да получим параметрите на нашите методи, а вторият ще ни даде и параметризирани типове.
static void getParameterTypes(Method[] methods) {
Class<?>[] types = method.getParameterTypes();
for (Class<?> type : types) {
System.out.println(type);
}
}
static void getGenericParameterTypes(Method[] methods) {
Type[] types = method.getGenericParameterTypes();
for (Type type : types) {
System.out.println(type);
}
}
Ще имаме достъп само до един от нашите методи. За достъп до метод с конкретно име, извикваме getMethod и предаваме името и параметрите на метода, който искаме:
public static void main(String[] args) throws NoSuchMethodException {
Method currentMethod = Person.class.getMethod("someMethod", List.class, String.class);
getParameterTypes(currentMethod);
System.out.println();
getGenericParameterTypes(currentMethod);
}
Изпълнявайки нашия code, ще видим How се различават методите и Howво връщат:
клас java.lang.String
java.util.List<java.lang.String>
клас java.lang.String
методи getExceptionTypes() и getGenericExceptionTypes().
Можем да използваме тези методи, за да получим масив от изключения, които нашият метод може да хвърли, Howто и изключения с параметризирани типове (ако има такива). Нека използваме нов пример, който има скрит статичен клас:
private static class Processor {
private void init() {}
private void process() throws IOException {}
}
И ще извикаме методи на нашия клас процесор :
public static void main(String... args) throws NoSuchMethodException {
Method method = Processor.class.getDeclaredMethod("process");
Type[] type = method.getExceptionTypes();
System.out.println(Arrays.toString(type));
}
Сега можем да видим нашето изключение:
Сега нека да параметризираме типа. Ще модифицираме нашия основен клас:
private static class Processor<E extends IOException> {
private void process() throws E {
}
}
И codeът на основния метод:
public static void main(String... args) throws NoSuchMethodException {
Method m = Processor.class.getDeclaredMethod("process");
Type[] t = m.getGenericExceptionTypes();
System.out.println(Arrays.toString(t));
for (Type type : t) {
if (type instanceof TypeVariable) {
for (Type type1 : ((TypeVariable) type).getBounds()) {
System.out.println(type1);
}
}
}
}
Вътре в този метод имаме обект TypeVariables , който е общ родителски интерфейс за променливи на тип. И вътре в това вече можем да получим вътрешния параметър, а именно нашето вложено изключение:
клас java.io.IOException
методи getAnnotations() и getDeclaredAnnotations().
Нека продължим да използваме този нов клас и да добавим няколко анотации към него. Ще създадем наша собствена анотация за анотация :
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation {
public String key();
public String value();
}
И го приложете към нашия метод:
@Annotation(key = "key", value = "value")
private void process() throws E{
}
И разбира се, ще добавим метод за показване на всичките ни анотации:
static void getMethodAnnotations(Class<?> clazz) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
System.out.println(Arrays.toString(method.getAnnotations()));
System.out.println();
}
}
Прилагане на основния ни метод:
public static void main(String... args) {
Class clazz = Processor.class;
getMethodAnnotations(clazz);
}
Полученият изход на екрана е:
[@com.company.Main&Annotation(key="ключ", value="стойност")]
Това е начинът, по който можем да получим анотациите, които са бor приложени към нашите методи, а методът getAnnotations ни позволява да получим достъп и до родителските анотации на класа.
Днес се запознахме с това How отражението може да работи с методи и полета и Howви данни можем да получим с него!
GO TO FULL VERSION