java.lang.reflect.Field 클래스

Field 클래스 클래스 또는 인터페이스의 단일 필드에 대한 정보 및 동적 액세스를 제공합니다. Field는 get 또는 set 액세스 작업 중에 확장 유형 변환을 허용하지만 축소가 발생하면 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;
}

다음은 해당 클래스로 작업하기 위한 코드입니다.


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

이것이 나중에 작업할 클래스의 필드 목록을 얻는 방법입니다. 결과는 다음과 같습니다.

[비공개 java.lang.String com.company.Person.name, 비공개 int com.company.Person.age, 공개 부울 com.company.Person.isMale, 보호된 java.lang.String com.company.Person.address, 공개 정적 최종 int com.company.Person.MAX_AGE, 공개 정적 최종 int com.company.Person.MIN_AGE]

이제 이 데이터로 무엇을 할 수 있는지 알아봅시다. Field 클래스 의 메서드에 대해 이야기해 봅시다 .

방법 설명
getType() 이 필드가 나타내는 필드의 선언된 유형을 식별하는 클래스 객체를 반환합니다.필드물체.
getAnnotatedType() 반환주석 유형이 Field가 나타내는 필드의 선언된 유형을 지정하기 위해 유형의 사용을 나타내는 개체입니다.
getGenericType() 반환유형this가 나타내는 필드의 선언된 유형을 나타내는 객체필드물체.
getName() 이 표시되는 필드의 이름을 반환합니다.필드물체.
getModifiers() 이 항목이 나타내는 필드에 대한 Java 언어 수정자를 인코딩하는 int를 반환합니다.필드물체.
getAnnotations() 이 필드에 대한 주석을 반환합니다. 주석이 없으면 빈 배열을 반환합니다.

getType(), getName() 및 getModifiers() 메서드

getType() 메서드를 사용하여 필드의 유형을 가져올 수 있습니다. 방법을 작성해 봅시다:


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

결과는 다음과 같습니다.

클래스 java.lang.String
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()));
}

이제 결과가 더 이해하기 쉽습니다.

필드 유형 - class java.lang.String
필드 이름 - name

필드 유형 - int
필드 이름 - age

필드 유형 - boolean
필드 이름 - isMale

필드 유형 - class 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())));
}

그리고 e.getModifiers() 가 반환하는 것을 살펴보겠습니다 . 이 메서드는 필드의 액세스 한정자의 상태를 결정할 수 있는 int를 반환합니다. Modifier 클래스에는 필드의 각 특정 수정자를 담당하는 정적 변수가 포함되어 있습니다 .

반환 값을 Modifier.toString() 에 래핑 하고 즉시 값을 텍스트로 가져옵니다.

필드 유형 - 클래스 java.lang.String
필드 이름 - 이름
수정자 - 개인

필드 유형 - int
필드 이름 - 나이
수정자 - 개인

필드 유형 - 부울
필드 이름 - isMale
수정자 - 공개

필드 유형 - 클래스 java.lang.String
필드 이름 - 주소
수정자 - 보호된

필드 유형 - int
필드 이름 - MAX_AGE
수정자 - public static final

필드 유형 - int
필드 이름 - MIN_AGE
수정자 - public static final

Modifier.toString() 이 없는 모습은 다음과 같습니다 .

필드 유형 - 클래스 java.lang.String
필드 이름 - 이름
수정자 - 2

필드 유형 - int
필드 이름 - 연령
수정자 - 2

필드 유형 - 부울
필드 이름 - isMale
수정자 - 1

필드 유형 - 클래스 java.lang.String
필드 이름 - 주소
수정자 - 4

필드 유형 - int
필드 이름 - MAX_AGE
수정자 - 25

필드 유형 - int
필드 이름 - MIN_AGE
수정자 - 25

getAnnotations(), getAnnotatedType() 및 getGenericType() 메서드

이러한 메서드와 함께 작동하도록 Person 클래스를 수정해 보겠습니다 . 자체 주석을 작성하여 필드에 적용합니다. 그리고 필드를 몇 개 더 추가합니다.

두 개의 주석을 만들어 보겠습니다. Pig Latin의 변수 이름을 하나에 전달하고 두 번째는 요소에 사용합니다.


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

우리 방법의 결과를 살펴보고 그것이 무엇을 위한 것인지 알아낼 때입니다.

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

getGenericType:
java.lang.Class<java.lang. 객체>
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")]
[@이름(이름="\u0041\u006d\u0065\u002d\u006e\u0061\u0079")] [
]
  • getAnnotatedType은 주어진 필드에 대한 주석을 반환합니다(있는 경우). 필드에 대한 주석을 얻었고 완벽하게 볼 수 있습니다.

  • getGenericType을 사용하면 매개변수화된 유형을 올바르게 표시할 수 있습니다.

  • getAnnotations는 개체에 적용된 주석을 반환합니다.

이것은 클래스의 각 필드에 대한 모든 데이터와 액세스 수정자, 주석 및 데이터 유형을 쉽게 얻을 수 있는 방법입니다.

java.lang.reflect.Method 클래스

감독자! 우리는 우리 수업의 분야에 대해 이야기했습니다. 이제 방법에 대해 이야기할 시간입니다.

Method 객체를 얻으려면 getMethod 메서드를 호출하여 메서드 이름을 전달합니다. 이것은 Method 객체를 얻는 기본 방법입니다 .


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

우리는 계속해서 우리 학급과 함께 일할 것입니다. getter 및 setter, hashCode, equalstoString 메서드를 추가해 보겠습니다 .


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() 메서드가 throw할 수 있는 예외를 반환합니다.
getGenericExceptionTypes() 매개변수화된 유형을 고려하여 메서드가 throw할 수 있는 예외를 반환합니다.
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));
}

우리의 결과:

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

모든 메서드에는 public 한정자가 있으므로 마지막 메서드는 1의 배열을 반환합니다. 코드를 수정하면 수정자 자체가 표시됩니다.


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] [
공개, 공개, 공개, 공개, 공개, 공개, 공개, 공개, 공개, 공개, 공개]

getReturnedType()

이 메서드를 사용하면 메서드의 반환 유형을 얻을 수 있습니다.


static void getReturnedType(Method[] methods) {
    Arrays.stream(methods)
            .map(Method::getReturnType)
            .forEach(System.out::println);
}
클래스 java.lang.String
부울
클래스 java.lang.String
int
void
클래스 java.lang.String
부울
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);
}

우리 방법의 결과:

클래스 java.lang.String
부울
클래스 java.lang.String
int
void
클래스 java.lang.String
부울
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);
}

코드를 실행하면 메서드가 어떻게 다른지, 반환되는 내용이 무엇인지 확인할 수 있습니다.

인터페이스 java.util.List
클래스 java.lang.String

java.util.List<java.lang.String>
클래스 java.lang.String

getExceptionTypes() 및 getGenericExceptionTypes() 메서드

이러한 메소드를 사용하여 메소드가 던질 수 있는 예외 배열과 매개변수화된 유형이 있는 예외(있는 경우)를 가져올 수 있습니다. 숨겨진 정적 클래스가 있는 새 예제를 사용하겠습니다.


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

    private void process() throws IOException {}
}

그리고 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));
}

이제 예외를 볼 수 있습니다.

[클래스 java.io.IOException]

이제 유형을 매개변수화하겠습니다. 기본 클래스를 수정합니다.


private static class Processor<E extends IOException> {

    private void process() throws E {
    }
}

그리고 주요 방법 의 코드 :


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 개체가 있습니다 . 그 안에 이제 내부 매개변수, 즉 중첩 예외를 가져올 수 있습니다.

[E]
클래스 java.io.IOException

getAnnotations() 및 getDeclaredAnnotations() 메서드

이 새 클래스를 계속 사용하고 몇 가지 주석을 추가해 보겠습니다. 자체 Annotation 주석을 생성합니다 .


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

결과 화면 출력은 다음과 같습니다.

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

이것이 메서드에 적용된 주석을 가져올 수 있는 방법이며 getAnnotations 메서드를 사용하면 클래스의 상위 주석에도 액세스할 수 있습니다.

오늘 우리는 리플렉션이 메서드 및 필드와 함께 작동하는 방식과 이를 통해 얻을 수 있는 데이터에 대해 알게 되었습니다!