본문 바로가기

STUDY/이펙티브자바

9-9) 리플렉션보다는 인터페이스를 사용하라

자바 리플렉션

 

// effectivejava 패키지에 선언된 Person 클래스
package effectivejava;

public class Person {
    private int age;
    private String name;
	
    public Person(int age, String name) {
	    super();
	    this.age = age;
		this.name = name;
    }

    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }
}

// 다른 .java 파일의 main 코드
Class personClass = Class.forName("effectivejava.Person");

for(Field field : personClass.getDeclaredFields()) {
    System.out.println(field.getName());
}

for(Constructor constructor : personClass.getConstructors()) {
    System.out.println(constructor.getName());
}

for(Method method : personClass.getDeclaredMethods()) {
    System.out.println(method.getName());
}

 

// Person 클래스의 필드, 생성자, 메소드들의 이름이 출력된다
// private로 선언되어있어서 존재를 알 수 없는 age, name까지 확인할 수 있다.
age
name
effectivejava.Person
toString

 

자바 리플렉션은 클래스의 필드, 생성자, 메소드 등 모든 정보를 분석, 조작하는 행위를 말한다. 위의 코드를 보면 Person 클래스가 존재하고 필드와 생성자, 메소드가 정의되어있다. 그리고 main 코드에서 Person의 Class 객체를 이용하여 선언된 필드, 생성자, 메소드를 출력하고 있다. 실제 실행결과를 보면 age, name, Person, toString 등 Person 클래스의 모든 정보가 나온다. 여기서 흥미로운 점은 본래 private로 선언되어있어서 존재조차 알 수 없는 age, name 필드까지 출력된다는 것이다. 이처럼 자바 리플렉션은 엄청난 자유도를 가져다주는 매우 강력한 도구라고 할 수 있다.

 

  


리플렉션 사용을 자제하라

 

리플렉션은 매우 강력한 기능이면서도 매우 많은 단점을 가지고있다. 먼저 클래스를 분석하고 조작하는 모든 동작이 런타임에 결정되고 이루어지기 때문에 컴파일 검사가 주는 이점을 모두 포기해야 한다. 자바 리플렉션을 사용하다보면 런타임 에러가 발생할 확률이 매우 올라간다. 또 리플렉션을 사용하면 코드의 가독성이 떨어진다. 클래스의 구조를 분석하는 과정이 복잡하기 때문에 코드또한 길어지고 장황해진다. 마지막으로 성능이 떨어진다. 정상적으로 인스턴스의 리플렉션을 사용하여 메소드를 호출하면 메소드를 호출하는 것보다 상당히 느리게 동작하는것을 확인할 수 있다.

 

 


인터페이스로 사용하라

 

// 리플렉션으로 객체를 생성하고 메소드를 호출하였다.
Object listObj = ArrayList.class.newInstance();
ArrayList.class.getDeclaredMethod("isEmpty", null).invoke(listObj, null);

// 리플렉션으로 객체를 생성하고 인터페이스를 참조하여 메소드를 호출하였다.
List list = ArrayList.class.newInstance();
list.isEmpty();

리플렉션은 그 단점때문에 제한된 용도로만 사용하는것이 좋다. 예를 들어 리플렉션으로 인스턴스를 생성하였다고 할지라도 인스턴스를 사용할때는 인터페이스로 참조하여 사용하는것이 좋다. 

 

 


리플렉션의 활용

 

// application.yml 설정파일
// JDBC 드라이버 클래스로 org.mariadb.jdbc.Driver를 설정하였다.
spring:
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://127.0.0.1:3307/test
    username: root
    password: ${LOCAL_MARIADB_PASSWORD}

이처럼 여러 단점이 있음에도 자바 리플렉션을 사용하는 이유는 매우 강력한 도구이고 이를 통해 높은 자유도의 코드를 개발할 수 있기 때문이다. 위는 Spring을 사용하는 프로젝트에서 볼 수 있는 설정파일이다. 여기서 JDBC 클래스로 org.mariadb.jdbc.Driver 클래스를 사용하라고 설정한 것을 볼 수 있다. Spring 프레임워크가 실행되면 이 설정파일을 읽어서 Class.forName("org.mariadb.jdbc.Driver")으로 클래스를 찾는다. 이 구조의 흥미로운 점은 Spring 프레임워크를 개발할 당시에는 org.mariadb.jdbc.Driver 클래스가 없어도된다는 것이다. 그리고 추후 어떠한 클래스던 java.sql.Driver을 상속한 클래스를 만들고 이름만 넣으면 기존 Spring 코드의 수정 없이 사용할 수 있다. 이처럼 자바 리플렉션은 엄청난 자유도를 제공해줄 수 있다.

 

 

 

728x90