鉴于这个简单的“Hello World”是Java 8界面,我如何通过反射调用其hello()方法?如何反射地调用Java 8默认方法
public interface Hello {
default String hello() {
return "Hello";
}
}
鉴于这个简单的“Hello World”是Java 8界面,我如何通过反射调用其hello()方法?如何反射地调用Java 8默认方法
public interface Hello {
default String hello() {
return "Hello";
}
}
你不能直接调用它,因为你需要一个实现类的实例。为此,你需要一个实施课程。 default
方法不是static
方法,也不能创建接口的实例。
因此,假设你已经实现类:
class HelloImpl implements Hello { }
您可以调用这样的方法:
Class<HelloImpl> clazz = HelloImpl.class;
Method method = clazz.getMethod("hello");
System.out.println(method.invoke(new HelloImpl())); // Prints "Hello"
我应该更精确的在我的问题:我如何*实例化它*并调用ist hello()方法 - *都通过反射? – thekid
@thekid你不能实例化一个接口。你需要一个实施课程,我已经在答案中展示了。 –
我已经found a solution从像上面的接口创建实例使用反思代码从sun.misc.ProxyGenerator
,它通过组装字节码来定义类HelloImpl
。现在我可以写:
Class<?> clazz = Class.forName("Hello");
Object instance;
if (clazz.isInterface()) {
instance = new InterfaceInstance(clazz).defineClass().newInstance();
} else {
instance = clazz.newInstance();
}
return clazz.getMethod("hello").invoke(instance);
......但这很丑陋。
必须是丑陋的,否则有人会想要使用它! –
肯定会比必要的工作更多。访问可以通过MethodHandles完成,不需要大量的依赖或过多的运行时间工作。 – Ajax
您可以使用该MethodHandles:
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ReflectiveDefaultMethodCallExample {
static interface Hello {
default String hello() {
return "Hello";
}
}
public static void main(String[] args) throws Throwable{
Hello target =
//new Hello(){};
(Hello)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{Hello.class}, (Object proxy, Method method, Object[] arguments) -> null);
Method method = Hello.class.getMethod("hello");
Object result = MethodHandles.lookup()
.in(method.getDeclaringClass())
.unreflectSpecial(method,method.getDeclaringClass())
.bindTo(target)
.invokeWithArguments();
System.out.println(result); //Hello
}
}
好主意,因为它提供了一个提示'InvocationHandler'如何委托给一个默认方法。这在其他情况下可能非常有用。 – Holger
这是正确的,除了它会在用于查找句柄的文件之外的文件中定义的任何接口失败。我使用了以下修改:final Field field = Lookup.class.getDeclaredField(“IMPL_LOOKUP”); field.setAccessible(true); final Lookup lookup =(Lookup)field.get(null); (); final Object value = lookup .unreflectSpecial(method,method.getDeclaringClass()) .bindTo(t) .invokeWithArguments(); – Ajax
这篇文章的评论也有其他的解决方法https://rmannibucau.wordpress.com/2014/03/27/java-8-default-interface-methods-and-jdk-dynamic-proxies/最好的可能是抢Lookup类的构造函数,因此您可以使用PRIVATE访问创建查找,而不像上面那样访问完全权限的IMPL_LOOKUP字段。 – Ajax
相关:http://stackoverflow.com/questions/37812393/how-to-explicitly-invoke-default-method-from-a-dynamic-proxy如注释为dup。通过@Rudziankoŭ – earcam