리플렉션이란 무엇이며 왜 유용합니까?
특히 Java에 관심이 있지만 원칙이 모든 언어에서 동일하다고 가정합니다.
답변
이름 반영은 동일한 시스템 (또는 자체)에서 다른 코드를 검사 할 수있는 코드를 설명하는 데 사용됩니다.
예를 들어, 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 ++입니다.
답변
리플렉션 은 런타임에 클래스, 메소드, 속성 등을 검사하고 동적으로 호출하는 언어의 기능입니다.
예를 들어, 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();
}
답변
반사의 사용
리플렉션은 일반적으로 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이지만 런타임에 모든 유형을 확인하므로 초과 사용하면 응용 프로그램 속도가 느려질 수 있습니다.