java.lang.reflect.Field class

Ang Field class ay nagbibigay ng impormasyon tungkol sa at dynamic na access sa isang field ng isang klase o interface. Binibigyang-daan din ng field ang pagpapalawak ng uri ng conversion sa panahon ng pagkuha o pagtatakda ng operasyon ng pag-access, ngunit naghagis ng IllegalArgumentException kung magkakaroon ng pagpapaliit.

Upang makakuha ng Field object, magsusulat muna kami ng isang klase:


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

At narito ang aming code para sa pagtatrabaho sa klase na iyon:


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

Ito ay kung paano namin makuha ang listahan ng mga patlang ng aming klase, na gagawin namin sa ibang pagkakataon. Narito ang resulta:

[private java.lang.String com.company.Person.name, private int com.company.Person.age, public boolean com.company.Person.isLalaki, protected java.lang.String com.company.Person.address, pampubliko static final int com.company.Person.MAX_AGE, public static final int com.company.Person.MIN_AGE]

Ngayon, alamin natin kung ano ang magagawa natin sa data na ito. Pag-usapan natin ang mga pamamaraan ng klase ng Field :

Pamamaraan Paglalarawan
getType() Nagbabalik ng Class object na kinikilala ang ipinahayag na uri ng field na kinakatawan nitoPatlangbagay.
getAnnotatedType() Ibinabalik ang isangAnnotatedTypebagay na kumakatawan sa paggamit ng isang uri upang tukuyin ang ipinahayag na uri ng field na kinakatawan ng Field na ito.
getGenericType() Nagbabalik aUribagay na kumakatawan sa ipinahayag na uri ng patlang na kinakatawan nitoPatlangbagay.
getName() Ibinabalik ang pangalan ng field na kinakatawan nitoPatlangbagay.
getModifiers() Nagbabalik ng int encoding ng Java language modifiers para sa field na kinakatawan nitoPatlangbagay.
getAnnotations() Ibinabalik ang mga anotasyon para sa field na ito. Kung walang mga anotasyon, nagbabalik ito ng isang walang laman na array.

getType(), getName(), at getModifiers() na mga pamamaraan

Maaari naming gamitin ang getType() na paraan upang makuha ang uri ng aming field. Sumulat tayo ng isang pamamaraan:


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

At nakuha namin ang resultang ito:

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

Ngayon, magdagdag tayo ng paraan sa ating klase para makuha ang pangalan ng isang field. Gagawin nitong mas madali ang pag-navigate sa mga field ng aming klase.


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

Ngayon ang resulta ay mas nauunawaan:

Uri ng field - class java.lang.String
Pangalan ng Field - pangalan

Uri ng field - int
Pangalan ng field - edad

Uri ng field - boolean
Pangalan ng field - isMale

Uri ng Field - class java.lang.String
Pangalan ng Field - address

Uri ng field - int
Pangalan ng Field - MAX_AGE

Uri ng field - int
Pangalan ng field - MIN_AGE

Malaki! Baguhin pa natin ang ating pamamaraan! Magdaragdag kami ng mga modifier ng access dito


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

At tingnan natin kung ano ang ibinabalik ng e.getModifiers() . Ang pamamaraang ito ay nagbabalik ng isang int na nagbibigay-daan sa amin na matukoy ang estado ng mga modifier ng access ng aming field. Ang klase ng Modifier ay naglalaman ng mga static na variable na responsable para sa bawat partikular na modifier ng field.

I-wrap natin ang ating return value sa Modifier.toString() at agad na makuha ang value nito bilang text:

Uri ng field - class java.lang.String
Pangalan ng Field - pangalan
Mga Modifier - pribadong

Uri ng Field - int
Pangalan ng field - edad
Mga Modifier - pribadong

Uri ng Field - boolean
Pangalan ng Field - isMale
Modifier - pampublikong

Uri ng Field - class java.lang.String
Pangalan ng Field - address
Mga Modifier - protektadong

Uri ng Field - int
Pangalan ng Field - MAX_AGE
Mga Modifier - pampublikong static na panghuling

Uri ng field - int
Pangalan ng Field - MIN_AGE
Mga Modifier - pampublikong static na pangwakas

Narito kung ano ang hitsura nang walang Modifier.toString() :

Uri ng field - class java.lang.String
Pangalan ng field - pangalan
Mga Modifier - 2

Uri ng field - int
Pangalan ng field - edad
Mga Modifier - 2

Uri ng field - boolean
Pangalan ng field - isMale
Mga Modifier - 1

Uri ng field - class java.lang.String
Pangalan ng Field - address
Mga Modifier - 4

Field type - int
Field name - MAX_AGE
Modifiers - 25

Field type - int
Field name - MIN_AGE
Modifiers - 25

getAnnotations(), getAnnotatedType(), at getGenericType() na mga pamamaraan

Baguhin natin ang klase ng Tao upang gumana sa mga pamamaraang ito. Magsusulat kami ng sarili naming anotasyon at ilalapat ito sa aming mga field. At magdaragdag kami ng ilan pang mga field.

Gumawa tayo ng dalawang anotasyon. Ipapasa namin ang variable na pangalan sa Pig Latin sa isa, at gagamitin namin ang pangalawa para sa mga elemento:


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

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

At babaguhin namin ang aming pangunahing klase at ang klase ng Tao :


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

Panahon na upang tingnan ang mga resulta ng aming mga pamamaraan at alamin kung para saan ang mga ito:

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
class [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")] [
]
  • Ibinabalik ng getAnnotatedType ang anotasyon para sa ibinigay na field, kung mayroon man. Nakukuha namin ang anotasyon para sa field at nakikita namin ito nang perpekto.

  • Hinahayaan ka ng getGenericType na magpakita ng tama ng isang parameterized na uri.

  • Ibinabalik ng getAnnotations ang mga annotation na inilapat sa aming object.

Ito ay kung paano namin madaling makuha ang lahat ng data tungkol sa bawat field sa aming klase, pati na rin ang mga access modifier, anotasyon at uri ng data nito.

java.lang.reflect.Method class

Super! Napag-usapan na namin ang mga larangan ng aming klase. Ngayon ay oras na upang pag-usapan ang mga pamamaraan.

Upang makakuha ng object na Method , tinatawagan namin ang getMethod method, na ipinapasa ito sa pangalan ng aming method. Ito ang pangunahing paraan upang makakuha ng object na Method :


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

Magpapatuloy kami sa aming klase. Magdagdag tayo ng mga getter at setter, at hashCode, equals at toString na mga pamamaraan:


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

Ngayon ay maghanda tayo ng isang hanay ng mga pamamaraan na ating susuriin gamit ang klase ng Method . Narito ang isang listahan ng pinakamahalagang pamamaraan:

Pamamaraan Paglalarawan
getName() Ibinabalik ang pangalan ng pamamaraan.
getModifiers() Ibinabalik ang access modifier ng paraang ito.
getReturnType() Ibinabalik ang uri ng pagbabalik ng pamamaraan.
getGenericReturnType() Ibinabalik ang uri ng pagbabalik ng pamamaraan, na isinasaalang-alang ang mga generic na pamamaraan.
getParameterTypes() Nagbabalik ng hanay ng mga parameter ng pamamaraan.
getGenericParameterTypes() Nagbabalik ng hanay ng mga parameter ng pamamaraan, na isinasaalang-alang ang mga generic na pamamaraan.
getExceptionTypes() Ibinabalik ang mga pagbubukod na maaaring itapon ng pamamaraan.
getGenericExceptionTypes() Ibinabalik ang mga pagbubukod na maaaring itapon ng pamamaraan, na isinasaalang-alang ang mga naka-parameter na uri.
getAnnotations() Ibinabalik ang mga anotasyon para sa pamamaraan, kabilang ang mga anotasyon ng magulang.
getDeclaredAnnotations() Ibinabalik ang mga anotasyon para sa pamamaraan, hindi kasama ang mga anotasyon ng magulang.

Upang makakuha ng isang hanay ng mga pamamaraan ng aming klase, maaari naming tawagan ang pamamaraang ito:


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

Ibibigay nito sa amin ang lahat ng mga pamamaraan sa aming klase.

getName() at getModifiers() na mga pamamaraan

Maaari naming gamitin ang getName upang makuha ang pangalan ng bawat pamamaraan:


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

Ngayon upang makuha ang mga modifier, magsulat tayo ng isang paraan na gumagamit ng getModifiers :


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

Narito ang aming pangunahing pamamaraan:


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

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

Ang aming resulta:

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

Ang lahat ng aming mga pamamaraan ay may pampublikong modifier, kaya ang huling paraan ay nagbabalik ng isang hanay ng mga iyon. Kung babaguhin namin ang aming code, makikita namin mismo ang aming mga modifier:


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

getReturnedType()

Hinahayaan kami ng pamamaraang ito na makuha ang uri ng pagbabalik ng pamamaraan:


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

getGenericReturnType()

Bigyan natin ang klase ng Tao ng isang paraan na nagbabalik ng uri na nakabalot sa isang naka-parameter na uri, at subukang makuha ang return value nito:


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

At i-update namin ang aming pangunahing pamamaraan:


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

Resulta ng aming pamamaraan:

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

getParameterTypes() at getGenericParameterTypes() na mga pamamaraan

Patuloy naming binabago ang aming klase ng Tao , nagdaragdag ng dalawa pang pamamaraan:


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

Ang una ay magbibigay-daan sa amin na makuha ang mga parameter ng aming mga pamamaraan, at ang pangalawa ay magbibigay din sa amin ng mga parameterized na uri.


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

Isa lang sa aming mga pamamaraan ang maa-access namin. Upang ma-access ang isang paraan sa pamamagitan ng isang partikular na pangalan, tinatawagan namin ang getMethod at ipinapasa ang pangalan at mga parameter ng paraan na gusto namin:


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

Sa pagpapatakbo ng aming code, makikita natin kung paano naiiba ang mga pamamaraan at kung ano ang ibinabalik nila:

interface java.util.List
class java.lang.String

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

getExceptionTypes() at getGenericExceptionTypes() na mga pamamaraan

Magagamit namin ang mga paraang ito upang makakuha ng hanay ng mga eksepsiyon na maaaring itapon ng aming pamamaraan, pati na rin ang mga pagbubukod na may mga naka-parameter na uri (kung mayroon man). Gumamit tayo ng bagong halimbawa na may nakatagong static na klase:


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

    private void process() throws IOException {}
}

At tatawagin namin ang mga pamamaraan sa aming klase ng Processor :


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

Ngayon ay makikita na natin ang ating exception:

[class java.io.IOException]

Ngayon, i-parameter natin ang uri. Babaguhin namin ang aming pangunahing klase:


private static class Processor<E extends IOException> {

    private void process() throws E {
    }
}

At ang code ng pangunahing pamamaraan:


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

Sa loob ng pamamaraang ito, nakakuha kami ng object na TypeVariables , na isang generic na interface ng magulang para sa mga variable ng uri. At sa loob nito, maaari na nating makuha ang panloob na parameter, katulad ng ating nested exception:

[E]
class java.io.IOException

getAnnotations() at getDeclaredAnnotations() mga pamamaraan

Ipagpatuloy natin ang paggamit ng bagong klase na ito at magdagdag ng ilang anotasyon dito. Gagawa kami ng sarili naming anotasyon ng Anotasyon :


@Retention(RetentionPolicy.RUNTIME)
@interface Annotation {

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

At ilapat ito sa aming pamamaraan:


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

}

At siyempre magdaragdag kami ng paraan para ipakita ang lahat ng aming anotasyon:


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

Pagpapatupad ng aming pangunahing pamamaraan:


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

Ang resultang screen output ay:

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

Ito ay kung paano namin makukuha ang mga anotasyon na inilapat sa aming mga pamamaraan, at ang getAnnotations na pamamaraan ay nagbibigay-daan sa amin na ma-access din ang mga magulang na anotasyon ng klase.

Ngayon nakilala namin kung paano gumagana ang pagmuni-muni sa mga pamamaraan at field, at kung anong data ang makukuha namin dito!