java.lang.reflect.Feltklasse

Feltklassen giver information om og dynamisk adgang til et enkelt felt i en klasse eller grænseflade . Feltet tillader også en udvidelsestypekonvertering under en hent eller sæt adgangsoperation, men kaster en IllegalArgumentException , hvis indsnævring ville forekomme.

For at få et feltobjekt , skriver vi først en klasse:


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

Og her er vores kode til at arbejde med den klasse:


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

Sådan får vi listen over vores klasses felter, som vi skal arbejde med senere. Her er resultatet:

[privat java.lang.String com.company.Person.name, private int com.company.Person.age, public boolean com.company.Person.isMand, beskyttet java.lang.String com.company.Person.address, public statisk endelig int com.company.Person.MAX_AGE, offentlig statisk endelig int com.company.Person.MIN_AGE]

Lad os nu finde ud af, hvad vi kan gøre med disse data. Lad os tale om metoderne i Field- klassen:

Metode Beskrivelse
getType() Returnerer et klasseobjekt, der identificerer den erklærede type af feltet repræsenteret af detteMarkobjekt.
getAnnotatedType() Returnerer enAnnoteret Typeobjekt, der repræsenterer brugen af ​​en type til at specificere den erklærede type af feltet repræsenteret af dette felt.
getGenericType() Returnerer enTypeobjekt, der repræsenterer den deklarerede type af feltet repræsenteret af detteMarkobjekt.
getName() Returnerer navnet på feltet repræsenteret af detteMarkobjekt.
getModifiers() Returnerer en int, der koder Java-sprogmodifikatorerne for det felt, der repræsenteres af detteMarkobjekt.
getAnnotations() Returnerer annoteringerne for dette felt. Hvis der ikke er nogen anmærkninger, returnerer det en tom matrix.

getType(), getName() og getModifiers() metoder

Vi kan bruge metoden getType() til at få typen af ​​vores felt. Lad os skrive en metode:


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

Og vi får dette resultat:

class java.lang.String
int
boolean
class java.lang.String
int
int

Lad os nu tilføje en metode til vores klasse for at få navnet på et felt. Dette vil gøre det nemmere at navigere i vores klasses felter.


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

Nu er resultatet mere forståeligt:

Felttype - klasse java.lang.String
Feltnavn - navn

Felttype - int
Feltnavn - alder

Felttype - boolean
Feltnavn - isMale

Felttype - klasse java.lang.String
Feltnavn - adresse

Felttype - int
Feltnavn - MAX_AGE

Felttype - int
Feltnavn - MIN_AGE

Store! Lad os ændre vores metode noget mere! Vi tilføjer adgangsmodifikatorer her


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

Og lad os se på, hvad e.getModifiers() returnerer. Denne metode returnerer en int , der lader os bestemme tilstanden for vores felts adgangsmodifikatorer. Modifier - klassen indeholder statiske variabler, der er ansvarlige for hver specifik modifikator af feltet.

Lad os pakke vores returværdi ind i Modifier.toString() og straks få dens værdi som tekst:

Felttype - klasse java.lang.String
Feltnavn - navn
Modifikatorer - privat

Felttype - int
Feltnavn - alder
Modifikatorer - privat

Felttype - boolean
Feltnavn - isMale
Modifikatorer - offentlig

Felttype - klasse java.lang.String
Feltnavn - adresse
Modifikatorer - beskyttet

Felttype - int
Feltnavn - MAX_AGE
Modifikatorer - offentlig statisk endelig

Felttype - int
Feltnavn - MIN_AGE
Modifikatorer - offentlig statisk endelig

Sådan ser det ud uden Modifier.toString() :

Felttype - klasse java.lang.String
Feltnavn - navn
Modifikatorer - 2

Felttype - int
Feltnavn - alder
Modifikatorer - 2

Felttype - boolean
Feltnavn - isMale
Modifikatorer - 1

Felttype - klasse java.lang.String
Feltnavn - adresse
Modifikatorer - 4

Felttype - int
Feltnavn - MAX_AGE
Modifikatorer - 25

Felttype - int
Feltnavn - MIN_AGE
Modifikatorer - 25

getAnnotations(), getAnnotatedType() og getGenericType() metoder

Lad os ændre Person -klassen til at arbejde med disse metoder. Vi skriver vores egen anmærkning og anvender den på vores felter. Og vi tilføjer nogle flere felter.

Lad os oprette to anmærkninger. Vi vil videregive variabelnavnet på Pig Latin til en, og vi vil bruge den anden til elementer:


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

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

Og vi ændrer vores hovedklasse og personklassen :


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

Det er tid til at se på resultaterne af vores metoder og finde ud af, hvad de er til:

getAnnotatedType:
java.lang.Class<java.lang.Object>
java.util.List<java.lang.String>
java.lang.String
int @Number()[]

getGenericType:
java.lang.Class<java.lang. Objekt>
java.util.List<java.lang.String>
klasse java.lang.String
klasse [I

getAnnotations:
[]
[@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")] [
]
  • getAnnotatedType returnerer annoteringen for det givne felt, hvis nogen. Vi får annoteringen for feltet, og vi kan se det perfekt.

  • getGenericType lader dig vise en parametreret type korrekt.

  • getAnnotations returnerer annoteringerne anvendt på vores objekt.

Sådan kan vi nemt få alle data om hvert felt i vores klasse, såvel som dets adgangsmodifikatorer, annoteringer og datatyper.

java.lang.reflect.Metode klasse

Super! Vi har talt om vores klasses områder. Nu er det tid til at tale om metoderne.

For at få et Method- objekt kalder vi getMethod- metoden og giver den navnet på vores metode. Dette er den grundlæggende måde at få et Method- objekt på:


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

Vi vil fortsætte med at arbejde med vores klasse. Lad os tilføje gettere og settere og hashCode, equals og toString metoder:


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

Lad os nu forberede et sæt metoder, som vi vil undersøge ved hjælp af metodeklassen . Her er en liste over de vigtigste metoder:

Metode Beskrivelse
getName() Returnerer navnet på metoden.
getModifiers() Returnerer adgangsmodifikatoren for denne metode.
getReturnType() Returnerer metodens returtype.
getGenericReturnType() Returnerer metodens returtype, der tager højde for generiske metoder.
getParameterTypes() Returnerer en matrix af metodeparametre.
getGenericParameterTypes() Returnerer en række metodeparametre, der tager højde for generiske metoder.
getExceptionTypes() Returnerer de undtagelser, som metoden kan kaste.
getGenericExceptionTypes() Returnerer de undtagelser, som metoden kan give, og tager højde for parameteriserede typer.
getAnnotations() Returnerer annoteringerne for metoden, inklusive overordnede annoteringer.
getDeclaredAnnotations() Returnerer annoteringerne for metoden, eksklusive overordnede annoteringer.

For at få en række af metoderne i vores klassetestamente kan vi kalde denne metode:


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

Det vil give os alle metoderne i vores klasse.

getName() og getModifiers() metoder

Vi kan bruge getName til at få navnet på hver metode:


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

Nu for at få modifikatorerne, lad os skrive en metode, der bruger getModifiers :


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

Her er vores vigtigste metode:


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

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

Vores resultat:

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

Alle vores metoder har den offentlige modifikator, så den sidste metode returnerer en række ener. Hvis vi ændrer vores kode, vil vi se selve modifikatorerne:


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] [
offentlig, offentlig, offentlig, offentlig, offentlig, offentlig, offentlig, offentlig, offentlig, offentlig, offentlig]

getReturnedType()

Denne metode lader os få metodens returtype:


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

getGenericReturnType()

Lad os give vores Person- klasse en metode, der returnerer typen pakket ind i en parameteriseret type, og forsøge at få dens returværdi:


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

Og vi opdaterer vores hovedmetode:


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

Resultatet af vores metode:

klasse java.lang.String
boolean
klasse java.lang.String
int
void
klasse java.lang.String
boolean
int
void
void
void
java.util.List<java.lang.String>

getParameterTypes() og getGenericParameterTypes() metoder

Vi fortsætter med at ændre vores Person- klasse og tilføjer yderligere to metoder:


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

Den første vil lade os få parametrene for vores metoder, og den anden vil også give os parameteriserede typer.


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

Vi vil kun få adgang til én af vores metoder. For at få adgang til en metode med et specifikt navn, kalder vi getMethod og indgiver navnet og parametrene for den metode, vi ønsker:


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

Når vi kører vores kode, vil vi se, hvordan metoderne adskiller sig, og hvad de returnerer:

grænseflade java.util.List
klasse java.lang.String

java.util.List<java.lang.String>
klasse java.lang.String

getExceptionTypes() og getGenericExceptionTypes() metoder

Vi kan bruge disse metoder til at få en række undtagelser, som vores metode kan kaste, såvel som undtagelser med parametriserede typer (hvis nogen). Lad os bruge et nyt eksempel, der har en skjult statisk klasse:


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

    private void process() throws IOException {}
}

Og vi kalder metoder på vores processorklasse :


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

Nu kan vi se vores undtagelse:

[klasse java.io.IOException]

Lad os nu parametrisere typen. Vi ændrer vores hovedklasse:


private static class Processor<E extends IOException> {

    private void process() throws E {
    }
}

Og koden for hovedmetoden :


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

Inde i denne metode har vi et TypeVariables- objekt, som er en generisk overordnet grænseflade til typevariabler. Og indeni det kan vi nu få den interne parameter, nemlig vores indlejrede undtagelse:

[E]
klasse java.io.IOException

getAnnotations() og getDeclaredAnnotations() metoder

Lad os fortsætte med at bruge denne nye klasse og tilføje et par anmærkninger til den. Vi opretter vores egen annoteringsanmærkning :


@Retention(RetentionPolicy.RUNTIME)
@interface Annotation {

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

Og anvende det på vores metode:


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

}

Og selvfølgelig tilføjer vi en metode til at vise alle vores annoteringer:


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

Implementering af vores hovedmetode :


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

Det resulterende skærmoutput er:

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

Det er sådan, vi kan få de annoteringer, der er blevet anvendt på vores metoder, og getAnnotations- metoden giver os også adgang til klassens overordnede annoteringer.

I dag har vi stiftet bekendtskab med, hvordan refleksion kan arbejde med metoder og felter, og hvilke data vi kan få med det!