리플렉션이란 무엇이며 왜 유용합니까?
특히 Java에 관심이 있지만 원칙이 모든 언어에서 동일하다고 가정합니다.
@Jailbreak
. 개인 필드, 메소드 등에 대한 직접적이고 안전한 유형의 액세스를 제공 합니다. Java 컴파일러가 코드를 안전하게 확인하고 매니 폴드가 기본 리플렉션 액세스를 생성하도록하십시오. 자세히 알아보기 : manifold.systems/docs.html#type-safe-reflection
리플렉션이란 무엇이며 왜 유용합니까?
특히 Java에 관심이 있지만 원칙이 모든 언어에서 동일하다고 가정합니다.
@Jailbreak
. 개인 필드, 메소드 등에 대한 직접적이고 안전한 유형의 액세스를 제공 합니다. Java 컴파일러가 코드를 안전하게 확인하고 매니 폴드가 기본 리플렉션 액세스를 생성하도록하십시오. 자세히 알아보기 : manifold.systems/docs.html#type-safe-reflection
답변:
이름 반영은 동일한 시스템 (또는 자체)에서 다른 코드를 검사 할 수있는 코드를 설명하는 데 사용됩니다.
예를 들어, Java에 알 수없는 유형의 객체가 있고 'doSomething'메소드가 있으면이를 호출하려고한다고 가정하십시오. Java의 정적 타이핑 시스템은 객체가 알려진 인터페이스를 준수하지 않는 한 실제로 이것을 지원하도록 설계되지 않았지만 리플렉션을 사용하면 코드에서 객체를보고 'doSomething'이라는 메소드가 있는지 확인한 다음 호출하면 호출 할 수 있습니다 고 싶어요.
따라서 Java로 코드 예제를 제공하려면 (문제의 객체가 foo라고 상상하십시오.)
Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);
Java에서 가장 일반적인 사용 사례는 주석을 사용한 사용법입니다. 예를 들어, JUnit 4는 리플렉션을 사용하여 @Test 주석으로 태그가 지정된 메소드를 클래스에서 살펴본 다음 단위 테스트를 실행할 때이를 호출합니다.
http://docs.oracle.com/javase/tutorial/reflect/index.html 에서 시작할 수있는 몇 가지 좋은 예가 있습니다.
마지막으로, 개념은 C #과 같이 리플렉션을 지원하는 다른 정적으로 유형이 지정된 언어와 거의 유사합니다. 동적으로 유형이 지정된 언어에서는 위에서 설명한 유스 케이스가 덜 필요합니다 (컴파일러는 객체에서 메소드를 호출 할 수 있기 때문에 객체가 없을 경우 런타임에 실패 함). 특정 방식으로 작업하는 것은 여전히 흔합니다.
댓글에서 업데이트 :
시스템에서 코드를 검사하고 객체 유형을 볼 수있는 기능은 리플렉션이 아니라 유형 검사입니다. 리플렉션은 런타임에 내부 검사를 사용하여 수정하는 기능입니다. 일부 언어는 내부 검사를 지원하지만 리플렉션은 지원하지 않으므로 구별이 필요합니다. 그러한 예 중 하나는 C ++입니다.
Method
, Constructor
, Modifier
, Field
, Member
, 기본적으로 분명히 외 모두 Class
)에 내에있는 java.lang.*reflect*
패키지. 아마도 "반사"라는 개념에는 "유형 내부 검사"와 런타임시 수정이 모두 포함되어 있습니까?
리플렉션 은 런타임에 클래스, 메소드, 속성 등을 검사하고 동적으로 호출하는 언어의 기능입니다.
예를 들어, Java의 모든 객체에는 메소드가 있습니다.이 메소드 getClass()
를 사용하면 컴파일 타임에 객체를 모르더라도 (예 : 객체를으로 선언 한 경우에도) 객체의 클래스를 확인할 Object
수 있습니다. 와 같이 덜 동적 인 언어로 C++
. 보다 고급으로 사용하면 메소드, 생성자 등을 나열하고 호출 할 수 있습니다.
리플렉션은 컴파일 타임에 모든 것을 "알지"않아도되는 프로그램을 작성할 수있게 해주므로 런타임에 서로 묶을 수 있기 때문에 더욱 역동적으로 만들 수 있기 때문에 중요합니다. 알려진 인터페이스에 대해 코드를 작성할 수 있지만 구성 파일에서 리플렉션을 사용하여 사용할 실제 클래스를 인스턴스화 할 수 있습니다.
많은 현대 프레임 워크가 바로 이런 이유로 반사를 광범위하게 사용합니다. 대부분의 다른 현대 언어도 리플렉션을 사용하며, 스크립트 언어 (예 : Python)에서는 언어의 일반적인 프로그래밍 모델에서보다 자연스럽게 느껴지므로 훨씬 더 밀접하게 통합되어 있습니다.
리플렉션을 가장 좋아하는 용도 중 하나는 아래 Java 덤프 방법입니다. 모든 객체를 매개 변수로 사용하고 Java 리플렉션 API를 사용하여 모든 필드 이름과 값을 인쇄합니다.
import java.lang.reflect.Array;
import java.lang.reflect.Field;
public static String dump(Object o, int callCount) {
callCount++;
StringBuffer tabs = new StringBuffer();
for (int k = 0; k < callCount; k++) {
tabs.append("\t");
}
StringBuffer buffer = new StringBuffer();
Class oClass = o.getClass();
if (oClass.isArray()) {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("[");
for (int i = 0; i < Array.getLength(o); i++) {
if (i < 0)
buffer.append(",");
Object value = Array.get(o, i);
if (value.getClass().isPrimitive() ||
value.getClass() == java.lang.Long.class ||
value.getClass() == java.lang.String.class ||
value.getClass() == java.lang.Integer.class ||
value.getClass() == java.lang.Boolean.class
) {
buffer.append(value);
} else {
buffer.append(dump(value, callCount));
}
}
buffer.append(tabs.toString());
buffer.append("]\n");
} else {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("{\n");
while (oClass != null) {
Field[] fields = oClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
buffer.append(tabs.toString());
fields[i].setAccessible(true);
buffer.append(fields[i].getName());
buffer.append("=");
try {
Object value = fields[i].get(o);
if (value != null) {
if (value.getClass().isPrimitive() ||
value.getClass() == java.lang.Long.class ||
value.getClass() == java.lang.String.class ||
value.getClass() == java.lang.Integer.class ||
value.getClass() == java.lang.Boolean.class
) {
buffer.append(value);
} else {
buffer.append(dump(value, callCount));
}
}
} catch (IllegalAccessException e) {
buffer.append(e.getMessage());
}
buffer.append("\n");
}
oClass = oClass.getSuperclass();
}
buffer.append(tabs.toString());
buffer.append("}\n");
}
return buffer.toString();
}
callCount
은 0으로 설정해야합니다. 이 값은 각 출력 줄 앞에 몇 개의 탭이 있어야하는지 결정하는 데 사용됩니다. 덤프가 "하위 오브젝트"를 덤프해야 할 때마다 출력이 상위에 중첩 된 것으로 인쇄됩니다. 이 방법은 다른 방법으로 감쌀 때 유용합니다. 고려하십시오 printDump(Object obj){ System.out.println(dump(obj, 0)); }
.
반사의 사용
리플렉션은 일반적으로 Java 가상 머신에서 실행되는 애플리케이션의 런타임 동작을 검사하거나 수정해야하는 프로그램에서 사용됩니다. 이것은 비교적 고급 기능이며 언어의 기본 사항을 잘 알고있는 개발자 만 사용해야합니다. 이러한 경고를 염두에두고 리플렉션은 강력한 기술이므로 응용 프로그램에서 불가능한 작업을 수행 할 수 있습니다.
확장 성 기능
응용 프로그램은 정규화 된 이름을 사용하여 확장 성 개체 인스턴스를 만들어 외부 사용자 정의 클래스를 사용할 수 있습니다. 클래스 브라우저 및 비주얼 개발 환경 클래스 브라우저는 클래스 멤버를 열거 할 수 있어야합니다. 시각적 개발 환경에서는 개발자가 올바른 코드를 작성하는 데 도움이되도록 형식 정보를 반영하여 활용할 수 있습니다. 디버거 및 테스트 도구 디버거는 클래스의 개인 멤버를 검사 할 수 있어야합니다. 테스트 하네스는 리플렉션을 사용하여 클래스에 정의 된 검색 가능한 세트 API를 체계적으로 호출하여 테스트 스위트에서 높은 수준의 코드 커버리지를 보장 할 수 있습니다.
반사의 단점
반사는 강력하지만 무차별 적으로 사용해서는 안됩니다. 반사를 사용하지 않고 작업을 수행 할 수 있으면 사용하지 않는 것이 좋습니다. 리플렉션을 통해 코드에 액세스 할 때는 다음 사항을 염두에 두어야합니다.
리플렉션에는 동적으로 분석되는 유형이 포함되므로 특정 Java 가상 머신 최적화를 수행 할 수 없습니다. 결과적으로, 반사 동작은 비 반사에 비해 성능이 느리고 성능에 민감한 응용 프로그램에서 자주 호출되는 코드 섹션에서는 피해야합니다.
Reflection에는 보안 관리자에서 실행할 때 존재하지 않는 런타임 권한이 필요합니다. 이는 애플릿과 같이 제한된 보안 컨텍스트에서 실행되어야하는 코드에있어 중요한 고려 사항입니다.
리플렉션을 사용하면 개인 필드 및 메소드에 액세스하는 것과 같이 비 반사 코드에서 불법적 인 작업을 코드에서 수행 할 수 있으므로 리플렉션을 사용하면 예기치 않은 부작용이 발생하여 코드가 제대로 작동하지 않아 이식성이 떨어질 수 있습니다. 반사 코드는 추상화를 손상 시키므로 플랫폼을 업그레이드하면 동작이 변경 될 수 있습니다.
출처 : Reflection API
리플렉션은 응용 프로그램이나 프레임 워크가 아직 작성되지 않았을 수도있는 코드로 작동 할 수 있도록하는 핵심 메커니즘입니다!
일반적인 web.xml 파일을 예로 들어 보겠습니다. 여기에는 중첩 된 서블릿 클래스 요소가 포함 된 서블릿 요소 목록이 포함됩니다. 서블릿 컨테이너는 web.xml 파일을 처리하고 리플렉션을 통해 각 서블릿 클래스의 새 인스턴스를 새로 만듭니다.
또 다른 예는 JAXP ( Java API for XML Parsing ) 입니다. XML 파서 공급자가 잘 알려진 시스템 속성을 통해 '플러그인'되는 경우 리플렉션을 통해 새 인스턴스를 구성하는 데 사용됩니다.
마지막으로 가장 포괄적 인 예는 리플렉션을 사용하여 Bean을 작성하고 프록시를 많이 사용하는 Spring 입니다.
모든 언어가 리플렉션을 지원하는 것은 아니지만 원칙을 지원하는 언어는 원칙이 동일합니다.
리플렉션은 프로그램 구조를 "반영"하는 능력입니다. 또는 더 구체적인. 가지고있는 객체와 클래스를보고 프로그래밍 방식으로 메소드, 필드 및 인터페이스에 대한 정보를 얻습니다. 주석과 같은 것을 볼 수도 있습니다.
많은 상황에서 유용합니다. 어디서나 코드에 클래스를 동적으로 연결할 수 있기를 원합니다. 많은 객체 관계형 맵퍼는 리플렉션을 사용하여 어떤 객체를 사용할지 미리 알지 않고도 데이터베이스에서 객체를 인스턴스화 할 수 있습니다. 플러그인 아키텍처는 리플렉션이 유용한 또 다른 장소입니다. 동적으로 코드를로드하고 플러그인으로 사용하기에 적합한 인터페이스를 구현하는 유형이 있는지 판별하는 것이 이러한 상황에서 중요합니다.
리플렉션은 구현에 대한 사전 지식없이 런타임에 새로운 객체의 인스턴스화, 메소드 호출 및 클래스 변수에 대한 작업 가져 오기 / 설정을 동적으로 허용합니다.
Class myObjectClass = MyObject.class;
Method[] method = myObjectClass.getMethods();
//Here the method takes a string parameter if there is no param, put null.
Method method = aClass.getMethod("method_name", String.class);
Object returnValue = method.invoke(null, "parameter-value1");
위의 예에서 null 매개 변수는 메서드를 호출하려는 객체입니다. 메소드가 정적이면 널을 제공합니다. 메소드가 정적이 아닌 경우, 호출하는 동안 널 대신 유효한 MyObject 인스턴스를 제공해야합니다.
리플렉션을 사용하면 클래스의 비공개 멤버 / 방법에 액세스 할 수 있습니다.
public class A{
private String str= null;
public A(String str) {
this.str= str;
}
}
.
A obj= new A("Some value");
Field privateStringField = A.class.getDeclaredField("privateString");
//Turn off access check for this field
privateStringField.setAccessible(true);
String fieldValue = (String) privateStringField.get(obj);
System.out.println("fieldValue = " + fieldValue);
java.lang.reflect
) 를 가져올 필요가 없습니다 . 를 통해 클래스 메타 데이터에 액세스 할 수 있습니다 java.lang.Class
.리플렉션은 매우 강력한 API이지만 런타임에 모든 유형을 확인하므로 초과 사용하면 응용 프로그램 속도가 느려질 수 있습니다.
Java Reflection은 매우 강력하며 매우 유용 할 수 있습니다. Java Reflection을 사용하면 컴파일 타임에 클래스, 메소드 등의 이름을 몰라도 런타임에 클래스, 인터페이스, 필드 및 메소드를 검사 할 수 있습니다. 리플렉션을 사용하여 새 객체 를 인스턴스화하고, 메소드를 호출하고, 필드 값을 가져 오거나 설정할 수도 있습니다.
리플렉션 사용의 모습을 보여주는 빠른 Java 리플렉션 예제 :
Method[] methods = MyObject.class.getMethods();
for(Method method : methods){
System.out.println("method = " + method.getName());
}
이 예제는 MyObject라는 클래스에서 Class 객체를 가져옵니다. 예제는 클래스 객체를 사용하여 해당 클래스의 메소드 목록을 가져 와서 메소드를 반복하고 이름을 인쇄합니다.
이 모든 것이 어떻게 작동하는지 정확히 여기에 설명되어 있습니다.
편집 : 거의 1 년 후 리플렉션을 읽는 동안 리플렉션을 더 많이 사용하지 않으므로이 답변을 편집하고 있습니다.
<bean id="someID" class="com.example.Foo">
<property name="someField" value="someValue" />
</bean>
Spring 컨텍스트가이 <bean> 요소를 처리 할 때 "com.example.Foo"인수와 함께 Class.forName (String)을 사용하여 해당 클래스를 인스턴스화합니다.
그런 다음 다시 반사를 사용하여 <property> 요소에 대한 적절한 설정자를 가져오고 해당 값을 지정된 값으로 설정합니다.
개인 메소드의 경우
Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);
개인 필드의 경우
Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
예:
예를 들어 API 메소드를 사용하여 얻은 객체를 애플리케이션에 제공하는 원격 애플리케이션을 예로 들어 보겠습니다. 이제 객체를 기반으로 일종의 계산을 수행해야 할 수도 있습니다.
공급자는 객체가 3 가지 유형일 수 있으며 어떤 유형의 객체를 기반으로 계산을 수행해야하는지 보장합니다.
따라서 각각 다른 로직을 포함하는 3 개의 클래스로 구현할 수 있습니다. 물론 런타임에 객체 정보를 사용할 수 있으므로 정적으로 코드를 작성하여 계산을 수행 할 수 없으므로 리플렉션을 사용하여 계산을 수행하는 데 필요한 클래스의 객체를 인스턴스화 할 수 있습니다. 공급자로부터받은 개체입니다.
instanceof
런타임에 객체 유형을 결정 하는 데 사용할 수 없습니까?
반사에 대한 간단한 예. 체스 게임에서는 런타임에 사용자가 무엇을 움직 일지 알 수 없습니다. 리플렉션은 런타임에 이미 구현 된 메소드를 호출하는 데 사용할 수 있습니다.
public class Test {
public void firstMoveChoice(){
System.out.println("First Move");
}
public void secondMOveChoice(){
System.out.println("Second Move");
}
public void thirdMoveChoice(){
System.out.println("Third Move");
}
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Test test = new Test();
Method[] method = test.getClass().getMethods();
//firstMoveChoice
method[0].invoke(test, null);
//secondMoveChoice
method[1].invoke(test, null);
//thirdMoveChoice
method[2].invoke(test, null);
}
}
리플렉션 은 런타임 에 메서드, 클래스, 인터페이스 의 동작을 검사하거나 수정하는 데 사용되는 API입니다 .
java.lang.reflect package
.java.lang
및 java.lang.reflect
패키지는 자바 반사하기위한 클래스를 제공합니다.
리플렉션 을 사용하여 다음에 대한 정보를 얻을 수 있습니다.
클래스 의 getClass()
방법은 객체가 속한 클래스의 이름을 가져 오는 데 사용됩니다.
생성자getConstructors()
방법은 객체가 속한 클래스의 public 생성자를 가져 오는 데 사용됩니다.
방법getMethods()
방법은 객체가 속한 클래스의 public 메소드를 가져 오는 데 사용됩니다.
반사 API는 주로 사용된다 :
IDE (Integrated Development Environment) (예 : Eclipse, MyEclipse, NetBeans 등)
디버거 및 테스트 도구 등
리플렉션 사용의 장점 :
확장 성 기능 : 응용 프로그램은 정규화 된 이름을 사용하여 확장 성 개체 인스턴스를 만들어 외부 사용자 정의 클래스를 사용할 수 있습니다.
디버깅 및 테스트 도구 : 디버거는 리플렉션 속성을 사용하여 클래스의 개인 멤버를 검사합니다.
단점 :
성능 오버 헤드 : 반사 작업은 비 반사 작업보다 성능이 느리므로 성능에 민감한 응용 프로그램에서 자주 호출되는 코드 섹션에서는 피해야합니다.
내부 노출 : 반사 코드는 추상화를 손상 시키므로 플랫폼 업그레이드에 따라 동작이 변경 될 수 있습니다.
내 이해에 따라 :
리플렉션을 사용하면 프로그래머가 프로그램의 엔터티에 동적으로 액세스 할 수 있습니다. 즉, 프로그래머가 클래스 나 클래스의 메서드를 모르는 경우 응용 프로그램을 코딩하는 동안 리플렉션을 사용하여 런타임에 이러한 클래스를 동적으로 사용할 수 있습니다.
클래스 이름이 자주 변경되는 시나리오에서 자주 사용됩니다. 이러한 상황이 발생하면 프로그래머가 응용 프로그램을 다시 작성하고 클래스 이름을 반복해서 변경하기가 복잡합니다.
대신 리플렉션을 사용하면 클래스 이름 변경 가능성에 대해 걱정할 필요가 있습니다.
리플렉션은 프로그램의 런타임 정보에 액세스하여 동작을 수정할 수있는 기능 세트입니다 (일부 제한 사항이 있음).
프로그램의 메타 정보에 따라 런타임 동작을 변경할 수 있기 때문에 유용합니다. 즉, 함수의 리턴 유형을 확인하고 상황 처리 방식을 변경할 수 있습니다.
예를 들어 C #에서는 런타임에 어셈블리 (.dll)를로드하여 클래스를 탐색하고 찾은 내용에 따라 작업을 수행 할 수 있습니다. 또한 런타임에 클래스의 인스턴스를 만들고 메소드 등을 호출 할 수 있습니다.
어디에서 유용 할 수 있습니까? 매번 유용하지는 않지만 구체적인 상황에 유용합니다. 예를 들어, 로깅 목적으로 클래스 이름을 가져오고 구성 파일에 지정된 내용에 따라 이벤트 핸들러를 동적으로 작성하는 데 사용할 수 있습니다.
나열된 모든 항목에 포인트를 추가하고 싶습니다.
Reflection API 를 사용하면 toString()
모든 객체에 대한 범용 메소드를 작성할 수 있습니다 .
디버깅에 유용합니다.
다음은 몇 가지 예입니다.
class ObjectAnalyzer {
private ArrayList<Object> visited = new ArrayList<Object>();
/**
* Converts an object to a string representation that lists all fields.
* @param obj an object
* @return a string with the object's class name and all field names and
* values
*/
public String toString(Object obj) {
if (obj == null) return "null";
if (visited.contains(obj)) return "...";
visited.add(obj);
Class cl = obj.getClass();
if (cl == String.class) return (String) obj;
if (cl.isArray()) {
String r = cl.getComponentType() + "[]{";
for (int i = 0; i < Array.getLength(obj); i++) {
if (i > 0) r += ",";
Object val = Array.get(obj, i);
if (cl.getComponentType().isPrimitive()) r += val;
else r += toString(val);
}
return r + "}";
}
String r = cl.getName();
// inspect the fields of this class and all superclasses
do {
r += "[";
Field[] fields = cl.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
// get the names and values of all fields
for (Field f : fields) {
if (!Modifier.isStatic(f.getModifiers())) {
if (!r.endsWith("[")) r += ",";
r += f.getName() + "=";
try {
Class t = f.getType();
Object val = f.get(obj);
if (t.isPrimitive()) r += val;
else r += toString(val);
} catch (Exception e) {
e.printStackTrace();
}
}
}
r += "]";
cl = cl.getSuperclass();
} while (cl != null);
return r;
}
}
반사는 물체가 자신의 모습을 볼 수있게하는 것입니다. 이 주장은 성찰과 관련이없는 것 같습니다. 실제로 이것은 "자가 식별"기능입니다.
리플렉션 자체는 Java 및 C #과 같은 자체 지식 및 자체 감지 기능이없는 언어의 단어입니다. 그들에게는 자기 지식의 능력이 없기 때문에, 그것이 어떻게 보이는지 관찰하고 싶을 때, 우리는 그것이 어떻게 보이는지에 대해 또 다른 것을 고려해야합니다. Ruby 및 Python과 같은 탁월한 동적 언어는 다른 개인의 도움 없이도 자신의 언어를 반영 할 수 있습니다. Java의 객체는 리플렉션 클래스의 객체 인 미러가없는 경우의 모습을 인식 할 수 없지만 Python의 객체는 미러없이이를 인식 할 수 있습니다. 그래서 우리는 Java로 리플렉션해야합니다.
자바 문서 페이지에서
java.lang.reflect
패키지는 클래스와 객체에 대한 반사 정보를 얻기위한 클래스와 인터페이스를 제공합니다. 리플렉션을 사용하면로드 된 클래스의 필드, 메서드 및 생성자에 대한 정보에 프로그래밍 방식으로 액세스하고 보안 제한 내에서 기본 필드에서 작동하는 반사 된 필드, 메서드 및 생성자를 사용할 수 있습니다.
AccessibleObject
필요한 경우 액세스 점검을 억제 할 ReflectPermission
수 있습니다.
와 함께,이 패키지의 클래스는, java.lang.Class
같은 디버거, 통역, 개체 검사, 클래스 브라우저 및 같은 서비스와 같은 응용 프로그램을 수용 Object Serialization
하고 JavaBeans
대상 객체의 public 멤버 중 하나에 그 필요성 액세스 (실행시의 클래스에 근거한다) 또는 회원에 의해 선언 주어진 수업
다음과 같은 기능이 포함되어 있습니다.
클래스 에 의해 노출 된 메소드에 대한 이 문서 링크를 살펴보십시오 Class
.
이 기사 (Dennis Sosnoski, Sosnoski Software Solutions, Inc. 사장) 및이 기사 (security-explorations pdf)에서 :
Reflection을 사용하는 것보다 상당한 단점이 있습니다.
리플렉션 사용자 :
반사의 단점 :
일반적인 학대 :
리플렉션 기능 남용에 관한이 SE 질문을 살펴보십시오.
요약:
시스템 코드 내에서 수행 된 기능을 안전하지 않게 사용하면 Java 보안 모드가 손상 될 수 있습니다 . 이 기능을 조금만 사용하십시오
Woozle
클래스가 시작시 다른 클래스를 검사하여 정적 RegisterAsWoozleHelper()
메소드 가있는 클래스를 확인 하고 콜백으로 찾은 모든 메소드를 호출하여 Woozle
자신에 대해 알 수 있도록하는 것입니다. 데이터를 직렬화 해제하는 동안 Reflection을 사용해야합니다.
이름 자체가 제안하는 것처럼 런타임에 인스턴스를 동적으로 생성하는 메소드를 호출하는 기능을 제공하는 것 외에도 클래스 메소드 등의 예를 반영합니다.
실제로 코드를 몰라도 서비스를 호출하기 위해 많은 프레임 워크와 응용 프로그램에서 사용됩니다.
Reflection
많은 용도가 있습니다. 내가 더 익숙한 것은 즉석에서 코드를 만들 수 있다는 것입니다.
IE : 동적 클래스, 함수, 생성자-모든 데이터 기반 (xml / array / sql results / hardcoded / etc.)
이 질문에 예를 들어 대답하고 싶습니다. 우선 모든 Hibernate
프로젝트는 실행중인 애플리케이션과 지속성 저장소 사이의 틈을 메우기위한 명령문 Reflection API
을 생성 하는 데 사용 합니다 CRUD
. 도메인에서 상황이 변경되면 Hibernate
데이터 저장소에 데이터를 유지하고 그 반대로도 유지해야합니다.
또는 작동합니다 Lombok Project
. 컴파일 타임에 코드를 삽입하여 도메인 클래스에 코드를 삽입합니다. (게터와 세터에게는 괜찮다고 생각합니다)
Hibernate
reflection
응용 프로그램의 빌드 프로세스에 최소한의 영향을 미치기 때문에 선택했습니다 .
그리고 Java 7부터는 다음 MethodHandles
과 같이 작동합니다 Reflection API
. 프로젝트에서 로거와 함께 작업하기 위해 다음 코드를 복사하여 붙여 넣습니다.
Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());
이 경우 오타를 만들기가 어렵 기 때문입니다.
예를 들어 설명하는 것이 가장 좋았지 만 그 대답 중 어느 것도 그렇게하지 않는 것 같습니다 ...
리플렉션 사용의 실제 예는 Java로 작성된 Java Language Server 또는 PHP로 작성된 PHP Language Server입니다. Language Server는 자동 완성, 정의로 건너 뛰기, 컨텍스트 도움말, 힌트 유형 등과 같은 IDE 기능을 제공합니다. 입력 할 때 가능한 모든 일치 항목을 표시하기 위해 모든 태그 이름 (자동 완성 할 수있는 단어)을 갖기 위해 언어 서버는 문서 블록 및 개인 멤버를 포함하여 클래스에 대한 모든 것을 검사해야합니다. 이를 위해서는 상기 클래스의 반영이 필요하다.
다른 예는 개인용 메소드의 단위 테스트입니다. 이를 수행하는 한 가지 방법은 테스트 설정 단계에서 리플렉션을 작성하고 메소드 범위를 공용으로 변경하는 것입니다. 물론 개인 메소드는 직접 테스트해서는 안되지만 요점은 아닙니다.