所以我看到了很多类似的帖子,但我无法理解,所以我希望在我的具体情况下得到一些帮助。在java 8之前,我见过如何做到这一点,创建一个带有未定义方法的接口,然后在HashMap里面实现它,这种方法对我来说很有意义,但我想学习新的方法。我只半懂lambda运算符和::运算符,但从我的观察来看,它们正是我所需要的,只是我不懂语法。这是我想请你解释如何做的伪代码。
public void doStuffA(String s) {some code A}
public void doStuffB(String s) {some code B}
public void doStuffC(String s) {some code C}
HashMap<String, MethodPointer> hmap = new HashMap<String, MethodPointer>();
hmap.put("Canada", doStuffA(String s));
hmap.put("futon", doStuffB(String s));
hmap.put("Peter", doStuffC(String s));
String str = "pass in this string";
void runStuff(String s) = hmap.get("Peter");
runStuff(str);
希望你能明白我的意图 我还没有把我的实际代码放在这里,因为我怕被人说我的整个程序都是愚蠢的,不应该写,但情况是类似的。我有一些方法,在本例中是3个,每个方法都接收一个字符串。在HashMap中,每个方法都被映射到一些字符串,在我的例子中,我使用了随机词。我希望能够得到存储在某个位置的任何函数,并以 "东西 "为参数运行它。无论我最终从HashMap中调用什么函数,我都会将字符串stuff传入其中并运行它。给我写一些代码,也许可以解释一下,如果我最终没有理解,我就用java 7及以下的方法来做。我希望能够在不创建任何新的类或接口的情况下完成这一切,但老方法迫使我这样做,我想。
该 ::
显示出 方法参考. 你想要的代码应该是这样的。
import java.util.function.Consumer;
...
class SomeClass {
public void doStuffA(String s) {some code A}
public void doStuffB(String s) {some code B}
public void doStuffC(String s) {some code C}
public void anotherMethod() {
HashMap<String, Consumer<String>> hmap = new HashMap<>();
hmap.put("Canada", this::doStuffA);
hmap.put("futon", this::doStuffB);
hmap.put("Peter", this::doStuffC);
String str = "pass in this string";
Consumer<String> runStuff = hmap.get("Peter");
runStuff.accept(str);
}
}
解释一下这段代码的工作原理
解释一下这段代码的工作原理: this::doStuffA
以上是对 doStuffA
的方法 this
有。如果有一个不同的对象叫做 obj
的方法,称为 doStuffA
,你可以直接替换 this::doStuffA
与 obj::doStuffA
. 如果 doStuffA
是一个静态方法,你可以说 ClassThatDoStuffAIsIn::doStuffA
.
该 Consumer
界面看起来像这样。
public interface Consumer<T> {
void accept(T t);
}
这就是所谓的 功能界面. 功能接口是具有单一抽象方法的接口。在本例中,这个方法就是accept。
方法引用和lambda表达式实际上只是语法糖。Java看的是你的方法的签名(doStuffA
)和功能接口中抽象方法的签名,如果匹配,基本上就会通过调用你的方法来创建一个覆盖该抽象方法的对象。
一个方法引用,如 Consumer<String> c = this::doStuff
或等价的lambda表达式,如 Consumer<String> c = (s) -> doStuff(c);
真正的意思是这样的。
class ConsumerImpl implements Consumer<String> {
@Override //This annotation isn't actually added, but it's just for clarity
public void accept(String str) {
this.doStuffA(str);
}
}
...
Consumer<String> c = new ConsumerImpl();
或与一个 匿名班:
Consumer<String> c = new Consumer<>() {
@Override //This annotation isn't actually added, but it's just for clarity
public void accept(String str) {
this.doStuffA(str);
}
};
实际上并不是这样的--JVM对这类对象进行了特殊处理,并使用了一个叫做"-"的操作码。invokedynamic
但这可能超出了本回答的范围。就所有的意图和目的而言,上面的代码就是方法引用的扩展。
所以你不能像这样直接调用这些方法。
Consumer<String> runStuff = hmap.get("Peter");
runStuff(str); //This is an error because there is no method called runStuff
因此,你必须使用 accept
的方法 Consumer
接口来实际使用 doStuffA
方法。
编辑: 只是想澄清一下,你不必使用这个。Consumer
接口。你可以制作你自己的接口,不管你想用什么名字,只要它只有一个抽象方法(你也可以用你想用的名字)。这样也可以。
public interface MyBeautifulFunctionalInterface {
void doStuffWithAString(String s);
}
and then
public static void main(String[] argh) {
MyBeautifulFunctionalInterface runStuff = this::doStuffA;
runStuff.doStuffWithAString("blah");
}