java reflection tutorial with examples
이 비디오 자습서에서는 Reflection이 무엇이며 Reflection API를 사용하여 구현하는 방법을 설명합니다.
Java의 Reflection은 런타임에 프로그램의 동작을 검사하고 변경하는 것입니다.
이 리플렉션 API를 사용하면 런타임에 클래스, 생성자, 수정 자, 필드, 메서드 및 인터페이스를 검사 할 수 있습니다. 예를 들어, 클래스의 이름을 얻거나 클래스의 개인 멤버에 대한 세부 정보를 얻을 수 있습니다.
전체 읽기 JAVA 교육 시리즈 Java 개념에 대한 자세한 정보는
다음은 Java Reflection에 대한 비디오 자습서입니다.
학습 내용 :
자바에서의 반사
우리는 주어진 클래스에서 컴파일 타임에 속성과 메서드를 수정할 수 있으며 그렇게하는 것이 매우 쉽다는 것을 알고 있습니다. 속성과 메서드가 익명이거나 이름이 있는지 여부에 관계없이 컴파일 시간 동안 원하는대로 변경할 수 있습니다.
그러나 이러한 클래스, 메서드 또는 필드는 런타임에 즉시 변경할 수 없습니다. 즉, 특히 알 수없는 개체에 대해 런타임에 다양한 프로그래밍 구성 요소의 동작을 변경하는 것은 매우 어렵습니다.
Java 프로그래밍 언어는 '반사' 이를 통해 런타임에 클래스 또는 필드 또는 메서드의 런타임 동작을 수정할 수 있습니다.
따라서 Reflection은 다음과 같이 정의 될 수 있습니다. “런타임에 알 수없는 개체의 런타임 동작을 검사하고 수정하는 기술. 객체는 클래스, 필드 또는 메서드가 될 수 있습니다.”
Reflection은 Java에서 제공하는 '애플리케이션 프로그래밍 인터페이스'(API)입니다.
'반사'프로세스는 아래에 설명되어 있습니다.
위의 표현에서 알 수없는 객체가 있음을 알 수 있습니다. 그런 다음이 객체에 Reflection API를 사용합니다. 결과적으로 런타임에이 개체의 동작을 수정할 수 있습니다.
따라서 객체의 동작을 수정하기 위해 프로그램에서 Reflection API를 사용할 수 있습니다. 객체는 메소드, 인터페이스, 클래스 등과 같은 것이 될 수 있습니다. 이러한 객체를 검사 한 다음 리플렉션 API를 사용하여 런타임시 동작을 변경합니다.
Java에서 'java.lang'과 'java.lang.reflect'는 리플렉션을위한 클래스를 제공하는 두 패키지입니다. 특수 클래스 'java.lang.Class'는 클래스 동작을 검사하고 수정할 수있는 메타 데이터를 추출하는 메서드와 속성을 제공합니다.
위의 패키지에서 제공하는 Reflection API를 사용하여 런타임시 필드, 메서드, 생성자 등을 포함한 클래스 및 해당 멤버를 수정합니다. Reflection API의 특징은 클래스의 개인 데이터 멤버 나 메서드를 조작 할 수도 있다는 것입니다.
Reflection API는 주로 다음에서 사용됩니다.
- 리플렉션은 주로 디버깅 도구, JUnit 및 프레임 워크에서 런타임시 동작을 검사하고 변경하는 데 사용됩니다.
- IDE (통합 개발 환경) 예 : Eclipse IDE, NetBeans 등
- 테스트 도구 등
- 애플리케이션에 타사 라이브러리가 있고 사용 가능한 클래스 및 메서드에 대해 알고 싶을 때 사용됩니다.
자바의 리플렉션 API
Reflection API를 사용하여 다음 엔티티에 리플렉션을 구현할 수 있습니다.
- 들 : Field 클래스에는 데이터 유형 (int, double, String 등), 액세스 수정 자 (private, public, protected 등), 이름 (식별자) 및 값과 같은 변수 또는 필드를 선언하는 데 사용하는 정보가 있습니다.
- 방법 : Method 클래스는 메소드의 액세스 수정 자, 메소드 반환 유형, 메소드 이름, 메소드 매개 변수 유형 및 메소드에서 발생하는 예외 유형과 같은 정보를 추출하는 데 도움이 될 수 있습니다.
- 빌더 : 생성자 클래스는 생성자 액세스 수정 자, 생성자 이름 및 매개 변수 유형을 포함하는 클래스 생성자에 대한 정보를 제공합니다.
- 편집하다 : 수정 자 클래스는 특정 액세스 수정 자에 대한 정보를 제공합니다.
위의 모든 클래스는 java.lang.reflect 패키지의 일부입니다. 다음으로 이러한 각 클래스에 대해 논의하고 프로그래밍 예제를 사용하여 이러한 클래스에 대한 반성을 보여줄 것입니다.
먼저 java.lang.Class 클래스부터 시작하겠습니다.
java.lang.Class 클래스
java.lang.The 클래스는 런타임에 클래스와 객체에 대한 모든 정보와 데이터를 보유합니다. 이것은 반사에 사용되는 메인 클래스입니다.
java.lang.Class 클래스는 다음을 제공합니다.
- 런타임에 클래스 메타 데이터를 검색하는 메서드입니다.
- 런타임에 클래스의 동작을 검사하고 수정하는 메서드입니다.
java.lang.Class 객체 생성
다음 옵션 중 하나를 사용하여 java.lang.Class의 객체를 만들 수 있습니다.
숙련자를위한 성능 테스트 인터뷰 질문
# 1) .class 확장자
Class 객체를 만드는 첫 번째 옵션은 .class 확장자를 사용하는 것입니다.
예를 들면Test가 클래스이면 다음과 같이 Class 객체를 만들 수 있습니다.
Class obj_test = Test.class;
그런 다음 obj_test를 사용하여 반사를 수행 할 수 있습니다.이 객체는 Test 클래스에 대한 모든 정보를 갖게됩니다.
# 2) forName () 메서드
forName () 메서드는 클래스 이름을 인수로 사용하고 Class 객체를 반환합니다.
예를 들면Test 클래스의 개체는 다음과 같이 만들 수 있습니다.
class obj_test = Class.forName (“Test”);
# 3) getClas () 메서드
getClass () 메소드는 클래스의 객체를 사용하여 java.lang.Class 객체를 가져옵니다.
예를 들면다음 코드를 고려하십시오.
Test obj = new Test (); Class obj_test = obj.getClass ();
첫 번째 줄에서는 Test 클래스의 개체를 만들었습니다. 그런 다음이 객체를 사용하여 'getClass ()'메서드를 호출하여 java.lang.Class의 객체 obj_test를 가져옵니다.
슈퍼 클래스 및 액세스 수정 자 받기
java.lang.class는 모든 클래스의 수퍼 클래스를 가져 오는 데 사용되는 'getSuperClass ()'메소드를 제공합니다.
마찬가지로 클래스의 액세스 수정자를 반환하는 getModifier () 메서드를 제공합니다.
아래 예제는 getSuperClass () 메서드를 보여줍니다.
import java.lang.Class; import java.lang.reflect.*; //define Person interface interface Person { public void display(); } //declare class Student that implements Person class Student implements Person { //define interface method display public void display() { System.out.println('I am a Student'); } } class Main { public static void main(String() args) { try { // create an object of Student class Student s1 = new Student(); // get Class object using getClass() Class obj = s1.getClass(); // get the superclass of Student Class superClass = obj.getSuperclass(); System.out.println('Superclass of Student Class: ' + superClass.getName()); } catch(Exception e) { e.printStackTrace(); } } }
산출
위의 프로그래밍 예제에서 Person 인터페이스는 'display ()'라는 유일한 메소드로 정의됩니다. 그런 다음 사람 인터페이스를 구현하는 Student 클래스를 정의합니다. main 메소드에서 getClass () 메소드를 사용하여 Class 객체를 검색 한 다음 getSuperClass () 메소드를 사용하여 Student 객체의 부모 또는 수퍼 클래스에 액세스합니다.
인터페이스 얻기
클래스가 일부 인터페이스를 구현하면 java.lang.Class의 getInterfaces () 메소드를 사용하여 이러한 인터페이스 이름을 가져올 수 있습니다. 이를 위해 Java 클래스에 대한 리플렉션을 수행해야합니다.
아래 프로그래밍 예제는 Java Reflection에서 getInterfaces () 메서드를 사용하는 방법을 보여줍니다..
import java.lang.Class; import java.lang.reflect.*; //define Interface Animals and PetAnimals interface Animals { public void display(); } interface PetAnimals { public void makeSound(); } //define a class Dog that implements above interfaces class Dog implements Animals, PetAnimals { //define interface method display public void display() { System.out.println('This is a PetAnimal::Dog'); } //define interface method makeSound public void makeSound() { System.out.println('Dog makes sound::Bark bark'); } } class Main { public static void main(String() args) { try { // create an object of Dog class Dog dog = new Dog(); // get class object Class obj = dog.getClass(); // get the interfaces implemented by Dog Class() objInterface = obj.getInterfaces(); System.out.println('Class Dog implements following interfaces:'); //print all the interfaces implemented by class Dog for(Class citem : objInterface) { System.out.println('Interface Name: ' + citem.getName()); } } catch(Exception e) { e.printStackTrace(); } } }
산출
위의 프로그램에서 우리는 Animals와 PetAnimals라는 두 가지 인터페이스를 정의했습니다. 그런 다음 두 인터페이스를 모두 구현하는 Dog 클래스를 정의합니다.
메인 메소드에서는 리플렉션을 수행하기 위해 java.lang.Class에서 Dog 클래스의 객체를 검색합니다. 그런 다음 getInterfaces () 메서드를 사용하여 Dog 클래스에 의해 구현 된 인터페이스를 검색합니다.
반영 : 필드 값 가져 오기
이미 언급했듯이 java.lang.reflect 패키지는 클래스의 필드 또는 데이터 멤버를 반영하는 데 도움이되는 Field 클래스를 제공합니다.
필드 리플렉션을 위해 Field 클래스에서 제공하는 메서드는 다음과 같습니다.
방법 | 기술 |
---|---|
getField ( 'fieldName') | 지정된 필드 이름이있는 필드 (공용)를 반환합니다. |
getFields () | 모든 공용 필드를 반환합니다 (클래스 및 수퍼 클래스 모두). |
getDeclaredFields () | 클래스의 모든 필드를 검색합니다. |
getModifier () | 필드 액세스 수정 자의 정수 표현을 리턴합니다. |
set (classObject, 값) | 필드에 지정된 값을 할당합니다. |
get (classObject) | 필드 값을 검색합니다. |
setAccessible (부울) | true를 전달하여 비공개 필드에 액세스 할 수 있도록합니다. |
getDeclaredField ( 'fieldName') | 지정된 이름의 필드를 반환합니다. |
다음은 공공 및 민간 분야에 대한 성찰을 보여주는 두 가지 성찰 예입니다.
아래의 Java 프로그램은 공개 필드에 대한 반영을 보여줍니다.
import java.lang.Class; import java.lang.reflect.*; class Student { public String StudentName; } class Main { public static void main(String() args) { try{ Student student = new Student(); // get an object of the class Class Class obj = student.getClass(); // provide field name and get the field info Field student_field = obj.getField('StudentName'); System.out.println('Details of StudentName class field:'); // set the value of field student_field.set(student, 'Lacey'); // get the access modifier of StudentName int mod1 = student_field.getModifiers(); String modifier1 = Modifier.toString(mod1); System.out.println('StudentName Modifier::' + modifier1); // get the value of field by converting in String String typeValue = (String)student_field.get(student); System.out.println('StudentName Value::' + typeValue); } catch(Exception e) { e.printStackTrace(); } } }
산출
이 프로그램에서 우리는 Public 필드 StudentName이있는 'Student'클래스를 선언했습니다. 그런 다음 Field 클래스의 API 인터페이스를 사용하여 StudentName 필드에서 리플렉션을 수행하고 해당 액세스 수정 자와 값을 검색합니다.
다음 프로그램은 클래스의 개인 필드에 대한 반영을 수행합니다. 작업은 private 필드에 대해 하나의 추가 함수 호출이 있다는 점을 제외하면 비슷합니다. private 필드에 대해 setAccessible (true)을 호출해야합니다. 그런 다음이 필드에 대해 공개 필드와 유사한 방식으로 반성을 수행합니다.
import java.lang.Class; import java.lang.reflect.*; class Student { private String rollNo; } class Main { public static void main(String() args) { try { Student student = new Student(); // get the object for class Student in a Class. Class obj = student.getClass(); // access the private field Field field2 = obj.getDeclaredField('rollNo'); // make the private field accessible field2.setAccessible(true); // set the value of rollNo field2.set(student, '27'); System.out.println('Field Information of rollNo:'); // get the access modifier of rollNo int mod2 = field2.getModifiers(); String modifier2 = Modifier.toString(mod2); System.out.println('rollNo modifier::' + modifier2); // get the value of rollNo converting in String String rollNoValue = (String)field2.get(student); System.out.println('rollNo Value::' + rollNoValue); } catch(Exception e) { e.printStackTrace(); } } }
산출
반사 : 방법
클래스의 필드와 마찬가지로 클래스 메서드에 대한 리플렉션을 수행하고 런타임에 동작을 수정할 수도 있습니다. 이를 위해 java.lang.reflect 패키지의 Method 클래스를 사용합니다.
다음은 클래스 메서드 리플렉션을 위해 Method 클래스에서 제공하는 함수입니다.
방법 | 기술 |
---|---|
getMethods () | 클래스 및 해당 수퍼 클래스에 정의 된 모든 공용 메서드를 검색합니다. |
getDeclaredMethod () | 클래스에 선언 된 메서드를 반환합니다. |
getName () | 메서드 이름을 반환합니다. |
getModifiers () | 메서드 액세스 수정 자의 정수 표현을 반환합니다. |
getReturnType () | 메서드 반환 유형을 반환합니다. |
아래 예제는 위의 API를 사용하여 Java에서 클래스 메소드를 반영하는 것을 보여줍니다.
import java.lang.Class; import java.lang.reflect.*; //declare a class Vehicle with four methods class Vehicle { public void display() { System.out.println('I am a Vehicle!!'); } protected void start() { System.out.println('Vehicle Started!!!'); } protected void stop() { System.out.println('Vehicle Stopped!!!'); } private void serviceVehicle() { System.out.println('Vehicle serviced!!'); } }class Main { public static void main(String() args) { try { Vehicle car = new Vehicle(); // create an object of Class Class obj = car.getClass(); // get all the methods using the getDeclaredMethod() in an array Method() methods = obj.getDeclaredMethods(); // for each method get method info for(Method m : methods) { System.out.println('Method Name: ' + m.getName()); // get the access modifier of methods int modifier = m.getModifiers(); System.out.print('Modifier: ' + Modifier.toString(modifier) + ' '); // get the return type of method System.out.print('Return Type: ' + m.getReturnType()); System.out.println('
'); } } catch(Exception e) { e.printStackTrace(); } } }
산출
위의 프로그램에서 getDeclaredMethods 메서드가 클래스에서 선언 한 메서드 배열을 반환하는 것을 볼 수 있습니다. 그런 다음이 배열을 반복하고 각 메서드의 정보를 표시합니다.
반사 : 생성자
java.lang.reflect 패키지의 'Constructor'클래스를 사용하여 Java 클래스의 생성자를 검사하고 수정할 수 있습니다.
생성자 클래스는이를 위해 다음 메서드를 제공합니다.
방법 | 기술 |
---|---|
getConstructors () | 클래스 및 수퍼 클래스에 선언 된 모든 생성자를 반환합니다. |
getDeclaredConstructor () | 선언 된 모든 생성자를 반환합니다. |
getName () | 생성자의 이름을 검색합니다. |
getModifiers () | 생성자의 액세스 수정 자의 정수 표현을 반환합니다. |
getParameterCount () | 생성자의 총 매개 변수 수를 반환합니다. |
아래 리플렉션 예제는 Java에서 클래스 생성자의 리플렉션을 보여줍니다. 메서드 리플렉션과 마찬가지로 여기에서도 getDeclaredConstructors 메서드는 클래스에 대한 생성자의 배열을 반환합니다. 그런 다음이 생성자 배열을 탐색하여 각 생성자에 대한 정보를 표시합니다.
import java.lang.Class; import java.lang.reflect.*; //declare a class Person with three constructors class Person { public Person() { } //constructor with no parameters public Person(String name) { } //constructor with 1 parameter private Person(String name, int age) {} //constructor with 2 parameters } class Main { public static void main(String() args) { try { Person person = new Person(); Class obj = person.getClass(); // get array of constructors in a class using getDeclaredConstructor() Constructor() constructors = obj.getDeclaredConstructors(); System.out.println('Constructors for Person Class:'); for(Constructor c : constructors) { // get names of constructors System.out.println('Constructor Name: ' + c.getName()); // get access modifier of constructors int modifier = c.getModifiers(); System.out.print ('Modifier: ' + Modifier.toString(modifier) + ' '); // get the number of parameters in constructors System.out.println('Parameters: ' + c.getParameterCount()); //if there are parameters, get parameter type of each parameter if(c.getParameterCount() > 0){ Class() paramList=c.getParameterTypes(); System.out.print ('Constructor parameter types :'); for (Class class1 : paramList) { System.out.print(class1.getName() +' '); } } System.out.println('
'); } } catch(Exception e) { e.printStackTrace(); } } }
산출
반사의 단점
성찰은 강력하지만 무차별 적으로 사용해서는 안됩니다. 반사를 사용하지 않고 작동 할 수 있다면 사용을 피하는 것이 좋습니다.
다음은 Reflection의 몇 가지 단점입니다.
- 성능 오버 헤드 : 반사는 강력한 기능이지만 반사 작업은 여전히 비 반사 작업보다 성능이 느립니다. 따라서 성능이 중요한 응용 프로그램에서 반사를 사용하지 않아야합니다.
- 보안 제한 : 리플렉션은 런타임 기능이므로 런타임 권한이 필요할 수 있습니다. 따라서 제한된 보안 설정에서 코드를 실행해야하는 응용 프로그램의 경우 리플렉션이 사용되지 않을 수 있습니다.
- 내부 노출 : 리플렉션을 사용하여 클래스의 개인 필드와 메서드에 액세스 할 수 있습니다. 따라서 리플렉션은 코드를 이식 할 수없고 기능을 저하시킬 수있는 추상화를 깨뜨립니다.
자주 묻는 질문
Q # 1) Java에서 Reflection이 사용되는 이유는 무엇입니까?
대답: 리플렉션을 사용하면 컴파일 타임에 익명 인 경우에도 런타임에 클래스, 인터페이스, 생성자, 필드 및 메서드를 검사 할 수 있습니다. 이 검사를 통해 런타임에 이러한 엔티티의 동작을 수정할 수 있습니다.
질문 # 2) Reflection은 어디에 사용됩니까?
대답: 리플렉션은 사용자 정의 클래스와 상호 운용되는 프레임 워크를 작성하는 데 사용되며 프로그래머는 클래스 또는 기타 엔티티가 무엇인지조차 알지 못합니다.
질문 # 3) Java Reflection이 느립니까?
대답: 예, 무반사 코드보다 느립니다.
질문 # 4) Java Reflection이 좋지 않습니까?
대답: 어떤면에서는 그렇습니다. 우선, 우리는 컴파일 타임 안전성을 잃습니다. 컴파일 타임 안전성이 없으면 최종 사용자에게 영향을 미칠 수있는 런타임 오류가 발생할 수 있습니다. 오류를 디버그하는 것도 어렵습니다.
질문 # 5) Java에서 Reflection을 어떻게 중지합니까?
대답: 우리는 단순히 비 반사 연산을 작성하여 반사를 사용하지 않습니다. 또는 리플렉션을 사용한 사용자 지정 유효성 검사와 같은 일반적인 메커니즘을 사용할 수 있습니다.
Java Reflection에 대한 추가 정보
java.lang.reflect 패키지에는 리플렉션을 수행 할 클래스와 인터페이스가 있습니다. 그리고 java.lang.class는 리플렉션의 진입 점으로 사용될 수 있습니다.
클래스 객체를 얻는 방법 :
1. 개체의 인스턴스가있는 경우
클래스 c = obj.getclass ();
2. 수업 유형을 알고 있다면
클래스 c = type.getClass ();
3. 수업 이름을 알고 있다면
클래스 c = Class.forName (“com.demo.Mydemoclass”);
반원을 얻는 방법 :
클래스 멤버는 필드 (클래스 변수) 및 메서드입니다.
- getFields () – private 필드를 제외한 모든 필드를 가져 오는 데 사용됩니다.
- getDeclaredField () – 개인 필드를 가져 오는 데 사용됩니다.
- getDeclaredFields () – 개인 및 공용 필드를 가져 오는 데 사용됩니다.
- getMethods () – private 메서드를 제외한 모든 메서드를 가져 오는 데 사용됩니다.
- getDeclaredMethods () – 공개 및 개인 방법을 얻는 데 사용됩니다.
데모 프로그램 :
ReflectionHelper.java :
리플렉션 API를 사용하여 검사 할 클래스입니다.
월드 오브 워크래프트 클래식 개인 서버
class ReflectionHelper { private int age; private String name; public String deptName; public int empID; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } }
ReflectionDemo.java
public class ReflectionDemo { public static void main(String() args) throws NoSuchFieldException, SecurityException { //get the class Class ReflectionHelperclass=ReflectionHelper.class; //get the name of the class String className = ReflectionHelperclass.getName(); System.out.println('className=='+className); System.out.println('getModifiers'+ReflectionHelperclass.getModifier s()); System.out.println('getSuperclass'+ReflectionHelperclass.getSupercla ss()); System.out.println('getPackage'+ReflectionHelperclass.getPackage()); Field() fields =ReflectionHelperclass.getFields(); //getting only the public fields for(Field oneField : fields) { Field field = ReflectionHelperclass.getField(oneField.getName()); String fieldname = field.getName(); System.out.println('only the public fieldnames:::::'+fieldname); } //getting all the fields of the class Field() privatefields =ReflectionHelperclass.getDeclaredFields(); for(Field onefield : privatefields) { Field field = ReflectionHelperclass.getDeclaredField(onefield.getName()); String fieldname = field.getName(); System.out.println('all the fieldnames in the class:::'+fieldname); } Method() methods =ReflectionHelperclass.getDeclaredMethods(); for(Method m: methods) { System.out.println('methods::::'+m.getName()); } }}
결론
이 튜토리얼에서는 Java의 Reflection API에 대해 자세히 설명했습니다. 리플렉션의 몇 가지 단점과 함께 클래스, 인터페이스, 필드, 메서드 및 생성자의 리플렉션을 수행하는 방법을 보았습니다.
Reflection은 Java에서 비교적 고급 기능이지만 언어에 대한 강점을 가진 프로그래머가 사용해야합니다. 주의해서 사용하지 않으면 예상치 못한 오류와 결과가 발생할 수 있기 때문입니다.
반사는 강력하지만 신중하게 사용해야합니다. 그럼에도 불구하고 리플렉션을 사용하여 런타임까지 클래스 및 기타 엔티티를 인식하지 못하는 애플리케이션을 개발할 수 있습니다.
=> 여기에서 Java Beginners Guide를 살펴보십시오.