자바의 리플렉션 기능은 뭘까요?

2014-05-21 01:38

(1) 자바에는 리플렉션이라는 게 있다고 들었는데요. 용도가 뭘까요? 그리고 실전에서 사용해 본 경험이 있나요?

(2) JDBC 드라이버를 사용할 때 Class.forName()이라는 메소드를 사용하는데, 이건 또 뭔가요? 그리고 JDBC 외에 다른 사용 용도가 있을까요?

0개의 의견 from FB

1개의 의견 from SLiPP

2014-05-23 13:07

동적으로 로드하고 싶고, 동적으로 실행하고 싶을 때 사용합니다. 대부분의 경우에 컴파일 시점에 클래스의 타입, 필드, 메소드들이 정의되지만 컴파일 이후의 시점에서 뭔가 제어를 해야할 필요가 있을 때가 있습니다.

본인모듈의 무결성을 유지하고(암것도 낑겨넣지않고) 외부모듈을 런타임시에만 사용하려고 하는 경우 스프링같은 뎁스가 깊은 라이브러리 내부의 로깅이 필요한 경우 커스텀 어노테이션을 만드는 경우

우선 java파일을 컴파일 한 이후의 상황에 대해서 상기할 필요가 있습니다. java코드 작성 후에 컴파일하고 나면 c++ 과는 다르게 단독으로 실행가능한 상태가 아닙니다. 클래스식별자인 magicNumber헤더와 나머지 데이터필드들을 가지고 클래스로더를 통해 로드되어지고 jvm에 의해 실행가능한 상태이죠 이때 클래스에서는 내부적으로 invokespecial 메소드 호출 후 최상위 Object를 통해서 해당 클래스가 초기화되어집니다. 그래서 단독클래스의 경우에는 main메소드는 반드시 static 이어야 합니다. 본인 스스로 인스턴스를 생성하는 게 아니니까요.

우선 class.forName에 대한 좀 더 자세한 내용이 필요할 수 있습니다. jdbc에 class.forName이 등장하는 이유는 벤더들 때문입니다.

oracle, mysql, mssql, postgresql, db2 등 다양한 dbms와 이 dbms들이 만들어낸 다양한 버전을 대응할 수 없기 때문에 JDBC 스펙을 정의하고 해당 드라이버에 대한 구현은 각 벤더에게 위임했습니다. 그래서 각 dbms마다 jdbc 라이브러리가 다 다릅니다. 대신 registerDirver메소드에 의해 등록되도록 만들었습니다. 이제 문제는 그 라이브러리가 어디있는지 어떻게 인식시키느냐는 건데 이때 class.forName을 사용해서 해당 클래스의 위치를 알려줄 수 있습니다. 하지만 알려줄 뿐이지 로드하지는 않습니다.

class.forName을 사용할 경우에는 .newInstance()메소드를 호출해서 인스턴스를 생성해야 합니다.

Class c = Class.forName("Aoa.설현"); GirlGroup gg= (Girl)c.newInstance(); //리턴형 Object

실제로 class.forName메소드에는 3개의 인자가 있습니다. 첫번째 인자는 클래스명문자열, 두번째 인자는 초기화여부, 세번째 인자는 클래스로더 입니다.

대부분의 경우에 첫번째 인자만을 사람들이 사용하는 데 그 이유는 두번째 초기화처리에 대한 인자 기본값이 true이고 세번째인자의 경우에는 this.getClass().getClassLoader() 하도록 되어있기 때문에 그렇습니다.

class.forName에 이렇게 인자가 많은 이유는 클래스로더의 특성때문입니다. 객체간의 통신은 단일 로더안에서만 가능하기 때문에 만일 로딩하려는 클래스가 이미 로드된 경우에는 NoClassDefinitionFound 오류가 발생할 수 있습니다.

class.forName 사용 시에 두번째 인자에 대해서 값을 명시하지 않으면 로드 후에 해당 클래스의 초기화블럭과 static 맴버변수의 값을 초기화합니다.

세번째 인자에 classLoader를 명시하는 경우는 명시된 classLoader를 사용하기 위해서 기존 ClassLoader를 버리게 되는데 사용 안해봤습니다. 잘 모르겠네요..

ClassLoader.loadClass를 이용해서 로드할 경우에는 해당 클래스의 사용이 요청될 때까지 초기화가 지연됩니다. ojdbc6 sqljdbc4 mysql-connector-java-com5와 같이 JDBC4.1 스펙을 만족하는 드라이버를 사용하는 경우에는 JDBC사용시에 드라이버를 자동으로 로딩하기 때문에 class.forName을 사용하지 않아도 됩니다.

앞서 말씀드렸듯이 class.forName은 class를 로딩하는 역할을 합니다. 그리고 세번째인자의 값이 this.getClass().getClassLoader()라는 것을 기억하실 겁니다.

그렇다면 실제로 클래스 로딩은 class.forName이 수행하는 것이 아니라 classLoader의 loadClass 메소드를 통해서 이루어지고 class.forName은 직접적인 호출을 피하기 위한 완충작용을 한다고 볼 수 있습니다.

jdk1.6 부터는 javax.tools.JavaCompiler 인터페이스를 통해서 동적으로 컴파일할 수 있고 java.lang.invoke 등을 이용해서 보다 편하게 작업할 수 있습니다.

의견 추가하기

연관태그

← 목록으로