← Назад к вопросам

Что такое хранение метода?

1.8 Middle🔥 51 комментариев
#JVM и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Хранение метода в Java (Method Handles)

Хранение метода (Method Handle) — это низкоуровневая типизированная ссылка на метод в Java, введённая в Java 7. Это более гибкий и производительный способ работать с методами по сравнению с рефлексией, хотя термин может также относиться к другим механизмам инокуляции методов.

Что это такое?

Метод Handle — это объект, который инкапсулирует информацию о методе и позволяет вызывать его динамически. Это альтернатива рефлексии с лучшей производительностью и типобезопасностью.

Основы Method Handles

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class MethodHandleExample {
    public String greet(String name) {
        return "Hello, " + name;
    }
    
    public static void main(String[] args) throws Throwable {
        // Получение Lookup объекта
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        
        // Получение Method Handle для экземплярного метода
        MethodType mt = MethodType.methodType(String.class, String.class);
        MethodHandle mh = lookup.findVirtual(
            MethodHandleExample.class,
            "greet",
            mt
        );
        
        // Вызов метода через Method Handle
        MethodHandleExample example = new MethodHandleExample();
        String result = (String) mh.invoke(example, "World");  // invoke - медленнее
        System.out.println(result);  // Hello, World
        
        // Или используй invokeExact для максимальной производительности
        String result2 = (String) mh.invokeExact(example, "Java");
        System.out.println(result2);  // Hello, Java
    }
}

Типы Method Handles

1. Для экземплярных методов:

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class InstanceMethodExample {
    public int add(int a, int b) {
        return a + b;
    }
    
    public static void main(String[] args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType mt = MethodType.methodType(int.class, int.class, int.class);
        MethodHandle mh = lookup.findVirtual(InstanceMethodExample.class, "add", mt);
        
        InstanceMethodExample instance = new InstanceMethodExample();
        int result = (int) mh.invokeExact(instance, 5, 3);
        System.out.println(result);  // 8
    }
}

2. Для статических методов:

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class StaticMethodExample {
    public static int multiply(int a, int b) {
        return a * b;
    }
    
    public static void main(String[] args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType mt = MethodType.methodType(int.class, int.class, int.class);
        MethodHandle mh = lookup.findStatic(StaticMethodExample.class, "multiply", mt);
        
        int result = (int) mh.invokeExact(5, 3);
        System.out.println(result);  // 15
    }
}

3. Для конструкторов:

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class ConstructorExample {
    private String name;
    
    public ConstructorExample(String name) {
        this.name = name;
    }
    
    public static void main(String[] args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType mt = MethodType.methodType(void.class, String.class);
        MethodHandle mh = lookup.findConstructor(ConstructorExample.class, mt);
        
        ConstructorExample instance = (ConstructorExample) mh.invokeExact("MyName");
        System.out.println(instance.name);  // MyName
    }
}

Сравнение: Рефлексия vs Method Handles

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;

public class PerformanceComparison {
    public int calculate(int a, int b) {
        return a + b;
    }
    
    public static void main(String[] args) throws Exception {
        PerformanceComparison obj = new PerformanceComparison();
        int iterations = 1_000_000;
        
        // 1. Рефлексия (медленнее)
        Method method = PerformanceComparison.class.getMethod("calculate", int.class, int.class);
        long startReflection = System.nanoTime();
        for (int i = 0; i < iterations; i++) {
            method.invoke(obj, 5, 3);
        }
        long timeReflection = System.nanoTime() - startReflection;
        System.out.println("Reflection time: " + timeReflection + " ns");
        
        // 2. Method Handles (быстрее)
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType mt = MethodType.methodType(int.class, int.class, int.class);
        java.lang.invoke.MethodHandle mh = lookup.findVirtual(
            PerformanceComparison.class,
            "calculate",
            mt
        );
        long startMH = System.nanoTime();
        for (int i = 0; i < iterations; i++) {
            mh.invokeExact(obj, 5, 3);
        }
        long timeMH = System.nanoTime() - startMH;
        System.out.println("Method Handle time: " + timeMH + " ns");
        
        System.out.println("Speedup: " + (timeReflection / (double) timeMH) + "x");
    }
}
// Результат: Method Handles примерно в 10-50 раз быстрее рефлексии

Bind и Curry (частичное применение)

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class BindExample {
    public int add(int a, int b) {
        return a + b;
    }
    
    public static void main(String[] args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType mt = MethodType.methodType(int.class, int.class, int.class);
        MethodHandle mh = lookup.findVirtual(BindExample.class, "add", mt);
        
        BindExample obj = new BindExample();
        
        // Bind - привязываем объект
        MethodHandle boundMH = mh.bindTo(obj);
        
        // Теперь вызываем без передачи объекта
        int result = (int) boundMH.invokeExact(5, 3);
        System.out.println(result);  // 8
    }
}

Method Handle Transformations

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class TransformationExample {
    public int getValue() {
        return 42;
    }
    
    public static void main(String[] args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType mt = MethodType.methodType(int.class);
        MethodHandle mh = lookup.findVirtual(TransformationExample.class, "getValue", mt);
        
        TransformationExample obj = new TransformationExample();
        MethodHandle boundMH = mh.bindTo(obj);
        
        // Создаём новый Method Handle с дополнительным параметром (не используется)
        MethodHandle dropFirst = MethodHandles.dropArguments(
            boundMH,
            0,  // позиция
            String.class  // тип параметра, который игнорируем
        );
        
        int result = (int) dropFirst.invokeExact("ignored");
        System.out.println(result);  // 42
    }
}

Практическое применение: Стратегия вызова методов

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.HashMap;
import java.util.Map;

public class StrategyDispatcher {
    private final Map<String, MethodHandle> handlers = new HashMap<>();
    
    public void register(String key, Object object, String methodName) throws Exception {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType mt = MethodType.methodType(void.class);
        MethodHandle mh = lookup.findVirtual(
            object.getClass(),
            methodName,
            mt
        );
        handlers.put(key, mh.bindTo(object));
    }
    
    public void dispatch(String key) throws Throwable {
        MethodHandle handler = handlers.get(key);
        if (handler != null) {
            handler.invokeExact();
        }
    }
}

// Использование
class EventHandler {
    public void onStart() { System.out.println("Started"); }
    public void onStop() { System.out.println("Stopped"); }
}

public class Demo {
    public static void main(String[] args) throws Exception {
        StrategyDispatcher dispatcher = new StrategyDispatcher();
        EventHandler handler = new EventHandler();
        
        dispatcher.register("start", handler, "onStart");
        dispatcher.register("stop", handler, "onStop");
        
        dispatcher.dispatch("start");  // Started
        dispatcher.dispatch("stop");   // Stopped
    }
}

Когда использовать Method Handles

  • Критична производительность при динамическом вызове методов
  • Большое количество вызовов одного и того же метода
  • Фреймворки и библиотеки (Spring, Hibernate используют их внутри)
  • Обработка событий с множественными handlers
  • Динамическая генерация кода и lambda-выражения

Итоги

  • Method Handles — это типизированные, производительные ссылки на методы
  • Быстрее рефлексии в 10-50 раз
  • Более гибкие чем методы, но безопаснее чем eval
  • Используются в основе для лямбд (Java 8+) и invoke динамики
  • Лучший выбор для высоконагруженных систем, требующих динамичности
Что такое хранение метода? | PrepBro