[Java] Class 클래스

Class 클래스

자바는 클래스와 인터페이스의 메타 데이터를 java.lang.Class의 클래스를 통해 관리한다. 메타 데이터란 클래스 이름, 필드, 생성자, 메서드 등을 말한다.

Class 객체 얻기

ObjectgetClass()를 통해 얻을 수 있다. 해당 메서드는 인스턴스를 생성했을 때만 사용할 수 있다. 인스턴스를 통하지 않고 Class의 정적 메서드인 forName() 을 통해 직접 클래스를 얻어오는 방법도 있다. 이 때 forName()의 인자로는 패키지가 포함된 클래스 또는 인터페이스 이름을 넣어주어야 한다.

@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

String으로 된 클래스 또는 인터페이스를 찾아 내부적으로 Reflection을 이용하고 있는 걸 알 수 있다.

아래는 간단한 예제이다. 해당 메서드를 이용할 때 인자로 대입된 값으로 클래스를 찾지 못하면 ClassNotFoundException을 발생시키므로 예외처리를 적절히 해주어야 한다.

public class ClassExam {

    public static void main(String[] args) throws ClassNotFoundException {

				
        Author author = new Author(); 
        Class authorClass = author.getClass(); // 인스턴스 생성하여 Class 객체 얻어오기

				
        Class clazz = Class.forName("org.java.chap11.apis.clone.Author"); // forName()으로 Class 객체 얻어오기
        System.out.println(clazz.getName());
        System.out.println(Arrays.toString(clazz.getDeclaredMethods()));
        System.out.println(Arrays.toString(clazz.getClasses()));
    }

}
org.java.chap11.apis.clone.Author
[public java.lang.String org.java.chap11.apis.clone.Author.toString(), protected java.lang.Object org.java.chap11.apis.clone.Author.clone() throws java.lang.CloneNotSupportedException, public java.lang.String org.java.chap11.apis.clone.Author.getName(), public java.lang.String org.java.chap11.apis.clone.Author.getId(), public void org.java.chap11.apis.clone.Author.setName(java.lang.String), public java.lang.String org.java.chap11.apis.clone.Author.getCountry(), public org.java.chap11.apis.clone.Biography org.java.chap11.apis.clone.Author.getBiography(), public void org.java.chap11.apis.clone.Author.setCountry(java.lang.String), public java.lang.String org.java.chap11.apis.clone.Author.getAge(), public void org.java.chap11.apis.clone.Author.setBooks(java.lang.String[]), public org.java.chap11.apis.clone.Author org.java.chap11.apis.clone.Author.cloneAuthor(), public void org.java.chap11.apis.clone.Author.setBiography(org.java.chap11.apis.clone.Biography), public void org.java.chap11.apis.clone.Author.setId(java.lang.String), public java.lang.String[] org.java.chap11.apis.clone.Author.getBooks(), public void org.java.chap11.apis.clone.Author.setAge(java.lang.String)]

위와 같은 두 가지 방식으로 클래스를 찾아올 수 있다. 패키지까지 모두 검색하는 것은 복잡할 수 있으므로 인스턴스를 통해 Class 객체를 얻어오는 것이 편해보인다.

Reflection

위와 같이 클래스나 인터페이스의 메타 정보를 찾아내는 것을 리플렉션이라고 한다. 위 예시에서 사용한 메서드 말고 다양한 메서드를 통해 클래스의 정보를 알아낼 수 있다.

예를 들어 getDeclaredMethods() 는 클래스 내부에 선언된 생성자의 정보를 배열의 형태로 받아온다. 상속받은 생성자는 무시하는데, 상속된 내용까지 확인하고 싶다면 getMethods() 를 이용하면 된다.



동적 객체 생성

Class 클래스의 newInstance()를 활용하면 런타임 시에 지정해둔 클래스를 동적으로 객체를 생성할 수도 있다.

newInstance()는 두 가지 예외를 발생시킨다. 따라서 예외 처리를 해주어야 한다.

  • InstantiationException:
    대입된 클래스가 추상 클래스이거나 인터페이스여서 인스턴스화할 수 없는 경우

  • IllegalAccessException:
    클래스나 생성자가 접근제한자로 인해 접근할 수 없을 경우

newInstance() 리턴 타입은 Object이므로 생성한 인스턴스를 변수에 저장하기 위해서는 변수 타입에 맞게 캐스팅을 해주어야 한다. 그런데 컴파일 단계에서는 어떤 타입의 변수를 쓸지 알 수가 없으므로 인터페이스를 구현하여 처리한다(구현 클래스의 형태는 인터페이스만 구현하면 형을 다양하게 바꿀 수 있으므로). 아래의 예시를 보자.

public interface TestInterface {

    void method1();
}
public class RuntimeClass1 implements TestInterface{

    @Override
    public void method1() {
        System.out.println("runtime class 1");
    }
}
public class RuntimeClass2 implements TestInterface {

    @Override
    public void method1() {
        System.out.println("RuntimeClass 2");
    }
}
public class NewInstanceExam {

    public static void main(String[] args) {

        try {
            Class clazz = Class.forName("org.java.chap11.apis.clazz.RuntimeClass1");
            TestInterface testInterface = (TestInterface) clazz.newInstance();
            testInterface.method1();
        } catch (ClassNotFoundException | InstantiationException |IllegalAccessException e ){
            e.printStackTrace();
        }

    }
}
runtime class 1

위와 같이 동적으로 생성할 인스턴스를 forName()으로 얻어온 뒤 TestInterface 타입으로 캐스팅해주면 인터페이스를 구현하는 인스턴스를 생성할 수 있다.


source: github

reference: 「이것이 자바다」, 신용권

좋은 웹페이지 즐겨찾기