본문 바로가기
Java

[Java] Class 클래스 / 리플렉션 / 동적로딩

by bkuk 2023. 4. 4.

Class 클래스

자바의 모든 클래스와 인터페이스는 컴파일 되고 나면 class 파일로 생성된다. 예를 들어, a.java 파일이 컴파일 되면 a.class 파일이 생성되고 이 class 파일에는 클래스나 인터페이스에 대한 변수, 메서드, 생성자 등의 정보가 들어간다. 이때, Class 클래스는 컴파일된 class 파일에 저장된 클래스나 인터페이스 정보를 가져오는 사용한다.

 

Class 클래스 사용하는 이유

프로그래밍에서 변수를 선언할 때 자료형을 미리 파악하고 그 자료형에 따라 변수를 선언한다. 클래스를 사용할 때도 이미 그 클래스의 정보(변수, 메서드)를 알고 있는 상황에서 프로그램을 만든다. 그런데 반환받는 클래스가 정확히 어떤 자료형인지 모르는 상황도 있다. 이때, Class 클래스를 활용해서 이 문제를 해결할 수 있다.

 

Class 클래스 사용

 

1) Object 클래스의 getClass() 메서드 사용

String str = new String();
Class c = str.getClass();

 

2) 클래스 파일 이름을 Class 변수에 직접 대입

Class c = String.Class;

 

3) Class.forName("클래스 이름") 메서드 사용

Class c = Class.forName("java.lang.String");

 

1)번의 경우 Object에 선언한 getClass() 메서드는 모든 클래스가 사용할 수 있는 메서드이다.

2)~3)번의 겨우에는 컴파일된 클래스 파일이 있다면 클래스 이름만으로 Class 클래스를 반환받는다.

 

 

리플렉션(reflection)

프로그래밍을 하다보면 내가 사용할 클래스의 자료형을 모르는 경우가 있을 수 있다. 예를 들어, 내 컴퓨터에 저장되어 있지 않은 객체를 메모리에 로드하고 생성하는 경우 그 객체의 정보는 알 수 없을 것이다.

이때, Class 클래스를 가져올 수 있다면 해당 클래스 정보..(생성자, 메서드, 멤버 변수 정보)를 찾을 수 있다. 이렇게 사용하려는 클래스의 자료형을 모르는 상태에서 Class 클래스를 활용하여 그 클래스의 정보를 가져오고, 이 정보를 활용하여 인스턴스를 생성하거나 메서드를 호출하는 방식을 '리플렉션'이라고 한다.

 

String 클래스 정보 가져오기

아래 예제는 String 클래스 정보를 가져오는 방법이다. 

public class StringClassTest {
	
	public static void main(String[] args) throws ClassNotFoundException {
		Class<?> strClass = Class.forName("java.lang.String");
		
		Constructor<?>[] cons = strClass.getConstructors();
		for( Constructor<?> c : cons ) {
			System.out.println( c );
		}
		System.out.println();
		Field[] fields = strClass.getFields();
		for( Field field : fields ) {
			System.out.println( field );
		}
		System.out.println();
		Method[] methods = strClass.getMethods();
		for( Method m : methods ) {
			System.out.println( m );
		}
	}
}

Class 클래스를 가져오기 위해 forName() 메서드를 사용한다. String 클래스 이름 java.lang.String을 사용하여 Class 클래스를 가져온다. 

String 클래스의 모든 생성자를 가져오기 위해 Class 클래스의 getConstructor() 메서드를 호출한다.

이렇듯.. Class 클래스와 java.lang.reflect 패키지에 있는 클래스를 활용하면 클래스 이름만 알아도 클래스의 생성자, 메서드 등의 정보를 알 수 있다.

 

인스턴스 생성하기

Class 클래스의 메서드 중 newInstance() 메서드를 사용해서 인스턴스를 생성할 수 있다. newInstance() 메서드는 항상 Object를 반환하므로 생성된 객체형으로 형 변환을 해야한다.

public class NewInstanceTest {
	public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException {
		Person person1 = new Person();
		System.out.println( person1 );
		
		Class<?> pClass = Class.forName("study.Person");
		Constructor<?> con = pClass.getConstructor();
		Person person2 = (Person) con.newInstance();
		System.out.println(person2);
	}
}

 

 

위 코드를 보면 두 가지 방식으로 인스턴스를 생성하고 있다.

Class 클래스를 사용하는 방법은 클래스의 자료형을 직접 사용하는 것보다 복잡하고, 예외처리 해야 한다. 클래스의 정보를 모두 알고 있는 상황에서 리플렉션 프로그래밍을 하면 오히려 코드가 복잡해지고, 속도도 느려진다. 따라서, 리플렉션 프로그래밍은 컴파일 시점에서 알 수 없는 클래스.. 즉, 프로그램 실행 중에 클래스를 메모리에 로딩하거나 객체가 다른 곳에서 위치해서 원격으로 로딩하고 생성할 때 사용한다.

 

동적 로딩

대부분의 클래스 정보는 프로그램이 로딩될 때 이미 메모리에 있다. 그런데 이런 경우를 생각해보면 좋을 것 같다.

어떤 시스템이 있다. 그 시스템은 여러 종류의 데이터베이스를 지원한다. 오라클, MySql.. 등 여러 데이터베이스를 연동할 수 있다. 그렇다고 이 시스템을 컴파일할 때 모든 데이터베이스 라이브러리를 같이 컴파일 할 필요는 없다. 시스템을 구동할 때 어떤 데이터베이스와 연결할지만 결정된다면 해당 드라이버만 로딩하면 된다.

즉, 프로그램 실행 이후 클래스의 로딩이 필요한 경우 클래스의 동적 로딩(dynamic loading) 방식을 사용하면 된다.

 

댓글