2025. 3. 12. 16:54ㆍ개발/개념 및 기법
1. 리플렉션(Reflection)이란?
리플렉션은 앱 실행 중에 클래스, 메서드, 속성 등의 정보를 동적으로 가져오거나 수정할 수 있는 기능이다.
즉, 코드가 자기 자신을 들여다보고 조작하는 능력.
(1) 리플렉션이 필요한 이유
- 런타임에서 클래스 정보를 조회해야 할 때 → 예를 들어, DI(의존성 주입) 같은 곳에서 객체 타입을 몰라도 생성해야 할 경우
- 코드 수정 없이 동적으로 메서드 호출 → 프레임워크에서 코드를 직접 수정하지 않고 기능을 확장할 때
- JSON 직렬화/역직렬화 → Gson, Moshi 같은 라이브러리가 리플렉션을 사용해서 객체를 변환
(2) 리플렉션 사용 예제
- 클래스 정보를 가져오기
import kotlin.reflect.full.*
data class User(val name: String, val age: Int)
fun main() {
val kClass = User::class // 클래스 정보 가져오기
println("클래스 이름: ${kClass.simpleName}")
val properties = kClass.memberProperties
println("프로퍼티 목록: $properties")
}
- 동적으로 프로퍼티 값 가져오기
import kotlin.reflect.full.memberProperties
data class Person(val name: String, val age: Int)
fun main() {
val person = Person("형님", 30)
val kClass = person::class
val nameProperty = kClass.memberProperties.find { it.name == "name" }
println("name 프로퍼티 값: ${nameProperty?.getter?.call(person)}")
}
- 동적으로 메서드 호출하기
import kotlin.reflect.full.functions
class Hello {
fun greet() = "안녕하세요, 형님!"
}
fun main() {
val hello = Hello()
val kClass = hello::class
val greetMethod = kClass.functions.find { it.name == "greet" }
println("메서드 호출 결과: ${greetMethod?.call(hello)}")
}
2. 리플렉션을 지원하는 언어
리플렉션(Reflection)은 모든 프로그래밍 언어에서 존재하는 건 아니다.
동적 타입이나 메타 프로그래밍이 지원되는 언어들에 한해서만 사용 가능하다.
(1) 리플렉션이 지원되는 대표적인 언어
- Kotlin - kotlin.reflect 패키지 사용
- Java - java.lang.reflect 패키지 사용
- Python - getattr(), type(), dir() 등으로 접근 가능
- C# - .NET에서 System.Reflection 사용
- Ruby - Object#methods, Object#instance_variables 등 활용 가능
- JavaScript - Object.keys(), Reflect API 등 사용
- Swift - Mirror API 활용 가능
이런 언어들은 런타임에서 클래스, 메서드, 속성 등을 확인하고 동적으로 조작할 수 있는 기능을 제공!!!
(2) 리플렉션이 지원되지 않거나 제한적인 언어
- C, C++ - 컴파일 타임에 구조가 고정되기 때문에 리플렉션 기능 없음
- Rust - 성능과 안전성 때문에 기본적으로 지원하지 않음 (serde 같은 라이브러리는 있음)
- Go - reflect 패키지가 있지만 타입 정보만 확인 가능 (메타프로그래밍 수준은 낮음)
이런 언어들은 정적으로 타입이 결정되며, 실행 중에 구조를 변경하는 기능이 거의 없음
3. 리플렉션 사용 시 주의할 점
(1) 성능 저하
리플렉션은 정적 코드보다 느리기 떄문에 앱의 성능이 중요한 곳에서는 자제해야 한다.
(2) 안드로이드 ProGuard 최적화 문제
난독화 설정 시 리플렉션을 사용하면 클래스 이름이 변경될 수 있어 문제가 발생한다.
- proguard-rules.pro 에 예외 추가 필요
(3) 보안 이슈
런타임에서 동적으로 클래스와 메서드를 호출하기 때문에 잘못된 접근이 발생할 가능성이 있다.
4. 리플렉션을 사용하는 이유
위와 같이 성능 저하와 복잡성 증가의 단점에도 불구하고 사용하는 이유는 무엇일까?
(1) 컴파일 타임에 알 수 없는 클래스를 다룰 때
예를 들어, 플러그인 시스템, DI(의존성 주입) 등에서 런타임에 동적으로 객체를 생성해야 하는 경우 사용한다.
(2) JSON → 객체 변환 (직렬화 & 역직렬화)
데이터를 네트워크에서 받아와야 하는데, 클래스를 미리 정의할 수 없는 경우,
Gson, Moshi 같은 JSON 파싱 라이브러리들이 리플렉션을 활용한다.
(3) 동적으로 메서드를 호출해야 할 때
특정 클래스에 어떤 메서드가 있는지 모르는 상황에서, 메서드 이름을 문자열로 받아 실행해야 할 때
리플렉션이 없으면 switch-case 같은 하드코딩을 해야 한다.
(4) 코드 수정 없이 확장성을 높일 때
플러그인 시스템, ORM 프레임워크, 동적 바인딩 같은 기능을 구현할 때 사용한다.
예를 들어, Room Database에서 @Entity 클래스를 자동으로 분석하는 기능도 리플렉션을 활용
리플렉션은 런타임에 클래스나 메서드를 동적으로 다룰 때 필수적인 기능이다.
하지만 성능 저하, 보안 이슈가 있어 남발하면 안된다.
'개발 > 개념 및 기법' 카테고리의 다른 글
[생존 매뉴얼] 작동하는 코드보다 더 무서운 건, 작동하는 줄 알고 넘어간 코드다. (0) | 2025.03.25 |
---|---|
보이지 않는 문자들의 연합: 유니코드 이야기 (1) | 2025.03.21 |
오버헤드(overhead)와 스택 오버플로우(Stack Overflow), 왜 발생하고 어떻게 해결할까? (0) | 2025.03.04 |
네트워크 API 통신할 때 suspend 함수 vs Flow (0) | 2025.02.19 |
KMP vs CMP (1) | 2025.01.25 |