如何在运行时实例化仅含默认方法的接口并实现通用代理?
How to Create a Generic Proxy for Interfaces with Only Default Methods
Got it, let's work through this problem. You want a reusable generic method that can generate a proxy for any interface containing only default methods, replicating the behavior of new T(){} (an anonymous inner class implementation) but in a flexible, generic way. Here's a clean solution using JDK's built-in dynamic proxy and method handles to handle default method invocations:
The Generic Proxy Method
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; public class ProxyUtils { public static <T> T proxy(final Class<T> clazz) { // First, validate the input is an interface if (!clazz.isInterface()) { throw new IllegalArgumentException("The provided class must be an interface"); } // Create the proxy instance using JDK dynamic proxy return (T) Proxy.newProxyInstance( clazz.getClassLoader(), new Class<?>[]{clazz}, (proxy, method, args) -> { // Check if the method is a public default method of the interface if (method.isDefault() && Modifier.isPublic(method.getModifiers())) { // Use MethodHandle to invoke the default method implementation MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle methodHandle = lookup.unreflectSpecial(method, clazz); // Bind the method handle to the proxy instance and invoke with arguments return methodHandle.bindTo(proxy).invokeWithArguments(args); } // Fallback for non-default methods (shouldn't occur in your use case) throw new UnsupportedOperationException( String.format("No implementation available for method: %s", method.getName()) ); } ); } }
How It Works
Let's break down the key pieces:
- Input Validation: We first ensure the provided class is an interface—since this method is designed specifically for interfaces with default methods.
- Dynamic Proxy Creation:
Proxy.newProxyInstancegenerates a runtime proxy class that implements the input interface, which acts as our stand-in for the anonymous inner class. - Default Method Handling: The core logic lives in the
InvocationHandler:- We check if the invoked method is a default method using Java 8's
method.isDefault()API. - Standard reflection can't directly call default methods on interfaces, so we use
MethodHandlesto access and execute the default method implementation.unreflectSpecialbinds the method to the original interface, andbindTo(proxy)ensures the method runs in the context of our proxy instance.
- We check if the invoked method is a default method using Java 8's
Example Usage
Test it with your original Some interface:
interface Some { default void doSome() { System.out.println("Executing default doSome() method"); } } public class Main { public static void main(String[] args) { Some proxyInstance = ProxyUtils.proxy(Some.class); proxyInstance.doSome(); // Prints "Executing default doSome() method" } }
Notes
- Java Version: This requires Java 8 or newer, as default methods and the required
MethodHandleAPIs were introduced in Java 8. - Interface Restriction: This method is optimized for interfaces with only default methods. If the interface includes abstract methods, calling those will throw an
UnsupportedOperationException—you can adjust the handler logic if you need to handle that scenario. - Class Loader: We use the interface's class loader to ensure the proxy class loads in the same context as the interface, avoiding class loader conflicts.
内容的提问来源于stack exchange,提问作者Jin Kwon
相关产品推荐
相关产品推荐

