java.lang.reflect.Field class

A Field osztály információkat és dinamikus hozzáférést biztosít egy osztály vagy interfész egyetlen mezőjéhez. A mező lehetővé teszi a kiterjesztő típusú konverziót a get vagy set access művelet során, de IllegalArgumentException kivételt dob , ha szűkítés történne.

A Field objektum megszerzéséhez először írunk egy osztályt:


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;
}

És itt van a kódunk az osztállyal való munkához:


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);
    }
}

Így kapjuk meg osztályunk mezőinek listáját, amivel később dolgozunk. Íme az eredmény:

[private java.lang.String com.company.Person.name, private int com.company.Person.age, public boolean com.company.Person.isMale, védett java.lang.String com.company.Person.address, public static final int com.company.Person.MAX_AGE, public static final int com.company.Person.MIN_AGE]

Most nézzük meg, mit tehetünk ezekkel az adatokkal. Beszéljünk a Field osztály metódusairól:

Módszer Leírás
getType() Egy osztály objektumot ad vissza, amely azonosítja az általa képviselt mező deklarált típusátTerülettárgy.
getAnnotatedType() Visszaadja anAnnotatedTypeobjektum, amely egy típus használatát reprezentálja a mező által képviselt mező deklarált típusának megadásához.
getGenericType() Visszatér atípusobjektum, amely az általa képviselt mező deklarált típusát képviseliTerülettárgy.
getName() Az általa képviselt mező nevét adja visszaTerülettárgy.
getModifiers() Az általa képviselt mező Java nyelvi módosítóit kódoló int-et ad visszaTerülettárgy.
getAnnotations() A mező megjegyzéseit adja vissza. Ha nincsenek megjegyzések, akkor üres tömböt ad vissza.

getType(), getName() és getModifiers() metódusok

Használhatjuk a getType() metódust, hogy megkapjuk a mezőnk típusát. Írjunk egy módszert:


static void printTypes(List<Field> fields){
      fields.forEach(e -> System.out.println(e.getType()));
  }

És ezt az eredményt kapjuk:

osztály java.lang.String
int
logikai
osztály java.lang.String
int
int

Most adjunk hozzá egy metódust az osztályunkhoz, hogy megkapjuk egy mező nevét. Így könnyebben eligazodhatunk osztályunk mezői között.


static void printTypesAndNames(List<Field> fields){
   fields.forEach(e -> System.out.printf("Field type - %s\nField name - %s\n\n", e.getType(), e.getName()));
}

Most már érthetőbb az eredmény:

Mezőtípus - osztály java.lang.String
Mezőnév - név

Mezőtípus - int
Mezőnév - életkor

Mezőtípus - logikai
érték Mezőnév - isMale

Mezőtípus - osztály java.lang.String
Mezőnév - cím

Mezőtípus - int
Mezőnév - MAX_AGE

Mezőtípus - int
Mezőnév - MIN_AGE

Nagy! Módosítsunk még egy kicsit a módszerünkön! Itt hozzáférésmódosítókat adunk hozzá


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())));
}

És nézzük, mit ad vissza az e.getModifiers() ? Ez a metódus egy int értéket ad vissza , amely lehetővé teszi, hogy meghatározzuk a mezőnk hozzáférés-módosítóinak állapotát. A Modifier osztály a mező minden egyes módosítójáért felelős statikus változókat tartalmaz.

Tekerjük vissza a visszatérési értékünket a Modifier.toString() -be , és azonnal megkapjuk az értékét szövegként:

Mezőtípus - osztály java.lang.String
Mezőnév - név
Módosítók - privát

Mezőtípus - int
Mezőnév - életkor
Módosítók - privát

Mezőtípus - logikai érték
Mezőnév - isMale
Módosítók - public

Mezőtípus - osztály java.lang.String
Mezőnév - cím
Módosítók - védett

Mezőtípus - int
Mezőnév - MAX_AGE
Módosítók - publikus statikus végleges

Mezőtípus - int
Mezőnév - MIN_AGE
Módosítók - publikus statikus végleges

Így néz ki a Modifier.toString() nélkül :

Mezőtípus - osztály java.lang.String
Mezőnév - név
Módosítók - 2

Mezőtípus - int
Mezőnév - életkor
Módosítók - 2

Mezőtípus - logikai érték
Mezőnév - isMale
Módosítók - 1

Mezőtípus - osztály java.lang.String
Mezőnév - cím
Módosítók - 4

Mezőtípus - int
Mezőnév - MAX_AGE
Módosítók - 25

Mezőtípus - int
Mezőnév - MIN_AGE
Módosítók - 25

getAnnotations(), getAnnotatedType() és getGenericType() metódusok

Módosítsuk a Person osztályt úgy, hogy ezekkel a metódusokkal működjön. Megírjuk a saját megjegyzésünket, és alkalmazzuk a mezőinkre. És hozzáadunk még néhány mezőt.

Hozzunk létre két megjegyzést. A Pig latin változónevet átadjuk az egyiknek, a másodikat pedig az elemekhez:


@Target(value=ElementType.FIELD)
@Retention(value= RetentionPolicy.RUNTIME)
public @interface Name {
    String name();
}

@Target({ ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Number {
}

És megváltoztatjuk a fő osztályunkat és a Személy osztályt:


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())));
}

Itt az ideje, hogy megnézzük módszereink eredményeit, és kitaláljuk, mire valók:

getAnnotatedType:
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>
class java.lang.String
osztály [Annotations-t

kapok:
[]
[@Name(name="\u0055\u0073\u0065\u0072\u0020\u006e\u0069\u0063" \u006b\u006e\u0061\u006d\u0065\u0073")]
[@Name(name="\u0041\u006d\u0065\u002d\u006e\u0061\u0079")] [
]
  • A getAnnotatedType visszaadja az adott mező megjegyzését, ha van ilyen. Megkapjuk a mezőre vonatkozó annotációt, és tökéletesen látjuk.

  • A getGenericType lehetővé teszi a paraméterezett típus helyes megjelenítését.

  • A getAnnotations visszaadja az objektumunkra alkalmazott megjegyzéseket.

Így könnyen hozzájuthatunk osztályunk egyes mezőinek minden adatához, illetve hozzáférési módosítóihoz, annotációihoz, adattípusaihoz.

java.lang.reflect.Method class

Szuper! Beszélgettünk az osztályunk területeiről. Itt az ideje, hogy beszéljünk a módszerekről.

Egy Method objektum megszerzéséhez a getMethod metódust hívjuk meg , és adjuk át a metódusunk nevét. Ez az alapvető módja a Method objektum beszerzésének :


Method getNameMethod =  Person.class.getMethod("getName");

Folytatjuk a munkát az osztályunkkal. Adjunk hozzá gettereket és settereket, valamint hashCode, equals és toString metódusokat:


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);
    }
}

Most készítsünk elő egy metóduskészletet, amelyet a Method osztály segítségével fogunk megvizsgálni. Íme a legfontosabb módszerek listája:

Módszer Leírás
getName() A metódus nevét adja vissza.
getModifiers() A metódus hozzáférésmódosítóját adja vissza.
getReturnType() A metódus visszatérési típusát adja vissza.
getGenericReturnType() A metódus visszatérési típusát adja vissza, figyelembe véve az általános metódusokat.
getParameterTypes() Metódusparaméterek tömbjét adja vissza.
getGenericParameterTypes() Metódusparaméterek tömbjét adja vissza, figyelembe véve az általános módszereket.
getExceptionTypes() Visszaadja azokat a kivételeket, amelyeket a metódus dobhat.
getGenericExceptionTypes() Visszaadja azokat a kivételeket, amelyeket a metódus dobhat, figyelembe véve a paraméterezett típusokat.
getAnnotations() A metódus megjegyzéseit adja vissza, beleértve a szülő megjegyzéseket.
getDeclaredAnnotations() A metódus megjegyzéseit adja vissza, kivéve a szülő megjegyzéseket.

Ahhoz, hogy megkapjuk az osztályakarat metódusainak tömbjét, hívhatjuk ezt a metódust:


Method[] methods = Person.class.getDeclaredMethods();

Ez megadja nekünk az összes módszert az osztályunkban.

getName() és getModifiers() metódusok

A getName segítségével megkaphatjuk az egyes metódusok nevét:


static List<String> getMethodsName(Method[] methods) {
    return Arrays.asList(methods)
            .stream()
            .map(Method::getName)
            .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}

Most, hogy megkapjuk a módosítókat, írjunk egy módszert, amely a getModifiers-t használja :


static List<String> getModifiers(Method[] methods) {
    return Arrays
            .stream(methods)
            .map(Method::getModifiers)
            .map(String::valueOf)
            .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}

Íme a módszerünk:


public static void main(String[] args) {
    Method[] methods = Person.class.getDeclaredMethods();

    System.out.println(getMethodsName(methods));
    System.out.println(getModifiers(methods));
}

Eredményünk:

[getName, equals, toString, hashCode, setName, getAddress, isMale, getAge, setAge, setMale, setAddress]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

Minden metódusunk rendelkezik nyilvános módosítóval, így az utolsó metódus egy tömböt ad vissza. Ha módosítjuk a kódunkat, magukat a módosítóinkat fogjuk látni:


public static void main(String[] args) {
    Method[] methods = Person.class.getDeclaredMethods();

    System.out.println(getMethodsName(methods));
    System.out.println(modifyModifiers(getModifiers(methods)));
}
[getName, equals, toString, hashCode, setName, getAddress, isMale, getAge, setAge, setMale, setAddress] [nyilvános, nyilvános, nyilvános, nyilvános, nyilvános, nyilvános, nyilvános, nyilvános,
nyilvános, nyilvános, nyilvános]

getReturnedType()

Ezzel a metódussal megkaphatjuk a metódus visszatérési típusát:


static void getReturnedType(Method[] methods) {
    Arrays.stream(methods)
            .map(Method::getReturnType)
            .forEach(System.out::println);
}
osztály java.lang.String
logikai
osztály java.lang.String
int
void
osztály java.lang.String
logikai
int
void
void
void

getGenericReturnType()

Adjunk a Person osztályunknak egy metódust, amely paraméterezett típusba csomagolva adja vissza a típust, és próbáljuk meg visszaadni a visszatérési értékét:


public List<String> someMethod() {
    // Very useful and important method
    return null;
}

És frissítjük fő módszerünket:


static void getGenericReturnType(Method[] methods) {
    Arrays.stream(methods)
            .map(Method::getGenericReturnType)
            .forEach(System.out::println);
}

Módszerünk eredménye:

osztály java.lang.String
logikai
osztály java.lang.String
int
void
osztály java.lang.String
logikai
int
void
void
void
java.util.List<java.lang.String>

getParameterTypes() és getGenericParameterTypes() metódusok

Folytatjuk a Személy osztály módosítását, két további metódus hozzáadásával:


public List<String> someMethod(List<String> list, String s) {
    // Very useful and important method
    return null;
}

Az első a módszereink paramétereit, a második pedig a paraméterezett típusokat is megadja.


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);
        }
}

Csak az egyik módszerünket fogjuk elérni. Egy metódus adott névvel való eléréséhez meghívjuk a getMethod-ot , és átadjuk a kívánt metódus nevét és paramétereit:


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);
}

A kódunk futtatásával látni fogjuk, hogy a metódusok miben térnek el egymástól, és mit adnak vissza:

interfész java.util.List
class java.lang.String

java.util.List<java.lang.String>
osztály java.lang.String

getExceptionTypes() és getGenericExceptionTypes() metódusok

Ezekkel a metódusokkal olyan kivételek tömbjét kaphatjuk meg, amelyeket metódusunk dobhat, valamint paraméterezett típusú kivételeket (ha vannak ilyenek). Használjunk egy új példát, amelynek rejtett statikus osztálya van:


private static class Processor {
    private void init() {}

    private void process() throws IOException {}
}

És meghívjuk a metódusokat a Processor osztályunkban:


public static void main(String... args) throws NoSuchMethodException {
    Method method = Processor.class.getDeclaredMethod("process");
    Type[] type = method.getExceptionTypes();
    System.out.println(Arrays.toString(type));
}

Most láthatjuk a kivételünket:

[osztály java.io.IOException]

Most paraméterezzük a típust. Módosítjuk fő osztályunkat:


private static class Processor<E extends IOException> {

    private void process() throws E {
    }
}

És a módszer kódja:


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);
            }
        }
    }
}

Ezen a metóduson belül kaptunk egy TypeVariables objektumot, amely a típusváltozók általános szülőfelülete. Ezen belül pedig megkaphatjuk a belső paramétert, nevezetesen a beágyazott kivételünket:

[E]
osztály java.io.IOException

getAnnotations() és getDeclaredAnnotations() metódusok

Folytassuk az új osztály használatát, és adjunk hozzá néhány megjegyzést. Létrehozzuk saját kommentárunkat :


@Retention(RetentionPolicy.RUNTIME)
@interface Annotation {

    public String key();
    public String value();
}

És alkalmazzuk a módszerünkre:


@Annotation(key = "key", value = "value")
private void process() throws E{

}

És természetesen hozzáadunk egy módszert az összes megjegyzésünk megjelenítéséhez:


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();
    }
}

módszerünk megvalósítása :


public static void main(String... args) {
    Class clazz = Processor.class;
    getMethodAnnotations(clazz);
}

A kapott képernyőkimenet a következő:

folyamat
[@com.company.Main&Annotation(key="key", value="value")]

Így kaphatjuk meg a metódusainkra alkalmazott annotációkat, a getAnnotations metódus pedig lehetővé teszi az osztály szülőannotációinak elérését is.

A mai napon megismerkedtünk azzal, hogyan működhet a reflexió módszerekkel, mezőkkel, és milyen adatokat nyerhetünk vele!