Field

Field 제어

이 문서에서는 Java Reflection을 이용하여 필드를 제어하는 방법에 대해서 살펴본다.

클래스의 형태

예시 클래스의 형태는 다음과 같이 상속 구조로 구성되어 있으며, 다양한 접근제한을 설정해두었다. 필드만 살펴볼 것이므로 다른 내용들은 추가하지 않았다.

Book.java
package com.hacademy.reflection4;

public class Book {
	private String publisher;
	int pages;
	protected String name;
	public String genre;
}
Novel.java
package com.hacademy.reflection4;

import java.util.Date;

public class Novel extends Book{
	private String serial;
	Date publishDate;
	protected int price;
	public String comment;
	@Override
	public String toString() {
		return "Novel [serial=" + serial + ", publishDate=" + publishDate + ", price=" + price + ", comment=" + comment + "]";
	}
}

예제 - 필드 목록 확인

package com.hacademy.reflection4;

import java.lang.reflect.Field;

public class Test01 {
	public static void main(String[] args) throws ClassNotFoundException {
		Class<?> c = Class.forName("com.hacademy.reflection4.Novel");
		
		System.out.println("<Accessible field list>");
		for(Field field : c.getFields()) {
			System.out.println(field);
		}
		
		System.out.println();
		System.out.println("<Declared field list>");
		for(Field field : c.getDeclaredFields()) {
			System.out.println(field);
		}
	}
}

Novel 클래스의 필드를 조회하는 코드이다.

c.getFields()를 통해 Novel 클래스가 접근 가능한 모든 필드의 정보를 조회할 수 있다. 이 중에는 Book 클래스에서 상속받은 항목 중 접근 가능한 genre 변수가 포함된다.

c.getDeclaredFields()를 통해 Novel 클래스에 명시된 모든 필드의 정보를 조회할 수 있다. Novel 클래스의 필드만 조회된다.

결과 화면 콘솔
<Accessible field list>
public java.lang.String com.hacademy.reflection4.Novel.comment
public java.lang.String com.hacademy.reflection4.Book.genre

<Declared field list>
private java.lang.String com.hacademy.reflection4.Novel.serial
java.util.Date com.hacademy.reflection4.Novel.publishDate
protected int com.hacademy.reflection4.Novel.price
public java.lang.String com.hacademy.reflection4.Novel.comment

예제 - 이름을 지정하여 필드 조회

package com.hacademy.reflection4;

import java.lang.reflect.Field;

public class Test02 {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException {
		Class<?> c = Class.forName("com.hacademy.reflection4.Novel");
		
		Field f1 = c.getField("genre");
		System.out.println(f1);
		
//		Field f2 = c.getField("serial");//NoSuchFieldException 발생
//		System.out.println(f2);
		
//		Field f3 = c.getDeclaredField("genre");//NoSuchFieldException 발생
//		System.out.println(f3);
		
		Field f4 = c.getDeclaredField("serial");
		System.out.println(f4);
	}
}

이름을 통해 필드에 접근하고 싶다면 c.getField() 또는 c.getDeclaredField() 메소드를 호출한다.

c.getField()는 상속된 필드를 포함하여 접근 가능한 필드를 이름으로 조회할 수 있으며, 접근이 불가능하거나 존재하지 않는 필드명인 경우 NoSuchFieldException이 발생한다.

c.getDeclaredField()는 상속을 제외한 현재 클래스에 명시된 모든 필드 중 지정한 이름의 필드를 조회할 수 있으며, 존재하지 않는 필드명일 경우 NoSuchFieldException이 발생한다.

예제 - 객체 필드 설정

package com.hacademy.reflection4;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;

public class Test03 {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException{
		Class<?> c = Class.forName("com.hacademy.reflection4.Novel");
		
		Novel novel = new Novel();
		
		Field serial = c.getDeclaredField("serial");
		serial.setAccessible(true);
		serial.set(novel, "TEST-SERIAL");
		
		Field publishDate = c.getDeclaredField("publishDate");
		publishDate.set(novel, new Date());
		
		Field price = c.getDeclaredField("price");
		price.set(novel, 5000);
		
		Field comment = c.getDeclaredField("comment");
		comment.set(novel, "테스트용 서적 정보");
		
		System.out.println(novel);
	}
}

위 코드는 객체를 생성한 뒤 Java Reflection을 사용하여 setter 없이 데이터를 설정하는 코드이다. private 항목까지 설정할 수 있어 기본 접근제한이 적용되지 않는다. 다만, 현재 코드 위치에서 접근이 불가능한 항목인 경우 field.setAccessible(true);를 통해 접근이 가능하도록 설정해야 필드의 항목을 설정할 수 있다.

코드 중 serial 필드는 private 접근제이므로 접근 허용 설정을 추가하였다.

Field serial = c.getDeclaredField("serial");
serial.setAccessible(true);
serial.set(novel, "TEST-SERIAL");

반대로 데이터를 추출하고 싶은 경우에는 field.get() 을 이용한다.

Last updated