Каковы различия между CapturingClass и ImplClass для Java SerializedLambda? - PullRequest
3 голосов
/ 28 апреля 2020

подпись SerializedLambda выглядит следующим образом:

SerializedLambda (класс capturingClass, String functionalInterfaceClass, String functionalInterfaceMethodName, String functionalInterfaceMethodSignature, внутр implMethodKind, String implClass, String implMethodName, String implMethodSignature, String instantiatedMethodType, Object [] capturedArgs)

Теперь я вижу, что класс захвата - один с deserializeLambda:

В SerializedLambda есть метод readResolve, который ищет (возможно, частные) данные c метод с именем $ deserializeLambda $ (SerializedLambda) в классе захвата, вызывает его в качестве первого аргумента

Но я не понял, для чего implClass.

Получить имя класса, содержащего метод реализации.

Разве класс захвата не является классом с методом реализации? Я попытался сериализовать лямбда-функции, чтобы увидеть, какие значения содержатся в этих полях, но у них был один и тот же класс. В чем разница между implClass и capturingClass?

1 Ответ

4 голосов
/ 28 апреля 2020

С текущими компиляторами лямбда-выражения всегда компилируются в синтетические c методы одного и того же класса, содержащие тело лямбда-выражения. Для этих лямбда-выражений класс захвата всегда идентичен «implClass».

Но для ссылки на метод, которая не требует вспомогательного метода, «implClass» будет классом объявления целевого метода, тогда как захват class - это класс, содержащий ссылку на метод.

Например, следующий пример

public class SerializedLambdaExample {
    public static void main(String[] args) throws ReflectiveOperationException {
        var hex = (IntFunction<String>&Serializable)Integer::toHexString;
        Method m = hex.getClass().getDeclaredMethod("writeReplace");
        m.setAccessible(true);
        SerializedLambda sl = (SerializedLambda)m.invoke(hex);
        System.out.println("cap: "+sl.getCapturingClass());
        System.out.println("target: "+sl.getImplClass()+" "+sl.getImplMethodName());
    }
}

печатает с HotSpot / OpenJDK / javac

cap: SerializedLambdaExample
target: java/lang/Integer toHexString

Но обратите внимание, что точная форма может зависеть от реализации. Для ссылок на методы некоторые конструкции, например, содержащие varargs или типы пересечений, могут быть скомпилированы с использованием вспомогательного метода, подобного лямбда-выражениям. Теоретически, лямбда-выражение, содержащее тривиальный вызов метода, может быть скомпилировано как ссылка на метод, или тело может быть помещено в другой класс, например, когда файл класса становится слишком большим, но на практике это не происходит с текущими компиляторами.

Кроме того, пример не гарантирует работу во всех средах выполнения. Это только для демонстрационных целей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...