Spec-Zone.ru › OpenJDK 24

Интерфейс InvocationHandler

Все известные реализующие классы:
CompositeDataInvocationHandler, EventHandler, MBeanServerInvocationHandler, RemoteObjectInvocationHandler
public interface InvocationHandler
InvocationHandler — это интерфейс, реализуемый обработчиком вызовов экземпляра прокси.

Каждый экземпляр прокси имеет связанный с ним обработчик вызовов. Когда метод вызывается на экземпляре прокси, вызов метода кодируется и передаётся методу invoke его обработчика вызовов.

С:
1.3
См. также:
  • Proxy

Краткое описание методов

Модификатор и тип Метод Описание
Object invoke(Object proxy, Method method, Object[] args)
Обрабатывает вызов метода на экземпляре прокси и возвращает результат.
static Object invokeDefault(Object proxy, Method method, Object... args)
Вызывает указанный метод по умолчанию на данном экземпляре proxy с заданными параметрами.

Подробное описание методов

invoke

Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Обрабатывает вызов метода на экземпляре прокси и возвращает результат. Этот метод будет вызван обработчиком вызовов, когда метод вызывается на экземпляре прокси, с которым он ассоциирован.
Параметры:
proxy - экземпляр прокси, на котором был вызван метод
method - экземпляр Method, соответствующий методу интерфейса, вызванному на экземпляре прокси. Класс-объявитель объекта Method будет интерфейсом, в котором был объявлен метод, который может быть суперинтерфейсом интерфейса прокси, который класс прокси наследует через метод.
args - массив объектов, содержащий значения аргументов, переданных в вызов метода на экземпляре прокси, или null, если метод интерфейса не принимает аргументов. Аргументы примитивных типов упаковываются в экземпляры соответствующего класса обёртки примитивных типов, таких как java.lang.Integer или java.lang.Boolean.
Возвращает:
значение, которое должно быть возвращено из вызова метода на экземпляре прокси. Если объявленный тип возвращаемого значения метода интерфейса — примитивный тип, то значение, возвращаемое этим методом, должно быть экземпляром соответствующего класса обёртки; в противном случае — типом, присваиваемым объявленному типу возвращаемого значения. Если значение, возвращаемое этим методом, равно null, а тип возвращаемого значения метода интерфейса — примитивный, то метод вызова на экземпляре прокси бросит исключение NullPointerException. Если возвращаемое значение несовместимо с объявленным типом возвращаемого значения метода интерфейса, как описано выше, метод вызова на экземпляре прокси бросит исключение ClassCastException.
Исключения:
Throwable - исключение, которое следует бросить из вызова метода на экземпляре прокси. Тип исключения должен быть присваиваем либо любому из типов исключений, объявленных в разделе throws метода интерфейса, либо исключениям без проверки типа java.lang.RuntimeException или java.lang.Error. Если этим методом брошено проверяемое исключение, которое не присваивается ни одному из типов исключений, объявленных в разделе throws метода интерфейса, то будет брошено исключение UndeclaredThrowableException, содержащее исключение, которое было брошено этим методом.
См. также:
  • UndeclaredThrowableException

invokeDefault

static Object invokeDefault(Object proxy, Method method, Object... args) throws Throwable
Вызывает указанный метод по умолчанию на данном экземпляре proxy с заданными параметрами. Указанный method должен быть методом по умолчанию, объявленным в интерфейсе прокси класса proxy или унаследованным от его суперинтерфейса непосредственно или косвенно.

Вызов этого метода ведёт себя так, как будто invokespecial выполняется из класса прокси, нацеливаясь на метод по умолчанию в интерфейсе прокси. Это эквивалентно вызову: X.super.m(A* a) где X — интерфейс прокси, а вызов X.super::m(A*) резолвится на данный method.

Примеры: интерфейс A и B оба объявляют реализацию метода по умолчанию m. Интерфейс C расширяет A и наследует метод по умолчанию m от своего суперинтерфейса A.


 interface A {
     default T m(A a) { return t1; }
 }
 interface B {
     default T m(A a) { return t2; }
 }
 interface C extends A {}
 
Следующий код создаёт экземпляр прокси, реализующий A, и вызывает метод по умолчанию A::m.

 Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { A.class },
         (o, m, params) -> {
             if (m.isDefault()) {
                 // if it's a default method, invoke it
                 return InvocationHandler.invokeDefault(o, m, params);
             }
         });
 
Если экземпляр прокси реализует как A, так и B, оба из которых предоставляют реализацию по умолчанию метода m, обработчик вызовов может направить вызов метода в A::m или B::m через метод invokeDefault. Например, следующий код делегирует вызов метода в B::m.

 Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { A.class, B.class },
         (o, m, params) -> {
             if (m.getName().equals("m")) {
                 // invoke B::m instead of A::m
                 Method bMethod = B.class.getMethod(m.getName(), m.getParameterTypes());
                 return InvocationHandler.invokeDefault(o, bMethod, params);
             }
         });
 
Если экземпляр прокси реализует C, который наследует метод по умолчанию m от своего суперинтерфейса A, то вызов метода интерфейса на "m" передаётся обработчику вызовов в метод invoke с аргументом объекта Method, представляющим метод по умолчанию A::m.

 Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { C.class },
        (o, m, params) -> {
             if (m.isDefault()) {
                 // behaves as if calling C.super.m(params)
                 return InvocationHandler.invokeDefault(o, m, params);
             }
        });
 
Вызов метода "m" на этом proxy будет вести себя так, как будто C.super::m называется, и это резолвится в вызов A::m.

Добавление метода по умолчанию или изменение метода из абстрактного в метод по умолчанию может привести к исключению, если существующий код пытается вызвать invokeDefault для вызова метода по умолчанию. Например, если C модифицирован для реализации метода по умолчанию m:


 interface C extends A {
     default T m(A a) { return t3; }
 }
 
Вышеприведённый код, создающий экземпляр прокси proxy с изменённым C, выполнится без исключений и приведёт к вызову C::m вместо A::m.

Вот ещё один пример, который создаёт экземпляр прокси C, а обработчик вызовов вызывает метод invokeDefault для вызова A::m:


 C c = (C) Proxy.newProxyInstance(loader, new Class<?>[] { C.class },
         (o, m, params) -> {
             if (m.getName().equals("m")) {
                 // IllegalArgumentException thrown as {@code A::m} is not a method
                 // inherited from its proxy interface C
                 Method aMethod = A.class.getMethod(m.getName(), m.getParameterTypes());
                 return InvocationHandler.invokeDefault(o, aMethod params);
             }
         });
 c.m(...);
 
Вышеприведённый код успешно выполняется со старой версией C, и A::m вызывается. При выполнении с новой версией C вышеприведённый код завершится ошибкой IllegalArgumentException, так как C переопределяет реализацию того же метода, и A::m недоступен для экземпляра прокси.
Примечание API:
Параметр proxy имеет тип Object, а не Proxy, чтобы облегчить обработчику вызовов InvocationHandler::invoke вызов напрямую без необходимости приведения типов.
Параметры:
proxy - экземпляр Proxy, на котором должен быть вызван метод по умолчанию
method - экземпляр Method, соответствующий методу по умолчанию, объявленному в интерфейсе прокси класса или унаследованному от его суперинтерфейсов напрямую или косвенно
args - параметры, используемые для вызова метода; могут быть null, если метод не требует формальных параметров.
Возвращает:
значение, возвращаемое из вызова метода
Исключения:
IllegalArgumentException - если какое-либо из следующих условий выполняется true:
  • proxy не является экземпляром прокси; или
  • указанный method не является методом по умолчанию, объявленным в интерфейсе прокси класса и не унаследованным ни от одного из его суперинтерфейсов; или
  • указанный method переопределяется непосредственно или косвенно интерфейсами прокси, и ссылка на метод с заданным именем никогда не резолвится на данный method; или
  • длина заданного массива args не соответствует числу параметров вызываемого метода; или
  • любой из элементов args не проходит преобразование распаковки, если соответствующий тип параметра метода — примитивный тип; или если, после возможной распаковки, любой из элементов args не может быть присвоен соответствующему типу параметра метода.
IllegalAccessException - если класс-объявитель указанного метода по умолчанию недоступен для вызывающего класса
NullPointerException - если proxy или method null
Throwable - любое исключение, брошенное методом по умолчанию
См. Спецификацию Java Virtual Machine:
5.4.3 Резолюция
С:
16

© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://download.java.net/java/early_access/jdk24/docs/api/java.base/java/lang/reflect/InvocationHandler.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API