# Table of Contents

# 클래스 참조, Class 클래스

Java의 모든 클래스와 인터페이스는 컴파일 후 .class파일로 변환된다. 이 파일에는 생성자, 멤버변수, 메서드 등 객체의 정보가 포함되어있는데 Class클래스를 사용하면 이 파일에서 가져온 객체의 정보를 담을 수 있다. 이를 클래스 참조(Class Reference)라고 한다.

Class클래스에 정보를 담는 방법에는 세 가지가 있다.

// 클래스에 .class를 붙여서 객체 정보 가져오기
Class clazz = String.class
// 인스턴스에서 getClass()를 호출하여 객체 정보 가져오기
String string = new String();
Class clazz = string.getClass();
// Class클래스의 forName()메소드를 사용하여 객체 정보 가져오기
Class clazz = Class.forName("java.lang.String");

# 리플렉션(Reflection)

코드를 작성하다보면 작성 시점에 데이터의 타입을 모를 수도 있다. 리플렉션(Reflection)런타임에서 클래스의 구체적인 타입을 몰라도 그 클래스의 멤버변수, 메소드 등을 분석하고 접근할 수 있도록 하는 자바 API와 기법이다. 리플렉션과 관련된 API는 java.lang.reflect.*패키지에 있으며, 클래스 참조를 사용하여 리플렉션을 수행할 수 있다.

예제를 살펴보자. 다음과 같은 클래스가 있다.

package com.yologger.app;

class Person {

    String name;
    String nation;

    // 기본 생성자
    Person() {
        this.name = "";
        this.nation = "";
    }

    // 보조 생성자
    Person(String name, String nation) {
        this.name = name;
        this.nation = nation;
    }

    void printName() {
        System.out.println(name);
    }

    void printNation() {
        System.out.println(nation);
    }

    void printSomething(String something) {
        System.out.println(something);
    }

    void printHello() {
        System.out.println("Hello");
    }
}

Class클래스의 인스턴스에는 클래스 정보를 저장할 수 있다.

Class personClass = Person.class;
// 또는 Class personClass = Class.forName("Person");

Class타입의 인스턴스로 클래스의 인스턴스를 생성할 수도 있다. 이 때는 newInstance()메소드를 사용한다. 다만 반드시 매개변수가 없는 기본생성자가 존재해야 한다.




 






Class personClass = Person.class;

try {
    Person person = (Person) personClass.newInstance();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
}

# 클래스의 멤버변수 가져오기

클래스의 멤버변수 정보를 읽어올 수 있다.

import java.lang.reflect.Field;

Field[] fields = personClass.getDeclaredFields();
for (int i=0; i<fields.length; i++) {
    System.out.println(fields[i].getName());
}
// name
// nation

# 클래스의 생성자 가져오기

클래스의 생성자 정보를 읽어올 수도 있다.

import java.lang.reflect.Constructor;

Class personClass = Person.class;

Constructor[] constructors = personClass.getDeclaredConstructors();
for (int i=0; i<constructors.length; i++) {
    System.out.println(constructors[i].getName());
}
// com.yologger.app.Person
// com.yologger.app.Person

# 클래스의 메소드 가져오기

클래스의 모든 메소드들은 다음과 같이 가져올 수 있다.

import java.lang.reflect.Method;

Class personClass = Person.class;

Method[] methods = personClass.getDeclaredMethods();
for (int i=0; i<methods.length; i++) {
    // 메소드 이름 출력
    System.out.println(methods[i].getName());
}
// printName
// printNation
// printSomething
// printHello

특정 메소드 한 개만 가져올 수도 있다.

Class personClass = Person.class;

try {
    Method method = personClass.getDeclaredMethod("printSomething");
    System.out.println(method.getName());   // printSomething
} catch (NoSuchMethodException e) {
    e.printStackTrace();
}

클래스의 메소드를 가져오면 이를 통해 호출도 할 수 있다. 이 때는 invoke()메소드를 호출한다.

Class personClass = Person.class;
Person person = new Person("Paul", "America");

try {
    Method declaredMethod = personClass.getDeclaredMethod("printHello");
    declaredMethod.invoke(person);    // Hello

} catch (NoSuchMethodException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
}