在我当前正在处理的一个 Java 项目中,我动态加载类,然后使用反射 API 来查找并执行那些具有某些注释的类的方法。
执行实际执行的代码专门根据 Java-8 功能接口工作(出于兼容性原因),因此我需要一个中间阶段,将Method使用反射发现的实例转换为适当的功能接口。我使用MethodHandleProxies类来实现这一点。
再次出于兼容性原因,所讨论的功能接口是通用接口。这会在使用该方法时导致“未经检查的转换”警告MethodHandleProxies.asInterfaceInstance,因为该方法返回“裸”接口。
以下是一个简短的示例,重现了所涉及的主要步骤:
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandleProxies;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.Arrays;
public class TestClass {
private String prefix;
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, SecurityException {
// Use reflection to find method.
Method method = Arrays.stream(TestClass.class.getDeclaredMethods()) // Stream over methods of ConsumerClass
.filter(m -> m.isAnnotationPresent(Marker.class)) // Retain only methods with @Marker annotation
.findFirst().get(); // Get first such method …Run Code Online (Sandbox Code Playgroud) 我两次引用相同的方法,但引用不同。看这个例子:
import java.util.function.Consumer;
public class MethodRefTest {
public static void main(String[] args) {
new MethodRefTest();
}
public MethodRefTest() {
Consumer<Integer> a = this::method;
System.out.println(a);
Consumer<Integer> b = this::method;
System.out.println(b);
}
public void method(Integer value) {
}
}
Run Code Online (Sandbox Code Playgroud)
输出是:
MethodRefTest$$Lambda$1/250421012@4c873330
MethodRefTest$$Lambda$2/295530567@776ec8df
Run Code Online (Sandbox Code Playgroud)
方法引用只不过是匿名类的语法糖吗?如果不是,我该怎么做才能始终获得相同的方法引用?(除了在字段中存储一次参考以供使用之外。)
(应用:我认为方法引用是观察者实现的一种更漂亮的方式。但是每次使用不同的引用,一旦添加观察者就不可能从可观察者中删除观察者。)
考虑以下代码:
val hwnd = Handler()
hwnd.postDelayed(object : Runnable {
override fun run()
hwnd.postDelayed(this, 5000)
}
}, 5000)
Run Code Online (Sandbox Code Playgroud)
这样,我可以通过this在run()方法中使用(指的是 Runnable)将相同的 Runnable 发布到 Handler 。但是我怎么能只使用一个 lambda 表达式来做同样的事情呢?
val hwnd = Handler()
hwnd.postDelayed({
//How to get "this" here?
}, 5000)
Run Code Online (Sandbox Code Playgroud)
这甚至可能吗?
我知道函数式接口意味着您可以完全/只有 1 个抽象方法和 1 个以上的默认方法,但我想知道如何将它与在 Java 中使用函数式接口的实际示例/情况相关联。
你能给出一个有效的情况/例子吗?
提前致谢!
我通过在公共static void main()方法内实现接口I创建了匿名类。因此,通过Java 8的抽象方法test(),实现是从类C的imple()方法提供的。
因此,在public static void main()方法内部,打印_interface.getClass(),我得到了
package_path.Main $ $ Lambda $ 1/310656974这是绝对好的。因为它打印的是匿名类名。
另外,_interface指向堆中的匿名对象,因此我正在做_interface.test();。
因此,test()方法现在具有的第一条语句是打印类名称,
但是最终它显示的是package_path.C(告诉我C是类名)。那怎么可能?不应再次打印package_path.Main $$ Lambda $ 1/310656974吗?因为“这”意味着在测试方法内部是匿名的,对吗?
@java.lang.FunctionalInterface
interface I {
void test();
}
class C {
void imple() {
System.out.println(this.getClass());
System.out.println("Inside Implementation");
}
}
class Main {
public static void main(String[] args) {
I _interface = new C()::imple;
System.out.println(_interface.getClass());
_interface.test();
}
}
Run Code Online (Sandbox Code Playgroud) 我们有这个代码:
public class Test {
public static Object foo() {
System.out.println("Foo");
return new Object();
}
public static void main(String[] args) {
J j = Test::foo;
j.m();
}
}
interface J {
void m();
}
Run Code Online (Sandbox Code Playgroud)
这段代码会起作用。关键线是
J j = Test::foo;
Run Code Online (Sandbox Code Playgroud)
虽然interface J声明它有一个void函数,但Test::foo返回一个Object.
虽然我们不能在实现接口时覆盖方法(这是显而易见的)。这仅在接口的方法为 时有效void,否则不会编译代码。有人能说出为什么这会以这种方式工作吗?:D
代码:
public void ifChangedString(String key, Consumer<String> consumer) {
...
consumer.accept(getString(key));
}
public void ifChangedBoolean(String key, Consumer<Boolean> consumer) {
...
consumer.accept(getBoolean(key));
}
Run Code Online (Sandbox Code Playgroud)
是否可以制作单个方法public <T> void ifChanged(String key, Class<T> clazz, Consumer<T> consumer)?
显而易见的解决方案是public void ifChanged(String key, Consumer<Object> consumer)但我不想Object用作参数类型,最好使用上述几种方法。
问题是对于accept我需要的方法? super XXX,只有 super 是 Object。那么有可能吗?
我有这个代码,它有效:
new JdbcTemplate(new SingleConnectionDataSource(c, true))
.query("select id, name from PLAYERS", (rs, rowNum) ->
new Player(rs.getString("id"), rs.getString("name")) // oneline
);
Run Code Online (Sandbox Code Playgroud)
但是我现在需要在新的 Player() 部分添加多个语句。我尝试将它们括在括号中,但似乎不起作用。什么是正确的语法?
我有一个我不明白的 java 编译器错误。似乎消费者< ? > 和 Consumer< T >(带有 T extends Object)在方法签名参数中是不等价的。请查看以下代码:
import java.util.function.Consumer;
public class MyClass {
public void joker(Consumer<?> fct) {}
public <T> void generic(Consumer<T> fct) {}
public void myConsumer(String s) {}
public void doesNotCompile()
{
joker(this::myConsumer); // COMPILE ERROR : (In Eclipse : ) The type MyClass does not define myConsumer(Object) that is applicable here
generic(this::myConsumer); // Works fine : how come are "T" and "?" not equivalent here ?
// The following also works fine as …Run Code Online (Sandbox Code Playgroud) 鉴于以下代码,有人可以解释为什么断言返回 true 吗?尽管已经进行了无数次搜索,但我无法得到任何适当的答案,说明为什么会出现这种情况,Java 特性是什么导致了这种行为,以及我在类似地创建这样的接口时会遇到哪些限制/要求作为这个。
interface X {
default int foo() {return 1;}
String bar();
}
public class Exercise{
public static void main(String[]arg){
X foo1=()->"hello";
assert (foo1.bar()).equals("hello");
}
}
Run Code Online (Sandbox Code Playgroud)