리플렉션

2022. 12. 15. 19:05자바멘토링

먼저 ! 

 

java.lang.class객체 대해서 알아보기 

 

class클래스

  • 자바는 클래스와 인터페이스의 메타 데이터를 class클래스로 관리
  • 메타 데이터: 타입이름 및 파일 경로 정보, 필드정보 , 메소드 정보

클래스 객체 얻는 방법

package main231;

public class Car {
	 public static void main(String[] args) {

	 }
}
package main231;

public class ClassExample {
	 public static void main(String[] args) throws ClassNotFoundException {
	
    //클래스 부터 얻는 방법
    Class clazz = Car.class;
	/* Class clazz1 = Class.forName("Car"); */
	
    //객체로 부터 얻는 방법
    Car car = new Car();
	Class   clazz2 = car.getClass();
	
	
	/* System.out.println(clazz==clazz1); */
	System.out.println(clazz==clazz2);
	
	System.out.println(clazz.getName()); // 전체 경로 얻기
	System.out.println(clazz.getSimpleName()); // 클래스 이름 얻기
	System.out.println(clazz.getPackage().getName());//클래스 패키지 이름 얻기
    
	}
}
true
main231.Car
Car
main231

궁금증?

 

new연산자 없이 Class객체를 이용하면 좋은점은 무엇인가

: 동적으로 객체 생성이 가능해진다, 코드 작성시에 클래스 이름을 결정할 수 없고, 런타임시에 클래스 이름이 결정되는 경우에 유용하다. 

 

 

 

 

참고:https://www.youtube.com/watch?v=IEs-pnSXvoU

 

Reflection이란?

:반사 , 반영된 이미지

 

실체 = Class

거울 = jvm 메모리 영역

 

 

 

 

class :

-실행중인 자바 어플리케이션의 클래스와 인터페이스의 정보를 가진 클래스

-public 생성자가 존재하지 않는다.

-class객체는jvm에 의해 자동으로 생성된다.

 

class의 기능들

  1. 클래스에 붙은 어노테이션 조회
  2. 클래스 생성자 조회
  3. 클래스 필드 조회
  4. 클래스 메소드 조회
  5. 부모 클래스, 인터페이스 조회 

 

 리플랙션은 힙 영역에 로드된 Class타입의 객체를 통해 , 원하는 클래스의 인스턴스를 생성 할수 있도록 지원하고, 인스턴스의 필드와 메소드를 접근 제어자와 상관없이 사용할 수 있도록 지원하는API이다.
여기서 로드된 클래스라고 함은,JVM의 클래스 로더에서 클래스 파일에 대한 로딩을 완료한 후 , 해당 클래스의 정보를 담은 Class타입의 객체를 생성하여 메모리의 힙 영역에 저장해 둔 것을 의미한다. 
new 키워드를 통해 만드는 객체와는 다른 것임을 유의하자

 

리플렉션 예제

package main231;

public class Dog {
	private static final String CATEGORY ="동물";
	
	private String name;
	public int age;
	
	
	private Dog() {
		this.name = "누렁이";
		this.age=0;
		
	}
	
	public Dog(final String name) {
		this.name =name;
		this.age =0;
	}
	public Dog(final String name, final int age) {
		this.name=name;
		this.age=age;
		
	}
	
	//메소드 
	private void speak(final String sound, final int count) {
		
		System.out.println(sound.repeat(count));
		
	}
	

	public void eate() {
		System.out.println("사료를 먹습니다.");
		
	}
	
    public  int getAgs() {
    	return age;
    	
    }
	

}

 

package main231;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Sample {
	
	 public static void main(String[] args) throws Exception {
	Class<?> clazz = Dog.class;
	
	Constructor<?> constructor1 = clazz.getDeclaredConstructor();//기본생성자를 Constructor 객체로 가져올수 있다.
	Constructor<?> constructor2 = clazz.getDeclaredConstructor(String.class);// 파라미터 값
	Constructor<?> constructor3 = clazz.getDeclaredConstructor(String.class,int.class);//두가지 타입의 파라미터 값을 가진 생성자 가져올수 있다.

	//생성자로 객체를 생성 
	//Object dog1 = constructor1.newInstance(); //하지만 생성자가 접근제어자라 private이라 접근이 불가
	
	//접근 제어자가 public이 아닌 경우 setAccessible 메소드를 이용하면 접근 할 숭있다.
	
	constructor1.setAccessible(true);
	Object dog1 =constructor1.newInstance();
	Object dog2 =constructor2.newInstance("호두");
	Object dog =constructor3.newInstance("호두",5);
	
	
	
	//필드 접근
	Field [] fields = clazz.getDeclaredFields();
	
	for(Field field : fields) {
		field.setAccessible(true);
		System.out.println(field);
		System.out.println(field.get(dog));
		System.out.println("------------------------");
	}
	
	//private 필드의 값도 변경 할 수 있다.
	Field field = clazz.getDeclaredField("name");
	field.setAccessible(true);
	System.out.println("기존:" + field.get(dog));
	field.set(dog, "땅콩");
	System.out.println("변경: " + field.get(dog));
	
	//필드에 정의 된 메소드 가져오기 
	Method[] methods = clazz.getDeclaredMethods();
	for(Method method : methods) {
		method.setAccessible(true);
		System.out.println(method);
		System.out.println("----------------------------");
	}
	Method method = clazz.getDeclaredMethod("speak", String.class ,int.class);
	method.setAccessible(true);
	method.invoke(dog, "멍멍!",5);
	
	 }
}
private static final java.lang.String main231.Dog.CATEGORY
동물
------------------------
private java.lang.String main231.Dog.name
호두
------------------------
public int main231.Dog.age
5
------------------------
기존:호두
변경: 땅콩
private void main231.Dog.speak(java.lang.String,int)
----------------------------
public int main231.Dog.getAgs()
----------------------------
public void main231.Dog.eate()
----------------------------
멍멍!멍멍!멍멍!멍멍!멍멍!

Class 객체에  필드(메소드,변수) 의 접근제어자와 메소드 이름 매개변수 타입을 알수 있다.

 

리플렉션이 사용되는 곳
-인텔리 제이의 자동 완성 기능 

궁금증?

 

리플렉션 왜 필요한가?

 

리플렉션으로 객체를 생성 할 수 있다고 했는데 생성자가 있음에도  기본 생성자가 꼭 필요한 이유?

:기본 생성자로 객체를 생성하고 필드를 통해 값을 넣어주는 것이 가장 간단한 방법이다. 

라이브러리나 , 프레임 워크가 어떤 생성자를  사용할지 고르기 어렵다.

생성자에 로직이 있는 경우 원하는 값을 필드에  바로 넣어 줄 수 없다. 

파라미터들의 타입이 같은 경우 필드와  이름이 다르면 값을 알맞게 넣어주기 힘들다.

기본 생성자를 사용할 경우 이 모든 경우의 수들을 고려하지 않아도된다.

(기본 생성자로 객체를 생성한 뒤 필드 이름에 맟줘 알맞은 값을 넣어주면 된다.)

 

 

어노테이션 

: 주석에 불과 해 보이지만 이것 또한도 리플렉션을 통해 가능하다.

 

  1. 리플렉션을 통해 클래스나 메소드, 파라미터 정보를 가져온다.
  2. 리플렉션의 getAnnotation(s) , getDeclaredAnnotation(s)등의 메소드를 통해 원하는 어노테이션이 붙어 있는지 확인한다.
  3. 어노테이션이 붙어 있다면 원하는 로직을 수행한다.

참고:https://steady-coding.tistory.com/609

 

[Java] Reflection 개념 및 사용 방법

java-study에서 스터디를 진행하고 있습니다. Reflection이란? 리플렉션은 힙 영역에 로드된 Class 타입의 객체를 통해, 원하는 클래스의 인스턴스를 생성할 수 있도록 지원하고, 인스턴스의 필드와 메

steady-coding.tistory.com

https://learn.microsoft.com/ko-kr/dotnet/standard/serialization/system-text-json/source-generation-modes?pivots=dotnet-7-0 

 

에서 리플렉션 또는 원본 생성을 선택하는 방법 System.Text.Json

에서 리플렉션 또는 원본 생성을 선택하는 방법을 알아봅니다 System.Text.Json.

learn.microsoft.com

 

 이해 안되는것 : 왜 생성자를 생성 해야 하는가?, 왜 꼭 리플렉션을 해야 하는가?, 리플렉션과 어노테이션은 무슨관계이며, json역직렬화 , 직렬화하고는 무슨 관계인가?,,,, 어떻게 스프링은 런타임시 di가 가능한가?

왜?new로 생성하면 안되는가?

'자바멘토링' 카테고리의 다른 글

리플렉션을 이용한 json 직렬화  (0) 2022.12.28
파일디스크립터  (0) 2022.12.18
Try - With - Resource  (0) 2022.12.04
추상클래스  (0) 2022.12.03
Weak Reference & Soft reference  (0) 2022.12.03