본문 바로가기
JAVA

[JAVA] CLASS 클래스

by oncerun 2020. 4. 23.
반응형

Class 클래스

클래스와 인터페이스의 메타 데이터를 얻을 수 있습니다. (reflection)

*메타데이터 : 클래스의 이름, 생성자 정보, 필드 정보, 메서드 정보
정보란 멤버 변수, 메서드, 인터페이스, 생성자 을 말하며 객체를 생성하거나 변수를 변경할 수 있고 메서드를 호출할 수도 있습니다.
Class clazz = obj.getClass();

 

Reflection은 객체를 통해 클래스의 정보를 분석해내는 프로그램 기법입니다.

정보란 멤버 변수, 메서드, 인터페이스, 생성자 을 말하며 객체를 생성하거나 변수를 변경할 수 있고 메서드를 호출할 수도 있습니다.

 

Reflection은 객체를 통해 클래스의 정보를 분석해내는 프로그램 기법입니다.

정보란 멤버 변수, 메서드, 인터페이스, 생성자 을 말하며 객체를 생성하거나 변수를 변경할 수 있고 메서드를 호출할 수도 있습니다.

우선적으로 reflection을 사용하기 앞서
import java.lang.reflect.*; 를 임포트 해줍니다.

첫 번째로 Class 클래스입니다.
java.lang.Class이며 lang패키지 안에 존재하므로 import 하지 않고 사용할 수 있습니다.
Class 클래스는 자바에서 사용되는 클래스들에 대한 구조를 가지고 있는 Class입니다.

package blog;

public class A extends B{

	public String str1 = "안녕하세요";
	public int num = 3;
	private String str2 = "안녕하세요";
	public A() {
	}
	private A(int num) {
		this.num = num;
	}
	public A(String str2) {
		this.str2 = str2;
	}

	public void method1() {
		System.out.println("method1");
	}

	public void method2(int a) {
		System.out.println(a);
	}

	private void method3(int a , String b) {
		System.out.println("method3");
		System.out.printf("int %d String %s",a,b);
	}
}


-----------------------------
package blog;

public class B {
	public String a;
	
}


A라는 클래스의 정보를 가져오기 위해 Class를 사용해보겠습니다.

클래스의 이름만을 가지고 클래스 정보를 가져옵니다.

Class cls = Class.forName("blog.A");
//forName()는 패키지를포함한 경로를 설정해줍니다.
Class cls2 = A.class;
//클래스명.class로 클래스정보를 가져올 수도 있습니다.

 

이제 클래스의 정보 가져왔으니 생성자의 정보를 가져오겠습니다.

인자 없는 생성자를 가져오는 방법입니다.

package blog;
import java.lang.reflect.Constructor;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	
	Constructor cons = cls.getDeclaredConstructor();
	System.out.println(cons);
	}

}

인자가 존재하는 생성자를 가져오기 위해선 getDeclaredConstructor(type)을 사용합니다.

같은 type의 생성자를 리턴합니다

package blog;
import java.lang.reflect.Constructor;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	
	Constructor cons = cls.getDeclaredConstructor(String.class);
	System.out.println(cons);
	}

}
결과 :public blog.A(java.lang.String)

 

다음 코드는 모든 생성자를 가져옵니다. getDeclaredConstructors();

package blog;
import java.lang.reflect.Constructor;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	
	Constructor[] cons = cls.getDeclaredConstructors();
	for(int i = 0; i < cons.length; i ++)
	System.out.println(cons[i]);
	
	}

}
결과 :  public blog.A(java.lang.String)
		private blog.A(int)
		public blog.A()

 

public 생성자만 조회하기위해선 getDeclaredConstructors();

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	
	Constructor[] cons = cls.getConstructors();
	for(int i = 0; i < cons.length; i ++)
	System.out.println(cons[i]);
	
	}

}
결과 : public blog.A(java.lang.String)
	   public blog.A()

 

이제 클래스의 메소드를 가져옵니다.

모든 메소드를 찾으려면, 다음과 같이 getDeclaredMethods를 사용하면 됩니다.

공통적으로 함수 이름에 Declared가 들어가면 Super 클래스의 정보는 가져오지 않습니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	Method[] method = cls.getDeclaredMethods();
	
	for(int i= 0 ; i<method.length; i ++)
		System.out.println(method[i]);
	}

}
결과 public void blog.A.method1()
public void blog.A.method2()
public void blog.A.method3()

 

모든 메서드 말고 찾고자 하는 메서드만을 찾을 수 있습니다. 파라미터 값에 찾고자 하는 메서드 이름과 타입을 매개변수로 넣어줍니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	Method method = cls.getDeclaredMethod("method2",int.class);
	
		System.out.println(method);
	}

}
결과 : public void blog.A.method2(int)

 

만약 인자가 두 개 이상이라면 배열로 인자 값을 넘겨줍니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	Class type[] = {int.class, String.class};
	Method method = cls.getDeclaredMethod("method3",type);
	
		System.out.println(method);
	}

}
결과 : public void blog.A.method3(int,java.lang.String)

 

getMethods()는 public이며  자신의 메서드와 상속받은 메서드 모두를 리턴해줍니다. 

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	Method[] method = cls.getMethods();
	
	for(int i= 0; i < method.length; i ++)
		System.out.println(method[i]);
	}

}

결과 : public void blog.A.method1()
public void blog.A.method2(int)
public void blog.A.method3(int,java.lang.String)
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

 

 

field 멤버변수의 정보를 얻어오겠습니다.

매개변수와 동일한 멤버변수를 찾아줍니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException {
		
	Class cls = Class.forName("blog.A");
	Field field = cls.getDeclaredField("str2");
	System.out.println(field);
	}
}

결과 : private java.lang.String blog.A.str2

 

객체에 선언된 모든 Field를 찾으려면 getFields()를 사용하면 됩니다.

public인 멤버변수와 상속받은 필드까지 가져옵니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException {
		
	Class cls = Class.forName("blog.A");
	Field[] fields = cls.getFields();
	for(Field fi : fields) {
		System.out.println(fi);
	}
	}
}

결과 :public java.lang.String blog.A.str1
public int blog.A.num
public java.lang.String blog.B.a

 

자신 필드에 대한 필드만 가져오기 위해서는 getDeclaredFields()를 사용하면 됩니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException {
		
	Class cls = Class.forName("blog.A");
	Field[] fields = cls.getDeclaredFields();
	for(Field fi : fields) {
		System.out.println(fi);
	}
	}
}
결과 :public java.lang.String blog.A.str1
public int blog.A.num
private java.lang.String blog.A.str2

 

Field 값 수정

 

클래스의 멤버 변수를 가져와서 값을 변경할 수 있습니다.

A클래스에 있는 str1의 멤버 변수의 정보를 가져와 값을 출력하고 변경해보겠습니다.

 

출력

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
	A a = new A();
	Class cls = Class.forName("blog.A");
	Field field = cls.getField("str1");
	System.out.println(field.get(a));
	
	}
}
결과 :안녕하세요

 

변경

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
	A a = new A();
	Class cls = Class.forName("blog.A");
	Field field = cls.getField("str1");
	field.set(a, "감사합니다.");
	System.out.println(field.get(a));
	
	}
}
결과 :감사합니다.

private 변수를 수정하려면  setAccessible(true)로 접근 상태를 변경하면 됩니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
	A a = new A();
	Class cls = Class.forName("blog.A");
	Field field = cls.getDeclaredField("str2");
	field.setAccessible(true);
	field.set(a, "잘먹었습니다.");
	System.out.println(field.get(a));
	
	}
}
결과 :잘먹었습니다.

 

 

 

Method 호출

클래스로부터 메서드 정보를 가져와, 객체의 메서드를 호출할 수 있습니다.

 

메서드 객체를 생성하고 invoke()로 호출합니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
	A a = new A();
	Class cls = Class.forName("blog.A");
	Method method = cls.getDeclaredMethod("method2", int.class);
	int value = (int) method.invoke(a, 30);
	}
}
결과 :30

 

private 메서드를 호출할 때는 setAccessible(true) 설정해주면 됩니다.

 

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
	A a = new A();
	Class cls = Class.forName("blog.A");
	Method method = cls.getDeclaredMethod("method3", int.class,String.class);
	method.setAccessible(true);
	method.invoke(a, 3,"수정하기");
	}
}
결과 : method3
int 3 String 수정하기

 

Class 동적 객체 생성하기

 

 

 

동적으로 클래스의 이름을 받아서 객체를 생성해 메서드를 실행할 수 있습니다.

package blog01;

public interface Action {
	public void execute();
}
-----
package blog01;

public class ReceiveAction implements Action{
@Override
public void execute() {
	System.out.println("데이터를 Receive합니다.");
	
}
}
-----
package blog01;

public class SendAction implements Action{
@Override
public void execute() {
	System.out.println("데이터를 Send합니다.");
	
}
}

 

실행할 프로그램입니다.

package blog01;

public class NewInstance {

	public static void main(String[] args) {

		try {
			Class clazz = Class.forName("blog01.SendAction");
			//매개값이 동적으로 전달이됩니다.
			Action action = (Action) clazz.newInstance();
			action.execute();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}

}

 

Class clazz = Class.forName("동적 클래스");
//매개 값이 동적으로 전달이 됩니다.

하나의 인터페이스를 상속받고 있으므로 Class객체를 생성해 인터페이스 타입으로 형 변환을 합니다.

인터페이스의 인스턴스를 생성한 뒤 오버라이드 된 메서드를 실행하면 자식의 메서드가 실행됩니다.

반응형

'JAVA' 카테고리의 다른 글

Server Networking Proxy  (0) 2021.11.14
메일 발송  (0) 2021.11.06
JavaMail API  (0) 2021.10.24
JAVA 연산자 -3  (0) 2020.02.20
JAVA 연산자 -2  (0) 2020.02.20

댓글