klasa java.lang.reflect.Field
Klasa Field zapewnia informacje i dynamiczny dostęp do pojedynczego pola klasy lub interfejsu. Pole zezwala również na rozszerzanie transformacji podczas operacji pobierania lub ustawiania dostępu, ale zgłasza wyjątek IllegalArgumentException , jeśli wystąpi zawężanie transformacji.
Aby uzyskać klasę Filed , napiszemy klasę, z którą będziemy pracować, a także program obsługi do tego:
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;
}
I sam prowadzący:
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);
}
}
Otrzymujemy w ten sposób listę dziedzin naszej klasy, z którymi będziemy dalej pracować. Wynik wykonania wygląda następująco:
Teraz zastanówmy się, co możemy zrobić z tym zestawem danych. Porozmawiajmy o metodach klasy Field :
metoda | Opis |
---|---|
getType() | Zwraca obiekt klasy, która definiuje zadeklarowany typ pola reprezentowanego przez ten obiektpole. |
getAnnotatedType() | Zwraca obiektTyp adnotacjiA, który reprezentuje użycie typu do określenia zadeklarowanego typu pola reprezentowanego przez to pole. |
getGenericType() | Zwraca obiekttypA, która reprezentuje zadeklarowany typ pola reprezentowanego przez ten obiektpole. |
pobierzNazwę() | Zwraca nazwę pola reprezentowanego przez ten obiektpole. |
getModifiers() | Zwraca modyfikatory języka Java dla pola reprezentowanego przez ten obiektpole, jako liczba całkowita. |
getAnnotations() | Zwraca adnotacje dla tego pola. Jeśli nie ma adnotacji, pusta tablica. |
Metody getType(), getName(), getModifiers()
Za pomocą metody getType() możemy uzyskać typ naszego pola. Napiszmy metodę:
static void printTypes(List<Field> fields){
fields.forEach(e -> System.out.println(e.getType()));
}
I otrzymujemy taki wynik:
int
logiczna
klasa java.lang.String
int
int
I od razu dodajmy metodę do naszej klasy, aby uzyskać nazwę pola. Ułatwi to poruszanie się po polach naszej klasy.
static void printTypesAndNames(List<Field> fields){
fields.forEach(e -> System.out.printf("Field type - %s\nField name - %s\n\n", e.getType(), e.getName()));
}
Otrzymujemy wynik, który jest już bardziej zrozumiały dla użytkownika:
Nazwa pola - nazwa
Typ pola - int
Nazwa pola - wiek
Typ pola - boolean
Nazwa pola - isMale
Typ pola - klasa java.lang.String
Nazwa pola - adres
Typ pola - int
Nazwa pola - MAX_AGE
Typ pola - int
Nazwa pola - MIN_AGE
Świetnie, zmodyfikujmy jeszcze trochę naszą metodę! Dodajmy tutaj modyfikatory dostępu:
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())));
}
Zobaczmy, co zwraca funkcja e.getModifiers() . Ta metoda zwraca int , w ramach którego możemy zdefiniować modyfikatory dostępu do naszego pola. Wewnątrz klasy Modifier znajdują się zmienne statyczne, które odpowiadają za określony modyfikator pola.
Zapakujmy naszą zwracaną wartość w Modifier.toString() - i natychmiast pobierzmy wartość w postaci tekstowej:
Nazwa pola - name
Modyfikatory - private
Typ pola - int
Nazwa pola - age
Modyfikatory - private
Typ pola - boolean
Nazwa pola - isMale
Modyfikatory - public
Typ pola - class java.lang.String
Nazwa pola - adres
Modyfikatory - protected
Typ pola - int
Nazwa pola - MAX_AGE
Modyfikatory - public static final
Typ pola - int
Nazwa pola - MIN_AGE
Modyfikatory - public static final
A tak to wygląda bez Modifier.toString() :
Nazwa pola - nazwa
Modyfikatory - 2
Typ pola - int
Nazwa pola - wiek
Modyfikatory - 2
Typ pola - boolean
Nazwa pola - isMale
Modyfikatory - 1
Typ pola - class java.lang.String
Nazwa pola - adres
Modyfikatory - 4
Typ pola - int
Nazwa pola - MAX_AGE
Modyfikatory - 25
Typ pola - int
Nazwa pola - MIN_AGE
Modyfikatory - 25
metody getAnnotations(), getAnnotatedType(), getGenericType().
Zmodyfikujmy klasę Person , aby działała z bieżącymi metodami. Napiszemy własną adnotację, którą dodamy do naszych pól i dodamy jeszcze kilka pól.
Utwórzmy dwie adnotacje. Nazwę zmiennej w języku rosyjskim przekażemy do jednego, a drugiego użyjemy dla elementów:
@Target(value=ElementType.FIELD)
@Retention(value= RetentionPolicy.RUNTIME)
public @interface Name {
String name();
}
@Target({ ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Number {
}
I zmień naszą główną klasę i klasę 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())));
}
Czas przyjrzeć się wynikom naszych metod i ponownie przeanalizować ich przeznaczenie:
java.lang.Class<java.lang.Object>
java.util.List<java.lang.String>
java.lang.String
int @Number()[]
getGenericType:
java.lang.Class<java.lang. Obiekt>
java.util.List<java.lang.String> klasa
klasa java.lang.String
[otrzymuję
adnotacje:
[]
[@Nazwa(nazwa="\u041d\u0438\u043a\u0438 \u043f\u043e\u043b\u044c \u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f")]
[@Nazwa(nazwa="\u0418\u043c\u044f")]
[]
-
getAnnotatedType zwraca adnotację dla danego pola, jeśli istnieje. Mamy adnotację dla pola i doskonale ją widzimy.
-
getGenericType umożliwia poprawne wyświetlanie ogólnych parametrów.
-
getAnnotations zwraca adnotacje, które znajdują się na górze naszego obiektu.
W ten sposób możemy łatwo uzyskać wszystkie dane o każdym polu w naszej klasie, jego modyfikatorach dostępu, adnotacjach i typach danych.
Klasa java.lang.reflect.Method
Świetnie, omówiliśmy dziedziny naszej klasy, czas porozmawiać o metodach.
Aby otrzymać obiekt klasy Method , wywołujemy getMethod i przekazujemy nazwę naszej metody. Oto podstawowy sposób uzyskania klasy Method :
Method getNameMethod = Person.class.getMethod("getName");
Będziemy dalej pracować z naszą klasą. Dodajmy gettery i settery, hash code, equals i 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);
}
}
I przygotujmy zestaw metod, którym przyjrzymy się klasie Method . Oto lista głównych metod:
metoda | Opis |
---|---|
pobierzNazwę() | Zwraca nazwę metody. |
getModifiers() | Zwraca modyfikator dostępu tej metody. |
getReturnType() | Zwraca zwracany typ metody. |
getGenericReturnType() | Zwraca zwracany typ metody, biorąc pod uwagę uogólnione metody. |
getParameterTypes() | Zwraca tablicę parametrów metody. |
getGenericParameterTypes() | Zwraca tablicę parametrów metody, w tym metody uogólnione. |
getExceptionType() | Zwraca wyjątki, które metoda może zgłosić. |
getGenericExceptionTypes() | Zwraca wyjątki, które metoda może zgłosić, biorąc pod uwagę ogólne parametry. |
getAnnotations() | Zwraca adnotacje dla metody, w tym adnotacje nadrzędne. |
getDeclaredAnnotations() | Zwraca adnotacje dla metody, ignorując adnotacje nadrzędne. |
Aby uzyskać tablicę metod, które zwróci nam nasza klasa, możemy wywołać tę metodę:
Method[] methods = Person.class.getDeclaredMethods();
Dzięki niemu otrzymamy wszystkie metody w naszej klasie.
metody getName() i getModifiers().
Aby uzyskać nazwy wszystkich metod, możemy użyć getName :
static List<String> getMethodsName(Method[] methods) {
return Arrays.asList(methods)
.stream()
.map(Method::getName)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
Aby uzyskać modyfikatory, napiszmy metodę używającą getModifiers :
static List<String> getModifiers(Method[] methods) {
return Arrays
.stream(methods)
.map(Method::getModifiers)
.map(String::valueOf)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
Nasza główna metoda :
public static void main(String[] args) {
Method[] methods = Person.class.getDeclaredMethods();
System.out.println(getMethodsName(methods));
System.out.println(getModifiers(methods));
}
Nasz wynik:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Wszystkie nasze modyfikatory mają publiczny dostęp , więc ostatnia metoda zwraca nam jednostki. Jeśli zmodyfikujemy nasz kod, zobaczymy nasze modyfikatory:
public static void main(String[] args) {
Method[] methods = Person.class.getDeclaredMethods();
System.out.println(getMethodsName(methods));
System.out.println(modifyModifiers(getModifiers(methods)));
}
]
getReturnedType()
Za pomocą tej metody możemy uzyskać zwracany typ metody:
static void getReturnedType(Method[] methods) {
Arrays.stream(methods)
.map(Method::getReturnType)
.forEach(System.out::println);
}
boolean
class java.lang.String
int
void
klasa java.lang.String
boolean
int
void
void
void
getGenericReturnType()
Dodajmy metodę do naszej klasy Person , która zwraca typ ogólny i spróbujmy uzyskać jej wartość zwracaną:
public List<String> someMethod() {
// Very useful and important method
return null;
}
I zmodyfikuj naszą główną metodę:
static void getGenericReturnType(Method[] methods) {
Arrays.stream(methods)
.map(Method::getGenericReturnType)
.forEach(System.out::println);
}
Wynik naszej metody:
boolean
class java.lang.String
int
void
class java.lang.String
boolean
int
void
void
void
java.util.List<java.lang.String>
metody getParameterTypes() i getGenericParameterTypes().
Kontynuujemy modyfikację naszej metody klasy Person i dodajemy jeszcze dwie metody:
public List<String> someMethod(List<String> list, String s) {
// Very useful and important method
return null;
}
Pierwszy pozwoli nam uzyskać parametry naszych metod, a drugi da nam również parametry uogólnione.
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);
}
}
Odniesiemy się tylko do jednej z naszych metod. Aby uzyskać dostęp do metody o określonej nazwie, wywołaj getMethod i podaj nazwę oraz parametry metody, której potrzebujemy:
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);
}
I zgodnie z wynikami naszego kodu zobaczymy, czym różnią się metody i co zwracają:
klasa java.lang.String
java.util.List<java.lang.String>
klasa java.lang.String
metody getExceptionTypes() i getGenericExceptionTypes().
Korzystając z tych metod, możesz uzyskać tablicę wyjątków, które nasza metoda może zgłaszać, a także wyjątki opakowane w generyczne (jeśli istnieją). Weźmy nowy przykład z ukrytą klasą statyczną:
private static class Processor {
private void init() {}
private void process() throws IOException {}
}
I będziemy wywoływać metody w naszej klasie Process :
public static void main(String... args) throws NoSuchMethodException {
Method method = Processor.class.getDeclaredMethod("process");
Type[] type = method.getExceptionTypes();
System.out.println(Arrays.toString(type));
}
W rezultacie nasz wyjątek jest wyraźnie widoczny:
Teraz zawińmy to wszystko w ogólny. Zmodyfikujmy naszą główną klasę:
private static class Processor<E extends IOException> {
private void process() throws E {
}
}
I kod dla klasy Main :
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);
}
}
}
}
Wewnątrz tej metody mamy TypeVariables - jest to wspólny superinterfejs dla zmiennych typu. A w nim możemy już uzyskać wewnętrzny parametr, a mianowicie nasz zagnieżdżony wyjątek:
klasa java.io.IOException
metody getAnnotations() i getDeclaredAnnotations().
Kontynuujmy naszą nową klasę i dodajmy do niej kilka adnotacji. Stwórzmy własną adnotację :
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation {
public String key();
public String value();
}
I dodaj to do naszej metody:
@Annotation(key = "key", value = "value")
private void process() throws E{
}
I oczywiście metoda wyświetlania wszystkich naszych adnotacji:
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();
}
}
Implementacja naszej klasy Main :
public static void main(String... args) {
Class clazz = Processor.class;
getMethodAnnotations(clazz);
}
Na ekranie otrzymujemy następujący wynik:
[@com.company.Main&Annotation(klucz=”klucz”, wartość=”wartość”)]
W ten sposób możemy uzyskać adnotacje należące do naszych metod, a przy pomocy metody getAnnotations uzyskujemy również dostęp do adnotacji nadrzędnych klasy.
Dziś poznaliśmy jak metody i pola działają z refleksją i jakie dane możemy dzięki temu uzyskać!
GO TO FULL VERSION