JAVA 반사 메커니즘은 무엇을 합니까?
1. 반사란 무엇인가:
반사라는 개념은 1982년 Smith에 의해 처음 제안되었습니다. 주로 자체 상태나 동작에 액세스하고 이를 감지하고 수정할 수 있는 프로그램을 의미합니다. . 일종의 능력. 이 개념의 도입으로 컴퓨터 과학 분야에서 응용 반사율에 대한 연구가 빠르게 촉발되었습니다. 프로그래밍 언어 설계 분야에서 처음 채택되었으며 Lisp 및 객체 지향 분야에서 성과를 거두었습니다. 그 중 LEAD/LEAD++, OpenC++, MetaXa, OpenJava는 리플렉션 메커니즘을 기반으로 한 언어입니다. 최근에는 윈도우 시스템, 운영체제, 파일 시스템에도 반사 메커니즘이 적용되고 있다. 비록 컴퓨터 과학이 반사라는 개념에 새로운 의미를 부여했지만, 반사 자체는 새로운 개념이 아닙니다. 컴퓨터 과학에서 리플렉션은 자기 설명적이고 자기 제어가 가능한 응용 프로그램 클래스를 의미합니다. 즉, 이러한 유형의 애플리케이션은 특정 메커니즘을 사용하여 자신의 동작에 대한 설명(자기 표현) 및 모니터링(검사)을 실현하고 이를 기반으로 애플리케이션이 설명하는 동작의 상태 및 결과를 조정하거나 수정할 수 있습니다. 자체 동작의 상태 및 결과. 2. Java의 클래스 리플렉션이란 무엇입니까?
리플렉션은 Java 프로그램 개발 언어의 기능 중 하나입니다. 이를 통해 실행 중인 Java 프로그램이 자체적으로 확인하거나 "자체 감사"할 수 있으며 직접적으로 내부 작업을 수행할 수 있습니다. 연산자의 속성과 메서드. Java의 이러한 기능은 실제 응용 프로그램에서는 많이 사용되지 않지만 다른 프로그래밍 언어에는 전혀 존재하지 않습니다. 예를 들어 Pascal, C 또는 C++에서는 프로그램의 함수 정의에 대한 정보를 얻을 수 있는 방법이 없습니다.
리플렉션은 Java가 동적(또는 준동적) 언어로 간주되는 핵심입니다. 리플렉션 API를 사용하면 프로그램이 실행 중에 패키지를 포함하여 알려진 이름을 가진 모든 클래스의 내부 정보를 얻을 수 있습니다. 유형 매개변수, 슈퍼클래스, 구현된 인터페이스, 내부 클래스, 외부 클래스, 필드, 생성자, 메소드, 수정자를 포함하며 실행 중에 인스턴스를 생성하거나 필드 내용을 변경하거나 메소드를 호출할 수 있습니다. 3. Java 클래스 리플렉션에 필요한 클래스:
Java 클래스 리플렉션에 필요한 클래스는 많지 않습니다. 아래에서는 이러한 클래스에 대해 설명합니다. 간단한 설명.
필드 클래스: 클래스 또는 인터페이스의 속성에 대한 정보와 이에 대한 동적 액세스를 제공합니다. 반영된 필드는 클래스(정적) 속성이거나 인스턴스 속성일 수 있습니다. 간단히 이해하면 반사 클래스의 속성을 캡슐화하는 클래스로 볼 수 있습니다.
생성자 클래스: 클래스의 단일 생성자 메서드에 대한 정보와 이에 대한 액세스를 제공합니다. 이 클래스는 Field 클래스와 다릅니다. Field 클래스는 리플렉션 클래스의 속성을 캡슐화하는 반면 Constructor 클래스는 리플렉션 클래스의 생성 메서드를 캡슐화합니다.
메서드 클래스: 클래스 또는 인터페이스의 단일 메서드에 대한 정보를 제공합니다. 반영된 메서드는 클래스 메서드 또는 인스턴스 메서드(추상 메서드 포함)일 수 있습니다. 이 클래스는 이해하기 어렵지 않습니다. 리플렉션 클래스 메서드를 캡슐화하는 데 사용되는 클래스입니다.
클래스 클래스: 클래스 인스턴스는 실행 중인 Java 애플리케이션의 클래스와 인터페이스를 나타냅니다. 열거형은 클래스이고 주석은 인터페이스입니다. 각 배열은 요소 유형과 차원이 동일한 모든 배열에서 공유되는 Class 개체에 매핑되는 클래스에 속합니다.
Object 클래스: 모든 클래스는 Object를 슈퍼 클래스로 사용합니다. 모든 객체(배열 포함)는 이 클래스의 메서드를 구현합니다. 4. Java의 리플렉션 클래스가 할 수 있는 작업:
위 내용을 너무 많이 읽으신 후에는 제가 시간을 낭비하고 있다고 생각하시겠죠? 아래에서는 이를 설명하기 위해 몇 가지 간단한 예를 사용하겠습니다.
먼저 Java의 Reflection 메커니즘을 통해 무엇을 얻을 수 있는지 살펴보겠습니다.
먼저 클래스를 작성합니다: java 코드
import java.awt.event.ActionListener
import java.awt.event.ActionEvent; >
p>
클래스 A는 ActionListener를 구현합니다.
private int a = 3
public Integer b = new Integer(4);
public A(){}
public A(int id,String name){}
public int abc(int id,String name){return 0;}
public void actionPerformed(ActionEvent e){}
} 제가 하고 싶은 일이 무엇인지 모르시면 헷갈리실 수도 있습니다. 이 클래스는 테스트를 위해 Object 클래스를 상속하고 ActionListener 인터페이스, 두 개의 속성 int 및 Integer, 두 개의 생성자 및 두 개의 메소드를 가지고 있다는 것을 알고 있습니다.
이제 A 클래스를 리플렉션 클래스로 두고 A 클래스의 몇 가지 정보를 살펴보겠습니다. 먼저 리플렉션 클래스의 속성과 속성 값을 살펴보겠습니다.
자바 코드
import java.lang.reflect.*
class B{
public static void main(String args[]){
A r = new A();
클래스 임시 = r.getClass()
try{
System.out.println(" 리플렉션 클래스의 모든 공용 속성");
Field[] fb =temp.getFields();
for(int j=0;j 클래스 cl = fb[j].getType(); System.out.println("fb:"+cl) } System.out.println("리플렉션 클래스의 모든 속성") Field[] fa = temp.getDeclaredFields() for(int j=0;j 클래스 cl = fa[j].getType() System.out.println("fa:"+ cl); } System.out.println("리플렉션 클래스의 개인 속성 값") Field f = temp. getDeclaredField(" a"); f.setAccessible(true); Integer i = (Integer)f.get(r); out.println (i); }catch(예외 e){ e.printStackTrace(); } 여기에서는 getFields() 및 getDeclaredFields()라는 두 가지 메서드가 사용됩니다. 이 두 메서드는 각각 리플렉션 클래스의 모든 공용 속성과 리플렉션 클래스의 모든 속성을 가져오는 데 사용되는 메서드입니다. 또한 리플렉션 클래스의 속성을 지정하는 데 사용되는 getField(String) 및 getDeclaredField(String) 메서드가 있습니다. getField 메서드는 리플렉션 클래스의 공용 속성만 가져올 수 있는 반면, getDeclaredField 메서드는 가져올 수 있습니다. 그것을 얻으십시오. Field 클래스의 setAccessible 메소드도 리플렉션 클래스의 비공개 속성에 대한 액세스 권한이 있는지 설정하는 데 사용됩니다. true로 설정된 경우에만 액세스할 수 있습니다. 기본값은 거짓입니다. 또한 Field 클래스에는 지정된 속성의 값을 변경할 수 있는 set(Object AttributeName, Object value) 메서드도 있습니다. Reflection 클래스에서 생성자 메소드의 Java 코드를 가져오는 방법을 살펴보겠습니다. import java.lang.reflect.* public class SampleConstructor { public static void main(String[] args) { A r = new A() printConstructors(r); /p> public static void printConstructors(A r) { Class c = r.getClass() //지정된 클래스의 클래스 이름 가져오기 p> String className = c.getName(); try { //지정된 클래스의 생성자를 가져옵니다. Constructor[] theConstructors = c.getConstructors(); for(int i=0; i //지정된 생성자의 매개변수 세트 가져오기 Class[] 매개변수 유형 = theConstructors[i].getParameterTypes(); System.out.print(className + "("); for(int j =0; j System.out.print(parameterTypes[j].getName() + " ") System.out.println( ")"); } }catch(예외 e) { e.printStackTrace() } p> } p> } 이 예제는 매우 간단합니다. getConstructors() 메서드를 사용하여 리플렉션 클래스의 생성자 컬렉션을 가져옵니다. , 생성자 클래스의 getParameterTypes()를 사용하여 생성자의 매개변수를 가져옵니다. 이제 리플렉션 클래스의 상위 클래스(수퍼 클래스)와 인터페이스 Java 코드를 가져옵니다. import java.io.* import java.lang.reflect.*; p> java.lang.reflect.* 가져오기 java.io.* 가져오기 p> public class SampleInterface { public static void main(String[] args) throws Exception { A raf = new A() printInterfaceNames(raf) } public static void printInterfaceNames(Object o) { Class c = o.getClass() //리플렉션 클래스의 인터페이스 가져오기 Class[] theInterfaces = c.getInterfaces(); for(int i=0; i System.out.println( theInterfaces[i].getName()); //리플렉션 클래스의 상위 클래스(슈퍼 클래스)를 가져옵니다. Class theSuperclass = c.getSuperclass(); > System.out.println(theSuperclass.getName()); } } 이 예제도 매우 간단합니다. 클래스의 getInterfaces() 메소드를 사용하십시오. 리플렉션 클래스의 모든 인터페이스를 가져오려면 클래스가 여러 개 있을 수 있으므로 Class 배열을 반환합니다. 리플렉션 클래스의 상위 클래스(슈퍼클래스)를 가져오려면 getSuperclass() 메서드를 사용하세요. 클래스는 하나의 클래스에서만 상속할 수 있으므로 Class 객체를 반환합니다. 리플렉션 클래스의 메소드 Java 코드를 가져옵니다. import java.lang.reflect.* public class SampleMethod { public static void main( String [] args) { A p = new A(); printMethods(p) } 공용 정적 무효 printMethods(Object o) { Class c = o.getClass(); String className = c.getName(); c.getMethods(); for(int i=0; i //메소드의 반환 유형을 출력합니다. System.out.print(m[i].getReturnType().getName()) //출력 메소드 이름 System.out.print(" "+ m [i].getName()+"("); //메소드의 매개변수 가져오기 Class[] 매개변수 유형 = m[i].getParameterTypes(); for(int j=0; j System.out.print(parameterTypes[j].getName()) if(parameterTypes.length>j+1){ System.out.print(",") } } p> System.out.println(")"); } } } 이 예는 어렵지 않습니다. 리플렉션 클래스 상위 클래스에서 상속된 메서드를 포함한 모든 메서드입니다. 그런 다음 메서드의 반환 유형, 메서드 이름, 메서드 매개변수를 가져옵니다. 다음으로, 리플렉션 클래스의 속성, 생성자, 부모 클래스, 인터페이스 및 메서드를 얻었지만 이러한 것들이 우리에게 무엇을 할 수 있는지 생각해 보겠습니다. ! Java의 리플렉션 클래스가 무엇을 할 수 있는지 설명하기 위해 아래에 비교적 완전한 작은 예를 작성하겠습니다! ! 자바 코드 java.lang.reflect.Constructor 가져오기 java.lang.reflect.Method 가져오기 public class LoadMethod; p>공용 객체 로드(String cName,String MethodName,String[] type,String[] param){ 객체 retobj = null try { //지정된 Java 클래스 로드 Class cls = Class.forName(cName) //지정된 객체의 인스턴스 가져오기 생성자 ct = cls .getConstructor(null); Object obj = ct.newInstance(null) //생성 메소드 매개변수의 데이터 유형 클래스 partypes[ ] = this.getMethodClass(type); //지정된 클래스에서 지정된 메소드를 가져옵니다. Method meth = cls.getMethod(MethodName, partypes); p> //메서드의 매개변수 값을 구성합니다. Object arglist[] = this.getMethodObject(type,param) //지정된 메서드를 호출하고 반환 값을 가져옵니다. 객체 유형으로 p> retobj= meth.invoke(obj, arglist) } catch (Throwable e) { System.err.println( e); } retobj 반환 } //방법 매개변수 유형 가져오기 Class[] public Class[] getMethodClass(String[] type){ Class[] cs = new Class[type.length] for (int i = 0; i < cs.length; i++) { if(!type[i].trim().equals("")||type[i]!= null){ if(type[i].equals("int")||type[i].equals("Integer")){ cs[i]= 정수.TYPE; }else if(type[i].equals("float")||type[i].equals("Float")){ cs[ i]=Float.TYPE; }else if(type[i].equals("double")||type[i].equals("Double")){ cs[i]=더블 e.TYPE; }else if(type[i].equals("boolean")||type[i].equals("Boolean")){ cs[ i]=Boolean.TYPE; }else{ cs[i]=String.class } } } return cs; } //매개변수를 가져오는 방법 Object[] public Object [] getMethodObject(String[] type,String[] param){ Object[] obj = new Object[param.length] for (int i = 0; i < obj.length; i++) { if(!param[i].trim().equals("")||param[i]!=null){ if(type[i].equals("int")||type[i].equals("Integer")){ obj[i]= new Integer(param[i]); /p> }else if(type[i].equals("float")||type[i].equals("Float")){ obj[i]= new Float (param[i]); }else if(type[i].equals("double")||type[i].equals("Double")){ obj[i]= new Double(param[i]); }else if(type[i].equals("boolean")||type[i].equals("Boolean") ){ obj[i]=new Boolean(param[i]); }else{ obj[i] = param[i]; } } } return obj; } } 이것은 지정된 클래스를 로드하고 런타임에 지정된 메서드를 호출하기 위해 Java를 구현하기 위해 직장에서 작성한 작은 예입니다. 여기에는 주요 메소드가 없으며 직접 작성할 수 있습니다. Load 메소드가 수신하는 5개의 매개변수는 Java 클래스 이름, 메소드 이름, 매개변수 유형 및 매개변수 값입니다. 결론: Java 언어 리플렉션은 프로그램 구성 요소를 동적으로 연결하는 다양한 방법을 제공합니다. 이를 통해 프로그램은 대상 클래스를 미리 하드코딩하지 않고도 모든 클래스의 객체를 생성하고 제어할 수 있습니다. 이러한 속성은 리플렉션을 매우 일반적인 방식으로 개체와 함께 작동하는 라이브러리를 만드는 데 특히 적합하게 만듭니다. Java 리플렉션은 클래스와 데이터 구조가 이름별로 관련 정보를 동적으로 검색하고 이 정보를 실행 중인 프로그램에서 조작할 수 있도록 허용하므로 매우 유용합니다. Java의 이 기능은 매우 강력하며 C, C++, Fortran 또는 Pascal과 같이 일반적으로 사용되는 다른 언어에서는 사용할 수 없습니다. 그러나 반사에는 두 가지 단점이 있습니다. 첫 번째는 성능 문제입니다. 필드 및 메서드 액세스에 사용되는 경우 리플렉션은 직접 코드보다 훨씬 느립니다. 성능 문제의 정도는 프로그램에서 리플렉션이 어떻게 사용되는지에 따라 다릅니다. 느린 성능은 프로그램 작업에서 비교적 드물게 관련된 부분이라면 문제가 되지 않습니다. 테스트에서 최악의 타이밍 그래프에서도 반사 작업에는 몇 마이크로초밖에 걸리지 않는 것으로 나타났습니다. 성능 문제는 성능이 중요한 애플리케이션의 핵심 논리에서 리플렉션이 사용될 때만 중요해집니다.