给出这个简单的"Hello World“式Java 8接口,如何通过反射调用它的hello()方法?
public interface Hello {
default String hello() {
return "Hello";
}
}发布于 2014-06-02 17:03:36
为此,您可以使用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
}
}发布于 2018-03-28 18:47:32
不幸的是,似乎没有一个理想的解决方案可以在所有JDK 8、9、10上工作,它们的行为方式是不同的。I've run into issues when fixing an issue in jOOR。I've also blogged about the correct solution here in detail。
此方法适用于Java 8
在Java8中,理想的方法是使用黑客从Lookup访问包私有构造函数
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
interface Duck {
default void quack() {
System.out.println("Quack");
}
}
public class ProxyDemo {
public static void main(String[] a) {
Duck duck = (Duck) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[] { Duck.class },
(proxy, method, args) -> {
Constructor<Lookup> constructor = Lookup.class
.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
constructor.newInstance(Duck.class)
.in(Duck.class)
.unreflectSpecial(method, Duck.class)
.bindTo(proxy)
.invokeWithArguments();
return null;
}
);
duck.quack();
}
}这是同时适用于私有可访问接口和私有不可访问接口的唯一方法。然而,上面的方法对JDK内部的反射访问是非法的,这在未来的JDK版本中将不再有效,或者如果在JVM上指定了--illegal-access=deny。
此方法适用于Java 9和10,但不适用于8
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Proxy;
interface Duck {
default void quack() {
System.out.println("Quack");
}
}
public class ProxyDemo {
public static void main(String[] a) {
Duck duck = (Duck) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[] { Duck.class },
(proxy, method, args) -> {
MethodHandles.lookup()
.findSpecial(
Duck.class,
"quack",
MethodType.methodType(void.class, new Class[0]),
Duck.class)
.bindTo(proxy)
.invokeWithArguments();
return null;
}
);
duck.quack();
}
}解决方案
只需实现上述两种解决方案,并检查您的代码是否在JDK 8或更高版本的JDK上运行,就可以了。直到您不再是这样:)
发布于 2014-03-25 00:15:03
你不能直接调用它,因为你需要一个实现类的实例。为此,您需要一个实现类。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"https://stackoverflow.com/questions/22614746
复制相似问题