https://sundaland.tistory.com/302
[ ▶ Arrays and Enumerated Types ]
배열은 컴포넌트 타입과 길이를 가지고 있으며, 길이는 타입의 일부가 아니다. 배열은 전체적으로 또는 컴포넌트별로 조작할 수 있다. 리플렉션은 후자의 목적을 위해 java.lang.reflect.Array 클래스를 제공한다.
[ ▶ 배열(Arrays) ]
배열은 컴포넌트 타입과 길이를 가지고 있으며, 길이는 타입의 일부가 아니다. 배열은 전체적으로 또는 컴포넌트 별로 조작할 수 있다. 리플렉션은 후자의 목적을 위해 java.lang.reflect.Array 클래스를 제공한다.
- 배열 타입 식별 (Identifying Array Types) : 클래스 멤버가 배열 타입의 필드인지 여부를 확인하는 방법을 설명한다.
- 새로운 배열 생성 (Creating New Arrays) :단순(primitive) 및 복합(자바 클래스) 컴포넌트 타입으로 배열 인스턴스를 새로 생성하는 방법을 보여준다.
- 배열 및 배열 컴포넌트 접근 (Getting and Setting Arrays and Their Components) : 배열 타입 필드에 접근하고 개별 배열 엘리먼트를 접근하는 방법을 설명한다.
- 문제 해결(Troubleshooting) : 일반적인 오류와 프로그래밍 오해를 다룬다.
[ ▷ 열거형 (Enumerated Types) ]
- 열거형 검사 (Examining Enums): 열거형의 상수와 기타 필드, 생성자, 메서드를 가져오는 방법을 설명한다.
- 열거형 타입 필드 접근 및 설정 (Getting and Setting Fields with Enum Types) : 열거형 상수 값으로 필드를 설정하고 가져오는 방법을 보여준다.
- 문제 해결(Troubleshooting) : 열거형과 관련된 일반적인 오류를 설명한다.
[ ▷ Arrays ]
배열은 동일한 타입의 고정된 수의 컴포넌트를 포함하는 참조 타입의 객체이다. 배열의 사이즈는 불변이다. 배열 인스턴스를 생성하려면 사이즈 와 컴포넌트 타입에 대한 정보가 필요하다.각 컴포넌트는 기본 타입, 참조 타입, 배열일 수 있다.
다차원 배열은 사실 배열 타입의 컴포넌트를 포함하는 배열에 불과하다.
배열은 자바 가상 머신에서 구현된다. 배열에서 사용할 수 있는 메서드는 Object 클래스로부터 상속된 메서드뿐이다. 배열의 사이즈는 그 타입의 일부가 아니며 배열은 java.lang.reflect.Array.getLength()를 통해 접근할 수 있는 사이즈 필드를 가지고 있다.
리플렉션은 배열 타입 및 배열 컴포넌트 타입에 접근하고, 새로운 배열을 생성하며, 배열 컴포넌트 값을 가져오고 설정하는 메서드를 제공한다.
- 배열 타입 식별 (Identifying Array Types) : 클래스 멤버가 배열 타입의 필드인지 여부를 확인하는 방법을 설명한다.
- 새로운 배열 생성 (Creating New Arrays) : 단순 및 복합 컴포넌트 타입으로 배열 인스턴스를 새로 생성하는 방법을 보여준다.
- 배열 및 배열 컴포넌트 접근 (Getting and Setting Arrays and Their Components) : 배열 타입 필드에 접근하고 개별 배열 엘리먼트를 접근하는 방법을 설명한다.
- 문제 해결(Troubleshooting):일반적인 오류와 프로그래밍 오해를 다룬다.
이 모든 작업은 java.lang.reflect.Array의 정적 메서드를 통해 지원된다.
[ ▷ Identifying Array Types ]
배열 타입은 Class.isArray()를 호출하여 식별할 수 있다.
▼ 지정된 클래스에서 배열 타입의 필드를 식별하고, 각각의 구성 요소 타입을 보고한다.
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import static java.lang.System.out;
public class ArrayFind {
public static void main(String... args) {
boolean found = false;
try {
Class<?> cls = Class.forName(args[0]);
Field[] flds = cls.getDeclaredFields();
for (Field f : flds) {
Class<?> c = f.getType();
if (c.isArray()) {
found = true;
out.format("%s%n"
+ " Field: %s%n"
+ " Type: %s%n"
+ " Component Type: %s%n",
f, f.getName(), c, c.getComponentType());
}
}
if (!found) {
out.format("No array fields%n");
}
// 실제 코드에서는 이 예외를 더 우아하게 처리해야 합니다.
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
}
Class.get*Type()의 리턴 값에 대한 문법은 Class.getName()에서 설명되어 있다. 타입 이름의 시작 부분에 있는 '[' 문자의 수는 배열의 차원 수 (중첩 깊이)를 나타낸다.
▼ 기본 타입이 byte인 배열
$ java ArrayFind java.nio.ByteBuffer
final byte[] java.nio.ByteBuffer.hb
Field: hb
Type: class [B
Component Type: byte
▼ 참조 타입 StackTraceElement의 배
$ java ArrayFind java.lang.Throwable
private java.lang.StackTraceElement[] java.lang.Throwable.stackTrace
Field: stackTrace
Type: class [Ljava.lang.StackTraceElement;
Component Type: class java.lang.StackTraceElement
predefined는 참조 타입 java.awt.Cursor의 1차원 배열이고, cursorProperties는 참조 타입 String의 2차원 배열이다.
$ java ArrayFind java.awt.Cursor
protected static java.awt.Cursor[] java.awt.Cursor.predefined
Field: predefined
Type: class [Ljava.awt.Cursor;
Component Type: class java.awt.Cursor
static final java.lang.String[][] java.awt.Cursor.cursorProperties
Field: cursorProperties
Type: class [[Ljava.lang.String;
Component Type: class [Ljava.lang.String;
[ ▷ Creating New Arrays ]
non-reflective 코드와 마찬가지로, 리플렉션을 통해 java.lang.reflect.Array.newInstance()를 사용하여 임의의 타입과 차원의 배열을 동적으로 생성할 수 있다.
fully_qualified_class_name variable_name[] =
{ val1, val2, val3, ... }
여기서 fully_qualified_class_name는 단일 문자열 아규먼트를 가진 생성자가 있는 클래스를 나타낸다고 가정한다. 배열의 차원은 제공된 값의 수에 따라 결정된다.
▼ 동적으로 배열을 생성할 수 있는 기본 인터프리
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.Arrays;
import static java.lang.System.out;
public class ArrayCreator {
private static String s = "java.math.BigInteger bi[] = { 123, 234, 345 }";
private static Pattern p = Pattern.compile("^\\s*(\\S+)\\s*\\w+\\[\\].*\\{\\s*([^}]+)\\s*\\}");
public static void main(String... args) {
Matcher m = p.matcher(s);
if (m.find()) {
String cName = m.group(1);
String[] cVals = m.group(2).split("[\\s,]+");
int n = cVals.length;
try {
Class<?> c = Class.forName(cName);
Object o = Array.newInstance(c, n);
for (int i = 0; i < n; i++) {
String v = cVals[i];
Constructor ctor = c.getConstructor(String.class);
Object val = ctor.newInstance(v);
Array.set(o, i, val);
}
Object[] oo = (Object[])o;
out.format("%s[] = %s%n", cName, Arrays.toString(oo));
// 실제 코드에서는 이 예외를 더 우아하게 처리해야 합니다.
} catch (ClassNotFoundException x) {
x.printStackTrace();
} catch (NoSuchMethodException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
} catch (InstantiationException x) {
x.printStackTrace();
} catch (InvocationTargetException x) {
x.printStackTrace();
}
}
}
}
$ java ArrayCreator
java.math.BigInteger [] = [123, 234, 345]
리플렉션을 통해 배열을 생성하는 것이 바람직할 수 있는 한 가지 경우를 보여준다. 컴포넌트 타입이 런타임까지 알려지지 않은 경우이다. 이 경우 코드는 Class.forName()을 사용하여 원하는 컴포넌트 타입의 클래스를 얻은 다음, 특정 생성자를 호출하여 배열의 각 컴포넌트를 초기화한 후 해당 배열 값을 설정한다.
[ ▷ Getting and Setting Arrays and Their Components ]
non-reflective 코드와 마찬가지로, 배열 필드는 전체 또는 구성 요소별로 설정하거나 가져올 수 있다. 배열을 한 번에 설정하려면 java.lang.reflect.Field.set(Object obj, Object value)를 사용한다. 전체 배열을 가져오려면 Field.get(Object)를 사용한다. 개별 구성 요소는 java.lang.reflect.Array의 메서드를 사용하여 설정하거나 가져올 수 있다. Array 클래스는 모든 기본 타입의 컴포넌트를 설정하고 가져오기 위한 setFoo(), getFoo() 형식의 메서드를 제공한다.
예를 들어 int 배열의 구성 요소는 Array.setInt(Object array, int index, int value)를 사용하여 설정할 수 있으며, Array.getInt(Object array, int index)를 사용하여 가져올 수 있다.
이 메서드들은 데이터 타입의 자동 확장을 지원한다. 따라서 Array.getShort()를 사용하여 int 배열의 값을 설정할 수 있으며 16비트 short가 32비트 int로 확장되며 데이터 손실 없이 저장될 수 있다. 반면에 Array.setLong()을 int 배열에 호출하면, 64비트 long을 32비트 int로 축소할 수 없기 때문에 IllegalArgumentException이 발생한다. 이 규칙은 전달된 실제 값이 대상 데이터 타입에 정확히 표현될 수 있는지 여부와 관계없지 적용된다. 자바 언어 명세서 (Java Language Specification), Java SE 7 Edition의 "Widening Primitive Conversion" 및 "Narrowing Primitive Conversion" 섹션에는 확장 및 축소 변환에 대한 완전한 논의가 포함되어 있다.
참조 타입 (배열의 배열 포함)의 배열 구성 요소는 Array.set(Object array, int index, int value) 및 Array.get(Object array, int index)를 사용하여 설장하고 가져온다.
[ ▷ Setting a Field of Type Array ]
▼ 배열 타입의 필드 값을 교체하는 방법 (코드가 java.io.BufferedReader의 백업 배열을 더 큰 배열로 교체한다)
import java.io.BufferedReader;
import java.io.CharArrayReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import static java.lang.System.out;
public class GrowBufferedReader {
private static final int srcBufSize = 10 * 1024;
private static char[] src = new char[srcBufSize];
static {
src[srcBufSize - 1] = 'x';
}
private static CharArrayReader car = new CharArrayReader(src);
public static void main(String... args) {
try {
BufferedReader br = new BufferedReader(car);
Class<?> c = br.getClass();
Field f = c.getDeclaredField("cb");
// cb는 private 필드입니다.
f.setAccessible(true);
char[] cbVal = char[].class.cast(f.get(br));
char[] newVal = Arrays.copyOf(cbVal, cbVal.length * 2);
if (args.length > 0 && args[0].equals("grow"))
f.set(br, newVal);
for (int i = 0; i < srcBufSize; i++)
br.read();
// 새로운 백업 배열이 사용되고 있는지 확인합니다.
if (newVal[srcBufSize - 1] == src[srcBufSize - 1])
out.format("Using new backing array, size=%d%n", newVal.length);
else
out.format("Using original backing array, size=%d%n", cbVal.length);
// 실제 코드에서는 이 예외를 더 우아하게 처리해야 합니다.
} catch (FileNotFoundException x) {
x.printStackTrace();
} catch (NoSuchFieldException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
} catch (IOException x) {
x.printStackTrace();
}
}
}
$ java GrowBufferedReader grow
Using new backing array, size=16384
$ java GrowBufferedReader
Using original backing array, size=8192
java.util.Arrays.copyOf()를 사용한다.
java.util.Arrays에는 배열 작업 시 유용한 많은 메서드가 포함되어 있다.
자바 9에서 java.io가 모듈화되면서 private에 접근할 수 없게 되었다. 대부분의 코드가 동작하지 않는다.
[ ▷ Accessing Elements of a Multidimensional Array ]
다차원 배열은 단순히 중첩된 배열이다. 2차원 배열은 배열의 배열이며, 3차원 배열은 2차원 배열의 배열이다.
▼ 리플렉션을 사용하여 다차원 배열을 생성하고 초기화하는 방법
import java.lang.reflect.Array;
import static java.lang.System.out;
public class CreateMatrix {
public static void main(String... args) {
Object matrix = Array.newInstance(int.class, 2, 2);
Object row0 = Array.get(matrix, 0);
Object row1 = Array.get(matrix, 1);
Array.setInt(row0, 0, 1);
Array.setInt(row0, 1, 2);
Array.setInt(row1, 0, 3);
Array.setInt(row1, 1, 4);
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
out.format("matrix[%d][%d] = %d%n", i, j, ((int[][])matrix)[i][j]);
}
}
$ java CreateMatrix
matrix[0][0] = 1
matrix[0][1] = 2
matrix[1][0] = 3
matrix[1][1] = 4
동일한 결과는 아래의 코드 조각을 사용하여 얻을 수 있다.
Object matrix = Array.newInstance(int.class, 2);
Object row0 = Array.newInstance(int.class, 2);
Object row1 = Array.newInstance(int.class, 2);
Array.setInt(row0, 0, 1);
Array.setInt(row0, 1, 2);
Array.setInt(row1, 0, 3);
Array.setInt(row1, 1, 4);
Array.set(matrix, 0, row0);
Array.set(matrix, 1, row1);
가변 아큐먼트 Array.newInstance(Class<?> componentType, int... dimensions)는 다차원 배열을 생성하는 편리한 방법을 제공하지만, 다차원 배열은 여전히 중첩 배열이라는 원칙에 따라 컴포넌트를 초기화해야 한다. (리플렉션은 이 목적을 위한 다중 인덱스 get/set 메서드를 제공하지 않는다.)
[ ▶ Enumerated Types ]
enum은 고정된 이름 값을 사용할 때 타입 안전한 열거를 정의하기 위해 사용되는 언어 구조이다. 모든 enum은 암묵적으로 java.lang.Enum을 상속한다. enum은 하나 이상의 enum 상수를 포함할 수 있으며, 이는 해당 enu, 타입의 고유한 인스턴스를 정의한다. enum 선언은 필드, 메서드, 생성자 (일부 제한 사항이 있다)와 같은 멤버를 가질 수 있다는 점에서 클래스와 매우 유사한 enum 타입을 정의한다.
enum은 클래스이므로, 리플렉에서 명시적인 java.lang.reflect.Enum 클래스를 정의할 필요가 없다. enum에 특정한 리플렉션 API는 Class.isEnum(), Class.getEnumConstants(), 및 java.lang.reflect.Field.isEnumConstant()뿐이다. enum과 관련된 대부분의 리플렉션 작업은 다른 클래스나 멤버와 동일하다. 예를 들어, enum 상수는 enum에서 public static final 필드로 구현된다.
- 열거형 검사 (Examining Enums) : enum의 상수 및 기타 필드, 생성자, 메서드를 가져오는 방법을 설명한다.
- 열거형 타입 필드 접근 및 설정하기(Getting and Setting Fields with Enum Types) : enum 상수 값을 사용하여 필드를 설정하고 가져오는 방법을 보여준다.
- 문제 해결(Troubleshooting) : enum과 관련된 일반적은 오류를 설명한다.
[ ▷ Examining Enums ]
- Clsss.isEum() : 이 클래스가 enum 타입을 나타내는지 여부를 나타낸다.
- Class.getEnumConstants() : enum에 정의된 상수 목록을 선언된 순서대로 가져온다.
- java.lang.reflect.Field.isEnumConstant() : 이 필드가 열거형 타입의 요소를 나타내는지 여부를 나타낸다.
때때로 enum 상수 목록을 동적으로 가져와야 할 때가 있다. non-reflective 코드에서 enum의 암묵적으로 선언된 정적 메서드인 values()를 호출하여 이를 수행한다. 그러나 enum 타입의 인스턴스가 없는 경우 가능한 값 목록을 얻는 유일한 방법은 Class.getEnumConstants()를 호출하는 것이다. 이는 enum 타입을 인스턴스화 하는 것이 불가능하기 때문이다.
▼ 지정된 이름이 주어졌을 때 Class.getEnumConstants()를 사용하여 enum에서 상수를 순서대로 가져오는 방법
import java.util.Arrays;
import static java.lang.System.out;
enum Eon { HADEAN, ARCHAEAN, PROTEROZOIC, PHANEROZOIC }
public class EnumConstants {
public static void main(String... args) {
try {
Class<?> c = (args.length == 0 ? Eon.class : Class.forName(args[0]));
out.format("Enum name: %s%nEnum constants: %s%n",
c.getName(), Arrays.asList(c.getEnumConstants()));
if (c == Eon.class)
out.format(" Eon.values(): %s%n",
Arrays.asList(Eon.values()));
// 실제 코드에서는 이 예외를 더 우아하게 처리해야 합니다.
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
}
$ java EnumConstants java.lang.annotation.RetentionPolicy
Enum name: java.lang.annotation.RetentionPolicy
Enum constants: [SOURCE, CLASS, RUNTIME]
$ java EnumConstants java.util.concurrent.TimeUnit
Enum name: java.util.concurrent.TimeUnit
Enum constants: [NANOSECONDS, MICROSECONDS,
MILLISECONDS, SECONDS,
MINUTES, HOURS, DAYS]
Class.getEnumConstants()가 리턴하는 값이 enum 타입에서 values()를 호출하여 리턴된 값과 동일하다는 것도 보여준다.
$ java EnumConstants
Enum name: Eon
Enum constants: [HADEAN, ARCHAEAN,
PROTEROZOIC, PHANEROZOIC]
Eon.values(): [HADEAN, ARCHAEAN,
PROTEROZOIC, PHANEROZOIC]
아래의 예제는 Class.isEnum()을 사용하여 검사할 클래스 집합을 제한합니다. 또한, Field.isEnumConstant()을 사용하여 enum 선언에서 다른 필드와 구별되는 enum 상수를 식별한다. (모든 필드가 enum 상수는 아니).
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Member;
import java.util.List;
import java.util.ArrayList;
import static java.lang.System.out;
public class EnumSpy {
private static final String fmt = " %11s: %s %s%n";
public static void main(String... args) {
try {
Class<?> c = Class.forName(args[0]);
if (!c.isEnum()) {
out.format("%s is not an enum type%n", c);
return;
}
out.format("Class: %s%n", c);
Field[] flds = c.getDeclaredFields();
List<Field> cst = new ArrayList<Field>(); // enum constants
List<Field> mbr = new ArrayList<Field>(); // member fields
for (Field f : flds) {
if (f.isEnumConstant())
cst.add(f);
else
mbr.add(f);
}
if (!cst.isEmpty())
print(cst, "Constant");
if (!mbr.isEmpty())
print(mbr, "Field");
Constructor[] ctors = c.getDeclaredConstructors();
for (Constructor ctor : ctors) {
out.format(fmt, "Constructor", ctor.toGenericString(),
synthetic(ctor));
}
Method[] mths = c.getDeclaredMethods();
for (Method m : mths) {
out.format(fmt, "Method", m.toGenericString(),
synthetic(m));
}
// 실제 코드에서는 이 예외를 더 우아하게 처리해야 합니다.
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
private static void print(List<Field> lst, String s) {
for (Field f : lst) {
out.format(fmt, s, f.toGenericString(), synthetic(f));
}
}
private static String synthetic(Member m) {
return (m.isSynthetic() ? "[ synthetic ]" : "");
}
}
$ java EnumSpy java.lang.annotation.RetentionPolicy
Class: class java.lang.annotation.RetentionPolicy
Constant: public static final java.lang.annotation.RetentionPolicy
java.lang.annotation.RetentionPolicy.SOURCE
Constant: public static final java.lang.annotation.RetentionPolicy
java.lang.annotation.RetentionPolicy.CLASS
Constant: public static final java.lang.annotation.RetentionPolicy
java.lang.annotation.RetentionPolicy.RUNTIME
Field: private static final java.lang.annotation.RetentionPolicy[]
java.lang.annotation.RetentionPolicy. [ synthetic ]
Constructor: private java.lang.annotation.RetentionPolicy()
Method: public static java.lang.annotation.RetentionPolicy[]
java.lang.annotation.RetentionPolicy.values()
Method: public static java.lang.annotation.RetentionPolicy
java.lang.annotation.RetentionPolicy.valueOf(java.lang.String)
출력은 java.lang.annotation.RetentionPolicy 선언에 세 가지 enum 상수만 포함되어 있음을 보여준다. enum 상수는 public static final 필드로 노출된다. 필드, 생성자, 메서드는 컴파일러에 의해 생성된다. $VALUES 필드는 values() 메서드의 구현과 관련이 있다.
enum 타입의 발전을 지원하는 등의 다양한 이유로 enum 상수의 선언 순서는 중요하다. Class.getFields()와 Class.getDeclaredFields()는 반환된 값의 순서가 선언된 소스 코드의 순서와 일치한다는 보장을 하지 않는다. 애플리케이션에서 순서가 필요할 경우 Class.getEnumConstants()를 사용한다.
java.util.concurrent.TimeUnit에 대한 출력은 훨씩 더 복잡한 enum이 가능하는 것을 보여준다. 이 클래스에는 몇 가지 메서드와 함께 enum 상수가 아닌 static final로 선언된 추가 필드가 포함되어 있다.
$ java EnumSpy java.util.concurrent.TimeUnit
Class: class java.util.concurrent.TimeUnit
Constant: public static final java.util.concurrent.TimeUnit
java.util.concurrent.TimeUnit.NANOSECONDS
Constant: public static final java.util.concurrent.TimeUnit
java.util.concurrent.TimeUnit.MICROSECONDS
Constant: public static final java.util.concurrent.TimeUnit
java.util.concurrent.TimeUnit.MILLISECONDS
Constant: public static final java.util.concurrent.TimeUnit
java.util.concurrent.TimeUnit.SECONDS
Constant: public static final java.util.concurrent.TimeUnit
java.util.concurrent.TimeUnit.MINUTES
Constant: public static final java.util.concurrent.TimeUnit
java.util.concurrent.TimeUnit.HOURS
Constant: public static final java.util.concurrent.TimeUnit
java.util.concurrent.TimeUnit.DAYS
Field: static final long java.util.concurrent.TimeUnit.C0
Field: static final long java.util.concurrent.TimeUnit.C1
Field: static final long java.util.concurrent.TimeUnit.C2
Field: static final long java.util.concurrent.TimeUnit.C3
Field: static final long java.util.concurrent.TimeUnit.C4
Field: static final long java.util.concurrent.TimeUnit.C5
Field: static final long java.util.concurrent.TimeUnit.C6
Field: static final long java.util.concurrent.TimeUnit.MAX
Field: private static final java.util.concurrent.TimeUnit[]
java.util.concurrent.TimeUnit. [ synthetic ]
Constructor: private java.util.concurrent.TimeUnit()
Constructor: java.util.concurrent.TimeUnit
(java.lang.String,int,java.util.concurrent.TimeUnit)
[ synthetic ]
Method: public static java.util.concurrent.TimeUnit
java.util.concurrent.TimeUnit.valueOf(java.lang.String)
Method: public static java.util.concurrent
[ ▷ Getting and Setting Fields with Enum Types ]
enum을 저장하는 필드는 Field.set() 및 Field.get()을 사용하여 다른 참조 타입과 동일하게 설정하고 가져올 수 있다.
▼ enum 문자열 포현을 enum 타입으로 변환하고, enum을 저장하는 필드의 값을 가져와 설정하는 방
import java.lang.reflect.Field;
import static java.lang.System.out;
enum TraceLevel { OFF, LOW, MEDIUM, HIGH, DEBUG }
class MyServer {
private TraceLevel level = TraceLevel.OFF;
}
public class SetTrace {
public static void main(String... args) {
TraceLevel newLevel = TraceLevel.valueOf(args[0]);
try {
MyServer svr = new MyServer();
Class<?> c = svr.getClass();
Field f = c.getDeclaredField("level");
f.setAccessible(true);
TraceLevel oldLevel = (TraceLevel)f.get(svr);
out.format("Original trace level: %s%n", oldLevel);
if (oldLevel != newLevel) {
f.set(svr, newLevel);
out.format(" New trace level: %s%n", f.get(svr));
}
// 실제 코드에서는 이 예외를 더 우아하게 처리해야 합니다.
} catch (IllegalArgumentException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
} catch (NoSuchFieldException x) {
x.printStackTrace();
}
}
}
$ java SetTrace OFF
Original trace level: OFF
$ java SetTrace DEBUG
Original trace level: OFF
New trace level: DEBUG
enum 상수는 싱글톤이므로 == 및 != 연산자를 사용하여 동일한 타입의 enum 상수를 비교할 수 있다.
'Reflection' 카테고리의 다른 글
Java Dynamic Proxy Classes (0) | 2024.08.21 |
---|---|
unqualified name (0) | 2024.08.20 |
sealed interface (0) | 2024.08.20 |
type-safe proxy object (0) | 2024.08.20 |
Structuring method calls (0) | 2024.08.20 |