본문 바로가기

Java

Class 클래스와 Constructor 클래스

Class 클래스

 

Class는 자바의 내장 클래스로, 클래스의 메타데이터를 나타내는 데 사용됩니다.
Class 클래스는 클래스의 구조, 필드, 메서드, 생성자 등의 정보를 동적으로 검사하고 조작할 수 있는 기능을 제공합니다.

Class<T>에서의 Class는 클래스 객체를 참조하는 변수의 타입을 나타내는 것입니다. Class 객체는 해당 클래스의 정보를 담고 있으며, 클래스의 인스턴스를 생성하거나 메서드를 호출하는 등의 작업을 수행할 수 있습니다.
이를 통해 리플렉션(Reflection)을 사용하여 런타임에 클래스의 동작을 조사하고 조작할 수 있습니다.

MyObject obj = new MyObject();
Class<?> clazz = obj.getClass();
System.out.println("The class of obj is: " + clazz.getName());

 

아래 getClass 메서드는 이 객체의 런타임 클래스를 반환합니다.

리턴된 Class 객체는 표현된 클래스의 정적 synchronized 메서드에 의해 locked 객체입니다.

실제 반환되는 결과 타입은 Class<? extends |X|>인데, 여기서 |X|는 getClass가 호출된 expression의 정적 타입의 소거(erasure)입니다. 예를 들어, 다음 코드 조각에서는 캐스트가 필요하지 않습니다:

리턴된 Class 객체는 표현된 클래스의 정적 synchronized 메서드에 의해 locked 객체입니다.
: 위 문장은 Java의 동시성과 관련된 개념을 설명하고 있습니다. 여기서 말하는 lock 객체는 멀티스레드 프로그래밍에서 중요한 개념입니다. 자바에서는 객체에 대한 동시 접근을 제어하기 위해 동기화(synchronization) 메커니즘이 사용됩니다. 자바에서 클래스의 정적 메서드에 synchronized 키워드를 사용하면, 해당 메서드는 클래스 레벨에서 동기화됩니다. 즉, 메서드에 접근하기 위해 스레드는 해당 클래스의 Class 객체에 대한 락(lock)을 획득해야 합니다. 이 때, getClass() 메서드가 반환하는 Class 객체는 바로 그 클래스의 메타데이터를 나타내는 객체이며, 정적 동기화 메서드에서 사용되는 lock 객체입니다. 간단히 말해, 문장은 getClass() 메서드가 리턴하는 Class 객체가 그 클래스에 대한 정적 동기화 작업에 사용되는 lock 객체임을 설명하고 있는 것입니다. 이는 멀티스레드 환경에서 해당 클래스의 모든 정적 동기화 메서드가 동시에 실행되지 않도록 보장하는 데 사용됩니다.
Number n = 0;
Class<? extends Number> c = n.getClass();

리턴값: 이 객체의 런타임 클래스를 나타내는 Class 객체입니다.

package java.lang;

import jdk.internal.vm.annotation.IntrinsicCandidate;

/**
 Class Object is the root of the class hierarchy.
 Every class has Object as a superclass. 
 All objects,including arrays, implement the methods of this class.
 */
public class Object {

    /**
     * Constructs a new object.
     */
    @IntrinsicCandidate
    public Object() {}
    
    @IntrinsicCandidate
    public final native Class<?> getClass();
    
    ...
    
    }



Class 클래스의 일부 중요한 메서드와 용도는 다음과 같습니다:

  • getName(): 클래스의 전체 이름(패키지 포함)을 반환합니다.
  • getSimpleName(): 클래스의 단순 이름(패키지 미포함)을 반환합니다.
  • getFields(): 클래스의 public 필드 배열을 반환합니다.
  • getMethods(): 클래스의 public 메서드 배열을 반환합니다.
  • getConstructors(): 클래스의 public 생성자 배열을 반환합니다.
  • newInstance(): 클래스의 인스턴스를 동적으로 생성합니다.

예를 들어, 다음과 같이 Class<T>를 사용하여 클래스의 메타데이터를 가져올 수 있습니다:

package com.intheeast.javaclass;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class ExampleClass<T> {
    private T value;
    private Integer intObj;

    public ExampleClass(T value) {
        this.value = value;
        intObj = Integer.valueOf(0);
    }
    
    public ExampleClass(Integer intObj) {
        this.intObj = intObj;
    }

    public void printValue() {
        System.out.println(value);
        System.out.println(intObj);

    }
}

public class ExampleClassMain {
	public static void testStringClass() {
		try {
			
            // String 클래스의 Class 객체를 가져옵니다.
            Class<?> stringClass = Class.forName("java.lang.String");

            // 클래스 이름 출력
            System.out.println("Class Name: " + stringClass.getName());

            // public 메서드 나열
            System.out.println("\nPublic Methods:");
            Method[] methods = stringClass.getMethods();
            for (Method method : methods) {
                System.out.println(method.getName());
            }

            // public 필드 나열
            System.out.println("\nPublic Fields:");
            Field[] fields = stringClass.getFields();
            for (Field field : fields) {
                System.out.println(field.getName());
            }

            // public 생성자 나열
            System.out.println("\nPublic Constructors:");
            Constructor<?>[] constructors = stringClass.getConstructors();
            for (Constructor<?> constructor : constructors) {
                System.out.println(constructor.toString());
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
	}
	
	public static void testExampleClass() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Class<ExampleClass> clazz = ExampleClass.class;
		
            // 클래스의 이름과 생성자 정보 출력
            System.out.println(clazz.getName());  // 출력: com.intheeast.javaclass.ExampleClass
            Constructor<ExampleClass> constructorIntrObj = clazz.getConstructor(Integer.class);
            System.out.println(constructorIntrObj);

            // 클래스의 인스턴스 생성 및 메서드 호출
            ExampleClass instance = constructorIntrObj.newInstance(42);
            instance.printValue();  // 출력: 42
	}
	
	public static void testGenericExampleClass() {
		ExampleClass<String> exampleInstance = new ExampleClass<>("Test");
		Class<? extends ExampleClass> instanceClass = exampleInstance.getClass();
		
		try {
		    // 제네릭 생성자를 찾기 위해 Object.class를 사용
		    Constructor<? extends ExampleClass> constructor = instanceClass.getConstructor(Object.class);
		    
		    // 생성자 정보 출력
		    System.out.println("Constructor: " + constructor.toString());

		} catch (NoSuchMethodException e) {
		    e.printStackTrace();
		}
	}
	
    public static void main(String[] args) throws Exception {
    	testStringClass();
    	
        System.out.println();  // 출력: com.intheeast.javaclass.ExampleClass

    	testExampleClass();
    }
}

 
위의 예제에서 Class<ExampleClass> clazz는 ExampleClass 클래스를 참조하는 Class 객체입니다.
getName() 메서드를 사용하여 클래스의 이름을 출력하고, getConstructor() 메서드를 사용하여 ExampleClass의 생성자를 가져옵니다. 이후 newInstance() 메서드를 사용하여 클래스의 인스턴스를 동적으로 생성하고, printValue() 메서드를 호출하여 값을 출력합니다.
따라서 Class는 자바에서 클래스의 메타데이터를 나타내는 데 사용되는 내장 클래스입니다.
 

Constructor 클래스


Java의 Constructor 클래스는 java.lang.reflect 패키지에 포함되어 있으며, 클래스의 생성자에 대한 정보를 나타냅니다. 이 클래스를 사용하면 Java의 Reflection API를 통해 클래스의 생성자에 접근하고, 그 생성자들을 조사하거나 사용할 수 있습니다.

주요 특징과 사용법은 다음과 같습니다:
1. 생성자 정보 가져오기: Constructor 클래스는 특정 클래스의 생성자에 대한 정보를 제공합니다. 예를 들어, Class.getDeclaredConstructors()는 해당 클래스에 정의된 모든 생성자들을 Constructor 객체의 배열로 반환합니다.
2. 생성자 인스턴스 생성: Constructor.newInstance() 메서드를 사용하여 새로운 객체 인스턴스를 동적으로 생성할 수 있습니다. 이 메서드는 생성자의 파라미터에 맞는 인수들을 받아서, 해당 클래스의 새 인스턴스를 생성합니다.
3. 액세스 제어자 관리: setAccessible() 메서드를 사용하여 private 생성자에 접근할 수 있습니다. 이것은 기본적인 접근 제어 규칙을 무시하고, private 생성자에 접근하거나 이를 사용할 수 있게 해줍니다.
4. 생성자 매개변수 정보: getParameters() 메서드를 통해 생성자의 파라미터 정보를 얻을 수 있습니다. 또한 getParameterTypes() 메서드를 사용하여 생성자의 파라미터 유형을 알아낼 수 있습니다.
5. 예외 처리: Constructor 객체를 사용하여 메서드를 호출할 때, IllegalAccessException, InstantiationException, InvocationTargetException 등과 같은 예외가 발생할 수 있습니다. 이는 보안 제한, 인스턴스 생성 불가, 또는 호출된 생성자에서 예외 발생 등의 상황을 나타냅니다.
6. 생성자 수정자 정보: getModifiers() 메서드를 사용하여 생성자의 접근 제어자 정보(예: public, private)를 얻을 수 있습니다.
7. 생성자 이름 및 선언 클래스: getName() 및 getDeclaringClass() 메서드를 사용하여 생성자의 이름과 선언된 클래스 정보를 얻을 수 있습니다.

Constructor 클래스는 주로 프레임워크 개발, 고급 프로그래밍 기법, 또는 Java의 내부 구조를 분석할 때 사용됩니다. 일반적인 애플리케이션 개발에서는 자주 사용되지 않으며, Reflection은 성능상의 이슈와 보안 문제를 야기할 수 있으므로 신중하게 사용해야 합니다.

'Java' 카테고리의 다른 글

Jenerics 1  (0) 2024.04.09
Cloneable 인터페이스  (0) 2024.04.08
Abstract  (0) 2024.04.08
String Class  (0) 2024.04.08
Call by Value / Call by Reference  (0) 2024.04.08