📖
Kyu9's Repo
  • Library of mameil
  • 이슈 경험
    • 20230220_트랜잭션
    • 20230306_캐싱이슈
    • 20230722_테스트코드에서 @Transactional
    • 20230807_deadlock
  • 인턴 스터디
    • Gradle
    • Stream, Optional, 람다식
    • JVM의 메모리 구조, Garbage Collector
    • RESTful API
    • Microservice Architecture
    • HTTP
    • 웹서버란 무엇인가
    • Git Branch
    • TDD
    • Redis을 이용한 캐시
    • Thymeleaf
    • 정리가 필요한 자료들
    • SpringBoot Management
    • 테스크 코드 분할
  • 동아리 스터디
    • 기본 SQL 공부
      • SQL의 기본 개념
      • SELECT 문장을 이용하여 원하는 데이터 출력하기
        • 집합 연산자 사용하기
        • where절에 비교 연산자를 사용해보기
        • SELECT_EX
        • 산술 연산자 사용해보기
      • 단일 행 함수 사용
        • lower/upper 함수 사용하기
        • length함수 사용하기
        • concat함수 사용
        • substr/mid/substring 함수 사용
        • instr함수 사용하기
        • lpad/rpad 함수 사용하기
        • trim/ltrim/rtrim 함수 사용하기
        • replace 함수 사용하기
        • round 함수 사용하기
        • truncate 함수 사용하기
        • mod함수 사용하기
        • ceil함수 사용하기
        • floor함수 사용하기
        • power 함수 사용하기
        • Date fn(날짜 함수)
        • 형 변환 함수
        • 일반함수란
    • a-ha 실습
    • 혼자서 만들어본 게시판
    • AWS 강의
  • 학교 나머지 공부 자료
    • 웹프레임워크(Spring)
      • Spring이란?
      • Webframework1-1
      • Webframework1-2
      • SpringBoot의 특징
      • SpringBoot 생성 방법
      • Spring Data JPA
      • SpringBoot Security
      • SpringBoot HATEOAS
  • 공부 자료들
  • WS 온라인 자바 스터디
    • Week1(JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.)
    • Week2(자바 데이터 타입, 변수 그리고 배열)
    • Week3(연산자)
    • Week4(제어문)
    • Week5(클래스)
    • Week6(상속)
    • Week7(패키지)
    • Week8(인터페이스)
    • Week9(예외처리)
    • Week10(멀티쓰레드 프로그래밍)
    • Week11(Enum)
    • Week12(Annotation)
    • Week13(I/O)
    • Week14(Generic)
    • Week15(람다식)
  • 백준문제
    • 입출력과 사칙연산
      • We love kriii(10718)
      • 고양이(10171)
      • 개(10172)
      • A+B(1000)
      • A-B(1001)
      • AxB(10998)
      • A/B(1008)
      • 사칙연산(10869)
      • 나머지(10430)
      • 곱셈(2588)
    • for문
      • 구구단(2739)
      • A+B - 3(10950)
      • 합(8393)
      • 빠른 A+B(15552)
      • N 찍기(2741)
      • 기찍 N(2742)
      • A+B - 7(11021)
      • A+B - 8(11022)
      • 별 찍기 - 1(2438)
      • 별 찍기 - 2(2439)
      • X보다 작은 수(10871)
    • if문
      • 두 수 비교하기(1330)
      • 시험 성적(9498)
      • 윤년(2753)
      • 사분면 고르기(14681)
      • 알람 시계(2884)
      • 오븐 시계(2525)
      • 주사위 세개(2480)
      • 영수증(25304)
    • While문
      • A+B - 5(10952)
      • A+B - 4(10951)
      • 더하기 사이클(1110)
    • 1차원 배열
      • 최소, 최대(10818)
      • 최댓값(2562)
      • 숫자의 개수(2577)
      • 나머지(3052)
      • 평균(1546)
      • OX퀴즈(8958)
      • 평균은 넘겠지(4344)
    • 함수
      • 정수N개의 합(15596)
      • 셀프 넘버(4673)
      • 한수(1065)
    • 문자열
      • 아스키코드(11654)
      • 숫자의 합(11720)
      • 알파벳 찾기(10809)
      • 문자열 반복(2675)
      • 단어 공부(1157)
      • 단어의 개수(1152)
      • 상수(2908)
      • 다이얼(5622)
      • 크로아티아 알파벳(2941)
      • 그룹 단어 체커(1316)
    • 기본수학-1
      • 손익분기점(1712)
      • 벌집(2292)
      • 분수찾기(1193)
      • 달팽이는 올라가고 싶다(2869)
      • ACM 호텔(10250)
      • 부녀회장이 될테야(2775)
      • 설탕 배달(2839)
      • 큰 수 A+B(10757)
      • Fly me to the Alpha Centauri(1011)
    • 기본수학-2
      • 소수 찾기(1978)
      • 소수(2581)
      • 소인수분해(11653)
      • 소수 구하기(1929)
      • 베르트와 공존(4948)
    • 재귀
      • 하노이 탑 이동 순서(11729)
      • 피보나치 수 5(10870)
      • 별 찍기(2447)
    • 브루트 포스
      • 블랙잭(2798)
      • 분해합(2231)
      • 덩치(7568)
      • 체스판 다시 칠하기(1018)
      • 영화감독 슘(1436)
    • 집합과 맵
      • 숫자 카드(10815)
      • 문자열 집합(14425)
      • 숫자 카드2(10816)
      • 듣보잡(1764)
      • 대칭 차집합(1269)
      • 서로 다른 부분 문자열 갯수(11478)
    • 정렬
      • 수 정렬하기(2750)
      • 수 정렬하기 2(2751)
      • 수 정렬하기 3(10989)
      • 통계학(2108)
      • 소트인사이드(1427)
      • 좌표 정렬하기(11650)
      • 좌표 정렬하기2(11651)
      • 단어 정렬(1181)
      • 나이순 정렬(10814)
      • 커트라인(25305)
      • 좌표압축(18870)
    • 백트래킹
      • N과 M - 1(15649)
      • N과 M - 2(15650)
      • N과 M - 3(15651)
      • N과 M - 4(15652)
      • N-Queen(9663)
      • 스도쿠(2580)
      • 연산자 끼워넣기(14888)
      • 스타트와 링크(14889)
    • 이분 탐색
      • 수 찾기(1920)
    • 동적계획법
      • 피보나치 함수(1003)
      • 신나는 함수 실행(9184)
      • 01타일(1904)
      • 파도반 수열(9461)
      • RGB거리(1149)
      • 정수 삼각형(1932)
      • 계단 오르기(2579)
      • 1로 만들기(1463)
      • 쉬운 계단 수(10844)
      • 포도주 시식(2156)
      • 가장 긴 증가하는 부분 수열(11053)
      • 가장 긴 바이토닉 부분 수열(11504)
      • 전깃줄(2565)
      • LCS(9251)
      • 연속합(1912)
      • 평범한 배낭(12865)
      • 더하기(9095)
    • DFS와 BFS
      • 미로탐색(2178)
      • 바이러스(2606)
      • DFS와 BFS(1260)
      • 단지번호붙이기(2667)
      • 전쟁 - 전투(1303)
      • 숨바꼭질(1697)
      • 데스 나이트(16948)
      • 나이트의 이동(7562)
      • 녹색 옷 입은 애가 젤다지?(4485)
      • 음식물 피하기(1743)
      • A->B (16953)
      • 숨바꼭질 3(13549)
      • 숨바꼭질 2(12851)
    • 구현
      • 치즈(2636)
  • 프로그래머스 문제
    • SQL
      • Animal Table - Oracle
      • Animal Table - MySQL
      • Animal Table2 - Oracle
      • Animal Table 3,4 - Oracle
    • Lv1
      • 두 개 뽑아서 더하기
      • 제일 작은 수 제거하기
      • 문자열 내 p와 y의 개수
      • 예산
      • 자릿수 더하기
      • 두 정수 사이의 합
      • 같은 숫자는 싫어
      • 가운데 글자 가져오기
      • 수박수박수박수박수박수?
      • 나누어 떨어지는 숫자 배열
      • 2016년
      • 폰캣몬
      • 서울에서 김서방 찾기
      • 문자열을 정수로 바꾸기
      • 소수 만들기
      • 문자열 다루기 기본
      • 소수 찾기(에라토스테네스의 체)
      • 숫자 문자열과 영단어
      • 이상한 문자 만들기
      • 없는 숫자 더하기
      • 문자열 내림차순으로 배치하기
      • 문자열 내 마음대로 정렬하기
      • 약수의 개수와 덧셈
      • 콜라츠 추측
      • 자연수 뒤집어 배열로 만들기
      • 신규 아이디 추천
      • 비밀지도
      • 크레인 인형뽑기 게임
      • 실패율
      • 로또의 최고 순위와 최저 순위
      • 키패드 누르기
      • 정수 내림차순으로 배치하기
    • Lv2
      • 행렬의 곱셈
      • 영어 끝말잇기
      • 영어 끝말잇기
      • N개의 최소 공배수
      • 피보나치 수
      • 124 나라의 숫자
      • 짝지어 제거하기
      • 프린터
      • 다음 큰 숫자
      • 최댓값과 최솟값
      • 최소값 만들기
      • 숫자의 표현
      • JadenCase 문자열 만들기
      • 오픈채팅방
      • 영어 끝말잇기
      • 멀쩡한 사각형
      • 올바른 괄호
      • 위장
      • 기능개발
      • 더 맵게
      • 스킬트리
    • 완전탐색
      • 모의고사(Lv1)
      • 카펫(Lv2)
      • 소수 찾기(Lv2)
    • 정렬(Sorting)
      • K번째 수(Lv1)
      • 가장 큰 수(Lv2)
      • H-Index(Lv2)
    • 해시(Hash)
      • 완주하지 못한 선수(Lv1)
      • 전화번호 목록(Lv2)
    • 탐욕법(Greedy)
      • 체육복(Lv1)
      • 큰 수 만들기(Lv2)
      • 구명보트(Lv2)
    • 동적계획법(DP)
      • 정수 삼각형(Lv3)
    • 깊이/너비 우선 탐색(DFS/BFS)
      • 타겟 넘버(Lv2)
      • 네트워크(Lv3)
      • 단어 변환(Lv3)
  • 스프링부트 책
    • Day 1
    • Day 2
    • Day 3
    • Day 4
    • Day 5
    • Day 6
    • Day 7
    • Day 8
    • Day 9
    • Day 10
    • Day 11
    • Day 12
    • Day 13
    • Day 14
    • Day 15
    • Day 16
    • Day 17
  • JPA 책
    • 프로젝트 세팅 및 기본설정
    • 영속성 관리 개념
    • 엔티티 매핑
      • 실습 예제
    • 연관관계 매핑 기초
      • 실습 예제
    • 다양한 연관관계 매핑
      • 다대일, 일대다 관계
      • 일대일, 다대다 관계
      • 실습 예제
    • 고급 매핑
      • 상속 관계 매핑
      • @MappedSuperclass
      • 복합 키와 식별 관계 매핑
      • 조인 테이블
    • 프록시와 연관관계 관리
      • 프록시
      • 즉시 로딩과 지연 로딩
      • 영속성 전이, 고아 객체
    • 값 타입
      • 임베디드 타입
      • 값 타입과 불변 객체
      • 값 타입의 비교, 컬렉션
    • 객체지향 쿼리 언어
      • JPQL part1
      • JPQL part2
      • JPQL part3
      • QueryDSL
      • NativeSQL
      • 객체지향 쿼리 심화
    • 응용 애플리케이션
      • 엔티티 설정
    • 스프링 데이터 JPA
      • 공통 인터페이스
  • Kotlin In Action
    • 코틀린의 특징
    • 코틀린의 기초
    • 함수 정의와 호출
    • 클래스, 객체, 인터페이스
    • 람다 방식
    • 코틀린 타입 시스템
    • 연산자 오버로딩과 기타 관례
    • 고차함수
    • 제네릭스
    • 애노테이션과 리플렉션
    • 코루틴
  • Oracle
    • Oracle 기본
    • Oracle 심화
  • SQL_연습
    • Revising the Select Query
    • Basic Select
    • Advanced Select
    • Basic Select 2
  • SQL 첫걸음(책)
    • Day 1
    • Day 2
    • Day 3
    • Day 4
    • Day 5
    • Day 6
    • Day 7
    • Day 8
    • Day 9
    • Day 10
    • Day 11
    • Day 12
    • Day 13
    • Day 14
    • Day 15
    • Day 16
    • Day 17
    • Day 18
    • Day 19
    • Day 20
    • Day 21
    • Day 22
    • Day 23
    • Day 24
    • Day 25
    • Day 26
    • Day 27
    • Day 28
    • Day 29
    • Day 30
  • 더 자바 코드를 조작하는 다양한 방법
    • JVM 이해하기
    • 바이트코드 조작
    • 리플렉션
    • 다이나믹 프록시
    • 애노테이션 프로세서
  • 더 자바, 애플리케이션을 테스트하는 다양한 방법
    • JUnit5
    • Mockito
    • 도커와 테스트
    • 성능, 운영이슈, 아키텍처 테스트
  • 이펙티브 자바
    • item1 - 생성자 대신 정적 팩토리 메소드를 고려하라
    • item2 - 생성자에 매개변수가 많다면 빌더를 고려하라
    • item3 - 생성자나 열거타입으로 싱글턴임을 보증하라
    • item4 - 인스턴스화를 막기 위해선 private 생성자를 사용하라
    • item5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
    • item6 - 불필요한 객체 생성을 피하라
    • item7 - 다 쓴 객체 참조를 해제하라
    • item8 - finalizer와 cleaner 사용을 피하라
    • item9 - try-finally 보다 try-with-resources을 사용하라
    • item10 - equals는 일반 규약을 지켜 재정의하라
    • item11 - equals을 재정의하려면 hashCode도 재정의하라
    • item12 - toString을 항상 재정의하라
    • item13 - clone 재정의는 주의해서 진행하라
    • item14 - Comparable을 구현할지 고민하라
  • Elastic Search
    • 강의 Summary
    • Elastic Summary 개념 정리
    • Elastic Summary 적용 정리
  • 토비의 스프링 강의
    • 스프링부트 살펴보기
    • 독립 실행형 서블릿 애플리케이션
  • k8s
    • minikube 설치
    • jenkins 추가
  • Article
    • Choosing the Right MessageBroker
Powered by GitBook
On this page
  • Java Reflection?
  • 클래스의 정보 조회
  • 애노테이션과 리플렉션
  • 클래스 정보 수정
  • 정리

Was this helpful?

  1. 더 자바 코드를 조작하는 다양한 방법

리플렉션

Java Reflection?

리플렉션은 투영이라는 의미를 가진 단어이고 유추하기 힘들수도 있지만 이 API들의 의미는 클래스의 정보를 사용자에게 뱉어주는 그러한 기능을 가진 함수들이다

사실 클래스를 만드는데 있어서 클래스를 만드는데 이걸 모를 일은 그렇게 많을 것 같지는 않다 하지만 무언가를 만들다보면 클래스에 대한 정보를 요하는 경우가 있다

실제로 과거에 클래스 자체에 대한 정보는 아니더라도 해당 클래스에 선언되어 있는 필드들을 찾을 일이 있었다 그때는 이러한 기능? API? 가 있는줄도 모르고 정말 무식하게 접근했던 것 같다 그때는 진짜 클래스적고 점찍고 뭔 함수가 있나... 이건뭐지... 쓰고 실행해서 결과확인하고 이러한 과정을 통하다보니 클래스.getDeclaredFields() 이런거에서 값이 나오는 것을 보고 찾아서 사용하곤 했었다 아무튼 이렇게 결국은 언젠가 사용할 떄가 올 수 도 있다는 점을 기억해서 이렇게 조금이라도 남겨두려고 한다

클래스의 정보 조회

클래스를 정보를 가져오기 위해서는 해당 클래스의 인스턴스를 먼저 가져오고 객체로 만들어줘야 한다 클래스 객체에 생성, 접근하는 방법은 일단 크게 2가지가 있다

//1
Class<클래스> exClass1 = 클래스.class;

//2
클래스 exClass = new 클래스(); 
Class<? extends 클래스> exClass2 = exClass.getClass();

요런식으로 객체로 생성하는 것이 가능하다 첫 번째 방식은 바로 그냥 클래스의 인스턴스를 통해서 가져오는 방식이고, 두 번째 방식은 해당 클래스 객체를 만들어둔 상태에서 그 객체를 통해서 클래스에 접근하는 방식이다

이외에도 클래스를 클래스의 경로와 이름까지 알고 있다면 경로를 통해서 가져오는 것도 가능하다

Class<?> exClass3 = Class.forName("경로.경로.경로.클래스");

이렇게도 가져올 수 있는데 src/main/java 부터니까 그건 주의하고 사용하자

이렇게 클래스에 접근하는 방법을 알았으니 접근해서 사용할 수 있는 것들을 보자

일단 클래스를 가져왔으면 클래스 내부에 선언되어 있는 필드들에 접근할 수 있다

Fields[] fieldArr = exClass2.getFields();
Fields[] fieldArrAll = exClass2.getDeclaredFields();

하지만 .getFields()로 가져온 배열을 막상 보면, public으로 선언되어 있는 필드만 나오게 된다 근데 사실 적어도 클래스에 선언된 모든 필드가 나와야 뭘 구별하고 하지 않겠니 그럴때 사용하는게 .getDeclaredFields()이다 요걸 사용하게 되면 해당 클래스에 선언된 모든 필드가 촤라락 뽑혀나온다 하지만 .getDeclaredFields()을 통해서 뽑은 필드에서 private이나 protected에 막상 접근하려고하면 막 접근 Exception이 떨궈질 수 있다 그럴때는 해당필드.setAccessible(true) 요 함수를 통해서 뽑은 Field객체에 접근할 수 있게 해주면 좋다

필드 이외에도, getMethods(), getConstructors(), getSuperClass(), getInterfaces() 등을 통해서 해당 클래스 내부에 있는 모든 메소드, 생성자, 부모클래스, 인터페이스 등에 접근하는 것이 가능하다

그리고 이렇게 클래스와 관련된 값들을 가져오는 함수들에 모두 빈값을 주게되면 모든 필드를 가져오게 되지만 특정 이름을 적어주면 해당 이름을 가진 특정 값를 가져오게 된다

이렇게 가져온 값들에 대한 특징들도 확인하는 것이 가능하다 값을 위의 다양한 메소드들을 통해서 가져왔을 때 .getModifiers()을 통해서 int 타입으로 Modifier를 받을 수 있다 그리고 int타입으로 받은 modifier에 대한 값을 확인하는 방법은 Modifier.isPrivate(받은 int값) 이나 Modifier.isStatic(받은 int값) 등을 통해서 진행하능 다양하게 있으니까 원하는 건 찾아서 적용하자

애노테이션과 리플렉션

애노테이션을 우리가 알고 자주 사용하는 @이름 이러한 형태를 가지고 있다 또한 이것은 제공해주는 것을 사용하는 것 뿐만 아니라 따로 '생성'하고, 기능을 커스텀하며 '사용'하는 것이 가능하다

근데 여기서 신기한 점은 위에서 사용했었던 리플렉션과 같은 클래스에도 .getAnnotations()가 있는데 이놈을 단순하게 생성만 해둔 애노테이션을 가져오기 위해서 사용해보며 실제로 나오지는 않는다 왜? -> 우선, 애노테이션은 근본적으로는 주석과 같은 것을 간주, 수행하지만 단순한 주석 기능보다는 원하는 커스텀 기능을 넣을 수 있다는 점이 특별한 점이다 -> 그래서 왜 단순히 애노테이션을 만들고 붙혀도 왜 안나오냐? getAnnotation()은 런타임시에 호출되며, 단순히 선언만한 애노테이션에 언제 사용될 것인지에 대한 추가가 있어야 사용할 수 있다

@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.FIELD})
public @interface TestAnnotation {
    String test1() default "TEST";
    String test2();
}

이렇게 사용하는데, @Retention은 애노테이션의 생명주기를 관리해주는 애노테이션이다. 즉, 언제 사용할 수 있게 할 것인지 정하는 그런 애노테이션이다 여기서 사용한 CLASS라는 정책은, 애노테이션을 단순하게 바이트코드에서 확인할 수 있는 수준으로만 정의해두고 런타임에서는 버려지는 메모리할당 정책이다 만약에 실제로 애노테이션을 만들어서 DI를 수행하고 싶다면 왠만하면 RUNTIME 정책을 채택해서 사용하는 것이 편하다 그리고 @Target 애노테이션은 해당 애노테이션이 어떠한 위치에서 사용될 수 있는지를 정해주는 애노테이션이다 위 예시 같은 경우에는 field에다가 추가했기 떄문에 그 의미는 오직 필드에서만 사용할 수 있게 해주는 그러한 능력이다

애노테이션 내부에는 값들을 넣어줄 수 있는데, 여기에는 primitive 타입과, boxing된 reference 타입 그리고 리스트등 다양한 타입을 가진 것들이 들어갈 수 있다 하지만 특별한 점은 필드를 선언하는데 있어서 우리가 기존에 선언하는 것과는 달리 ()을 붙혀서 함수를 만드는 것 처럼 비슷하게 만들어햐 한다 그리고 위에서 본 것 처럼 ()뒤에 default 을 넣어줘야 한다 default를 넣어주지 않는다면, 애노테이션을 선언해줄 때 @TestAnnotation(test2 = "qwer") 이렇게 선언해주지 않은 값들에 대해서 넣어줘야 한다 만약에 애노테이션 내부에 필드를 선언할 때 있어서 value()라는 이름을 가진 함수가 있다면 따로 애노테이션 선언 시, 이름을 지정해서 정해줄 필요는 없다

이러한 식으로 애노테이션을 선언하고 -> 이제는 해당 클래스에 선언되어있고 사용되고 있는 애노테이션들을 getAnnotation()을 사용해서 가져오고 해당 애노테이션을 타입으로 가지는 객체를 생성해서 .fieldName()을 통해서 애노테이션 내부에 선언되어 있는 값들을 가지고 조작하는 것이 가능하다

클래스 정보 수정

어떠한 객체를 생성하는 방식으로 생각해보면 일단 본인이 떠오르는 건 단순하게 new 키워드를 통해서 인스턴스를 생성하는 것밖에 아는 것이 없다 하지만 그런 방식 이외에도 위에서 배운 리플렉션 api를 사용해서 객체를 생성하는 것도 가능하다

        Class<?> aClass = Class.forName("me.kyu9.java8to11.Progress");
        Constructor<?> constructor = aClass.getConstructor();
        Progress progress = (Progress) constructor.newInstance();

이렇게 생성자를 가져오고, 생성자의 newInstance 함수와 해당 클래스로의 형변환을 통해서 객체를 생성하는 것이 가능하다

이렇게 객체를 가져온 이후에, 필드 이외에도 메소드를 가져오는 것 또한 가능하다 그 방법으로는 getDeclaredMethod를 통해서 가져올 수 있으며 이 함수를 사용할때는 reference 타입과 primitive 타입을 구분한다 가져온 메소드의 접근지정자를 만약에 private으로 정해져 있다면, .setAccessible()을 통해서 수정하는 것이 가능하며 .invoke()을 통해서 해당 메소드의 내부 기능을 수행시키는 것이 가능하다 그리고 invoke()를 수행하게 되면, Object타입으로 리턴되기 때문에 형변환 해야한다

정리

리플렉션은 뭔가 매우 강력하면서도 클래스 자체에 대한 api이기 때문에 무거운? 그러한 api라고 생각한다 이 것들은 정말 많은 곳들에서 사용하고 있다. 스프링에서도 DI를 하는데 있어서 사용한다고 한다 또한 특정한 뷰에서 값이 넘어올 때 넝어온 값을 객체로 바인딩하는데도 사용 하지만 이것의 문제는 컴파일 시점에서는 에러가 나오지는 않으며 런타임 시점에 에러가 나오는 문제를 만들 수도 있다는 점이 있다 물론 위에서 무겁고 뭐 런타임시에만 발견되는 문제를 만들 수도 있다 이러한 문제점들은 충분한 이해가 없는 경우에 나타나기 때문에 사용할 때는 충분한 이해와 테스트를 거치고 사용하자 그리고 또 문제가 있다면 setAccessible 통해서 접근 지시자를 무시하고 사용하는 것이 가능하기 때문에 캡슐화의 법칙을 위반하는 경우가 생길 수도 있다는 점 이렇게 자바의 내부적인 값에 접근하고, 사용하는 것은 정말 좋은 지식이고 활용도 높으며 프레임워크를 이해하는데도 좋은 용도라고 생각한다 실제로 사용할 때는 그래도 충분한 이해를 가지고 사용할 수 있도록 하자

Previous바이트코드 조작Next다이나믹 프록시

Last updated 3 years ago

Was this helpful?