이어서!!!
🍱 말밥: 인보크 다이나믹이 뭐야?
자, 인보크 다이나믹(InvokeDynamic)은 자바의 "마술 도구" 같은 거야.
평소에 우리가 코드를 실행할 때, 자바는 "야, 이 메서드 찾아봐!" 하면서 메서드 호출 경로를 딱딱하게 정해둬.
그런데 인보크 다이나믹은 이렇게 고정된 호출 경로를 완전히 유연하게 만들어줘.
🍳 비유: 요리사의 비법
보통 요리사가 요리를 만들려면:
- **레시피(코드)**를 꺼내고,
- 그걸 따라 만들어야 해.
즉, 어떤 요리를 만들지는 처음부터 정해져 있는 거야.
하지만 인보크 다이나믹을 쓰면?
- 요리사가 즉석에서 레시피를 고를 수 있는 도구를 가진 것과 같아.
- "이 상황에 맞게 딱 알맞은 레시피를 찾아서 써!"라고 말할 수 있지.
이렇게 하면:
- **동적으로 적합한 레시피(메서드)**를 골라 쓰는 거라, 코드를 훨씬 유연하게 작성할 수 있어.
🛠️ 인보크 다이나믹이 실제로 뭐하는 건데?
- 자바의 invokedynamic 명령어는 자바 바이트코드에서 제공하는 기능으로, 동적 메서드 호출을 가능하게 만들어.
- 이를 통해 컴파일 타임에 고정된 메서드 호출 대신 런타임에 메서드를 결정할 수 있어.
🎩 어디에 쓰이는데?
- 람다 표현식
- 자바 8부터 람다 표현식을 지원하면서, 내부적으로 인보크 다이나믹을 활용해 람다를 효율적으로 구현했어.
- 과거에는 람다를 익명 클래스 형태로 구현했는데, 인보크 다이나믹 덕분에 더 가벼운 구현이 가능해짐.
- 동적 언어 지원 (JSR 292)
- 자바는 정적 타입 언어지만, JavaScript, Groovy, Kotlin 같은 동적 언어를 실행할 때도 사용돼.
- 동적 언어에서 "어떤 메서드를 호출할지" 런타임에 결정하는 데 인보크 다이나믹을 활용.
- 메서드 핸들(MethodHandle)
- 메서드 핸들은 Method 객체처럼 동적으로 메서드를 호출할 수 있는 자바의 유연한 도구야.
- invokedynamic 명령어와 함께 동작하며, 유연한 메서드 호출을 가능하게 해.
🛠️ 자바 코드 예제: 인보크 다이나믹과 람다
람다의 내부 동작을 통해 인보크 다이나믹을 엿볼 수 있어.
import java.util.function.Function;
public class LambdaExample {
public static void main(String[] args) {
Function<Integer, Integer> square = x -> x * x; // 람다 표현식
System.out.println(square.apply(5)); // 25
}
}
이 코드 내부적으로
- 람다 표현식은 인보크 다이나믹(invokedynamic) 명령어를 사용해서 처리돼.
- invokedynamic은 런타임에 필요한 구현체(레시피)를 동적으로 찾아서 호출해.
- 이렇게 하면 메모리 효율과 실행 속도가 크게 개선돼!
🛠️ 동적 메서드 호출 예제: MethodHandle
직접 메서드 핸들과 인보크 다이나믹을 사용한 동적 호출을 구현해보자
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class InvokeDynamicExample {
public static void main(String[] args) throws Throwable {
// 메서드 핸들 생성
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(String.class, String.class);
// Example 클래스의 sayHello 메서드 핸들 가져오기
MethodHandle handle = lookup.findStatic(Example.class, "sayHello", methodType);
// 메서드 핸들 호출 (동적으로!)
String result = (String) handle.invokeExact("World");
System.out.println(result); // Hello, World
}
}
class Example {
public static String sayHello(String name) {
return "Hello, " + name;
}
}
MethodHandles.Lookup lookup = MethodHandles.lookup();
- MethodHandles.Lookup 객체는 메서드 핸들을 조회하는 데 필요한 도구를 제공해.
- lookup() 메서드를 통해 현재 클래스에서 접근 가능한 메서드나 필드의 핸들을 찾을 수 있어.
- 즉, 여기서는 Example 클래스의 메서드를 동적으로 호출하기 위해 이 도구를 사용.
MethodType methodType = MethodType.methodType(String.class, String.class);
- MethodType은 호출하려는 메서드의 **시그니처(반환 타입과 파라미터 타입)**를 나타내.
- 여기서 String.class는 반환 타입이 String, 매개변수 타입도 String임을 나타냄.
- 즉, sayHello(String) 메서드의 시그니처를 정의한 것.
MethodHandle handle = lookup.findStatic(Example.class, "sayHello", methodType);
- findStatic은 정적 메서드를 위한 핸들을 찾아 반환.
- 첫 번째 인자: 호출할 메서드가 속한 클래스 (Example.class).
- 두 번째 인자: 호출할 메서드의 이름 ("sayHello").
- 세 번째 인자: 메서드의 시그니처(methodType).
- 이 라인을 통해 sayHello(String) 메서드의 핸들(참조)을 가져옴.
String result = (String) handle.invokeExact("World");
- invokeExact는 메서드 핸들을 사용해 메서드를 호출하는 방법.
- "World"는 sayHello 메서드의 매개변수로 전달되는 값.
- 이 호출은 Example.sayHello("World")와 동일하게 작동하지만, 핸들을 통해 동적으로 호출했기 때문에 컴파일 타임에 연결된 것이 아니라 런타임에 결정된 메서드를 호출한 것.
💡 설명:
- MethodHandle은 메서드 호출을 다루는 도구로, 런타임에 동적으로 메서드를 호출할 수 있어.
- invokedynamic 명령어가 이 동작을 지원하며, 정적인 호출 방식보다 더 유연하게 동작.
🚀 정리: FP, 람다, 일급 객체와 인보크 다이나믹
- 일급 객체:
- 함수처럼 데이터를 자유롭게 다루는 개념.
- 람다:
- 자바에서 함수를 일급 객체처럼 활용하기 위한 방법.
- 인보크 다이나믹 덕분에 효율적으로 구현.
- FP(함수형 프로그래밍):
- 함수 조합이 핵심이고, 람다와 일급 객체가 기반.
- 인보크 다이나믹:
- 자바의 바이트코드 수준에서 동적 메서드 호출을 지원.
- 람다, 동적 언어, 유연한 메서드 호출의 핵심 기술.
💡 핵심 요약
"람다와 FP가 쉽게 쓰일 수 있는 건, 인보크 다이나믹이라는 도구가 있어서 가능하다!"
'Java' 카테고리의 다른 글
추상 클래스 / 인터페이스 (0) | 2024.12.20 |
---|---|
캡슐화 (0) | 2024.12.17 |
파라미터 타입이 다른 공통 로직 모듈화 - 어댑터 패턴 (0) | 2024.12.11 |
파라미터 타입이 다른 공통 로직 모듈화 - 정적 팩토리 메서드 (0) | 2024.12.11 |
파라미터 타입이 다른 공통 로직 모듈화 - 제네릭 (0) | 2024.12.11 |