如何从哈希图中调用方法(与 :: 操作符有关?

问题描述 投票:0回答:1

所以我看到了很多类似的帖子,但我无法理解,所以我希望在我的具体情况下得到一些帮助。在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及以下的方法来做。我希望能够在不创建任何新的类或接口的情况下完成这一切,但老方法迫使我这样做,我想。

java pointers lambda hashmap
1个回答
0
投票

:: 显示出 方法参考. 你想要的代码应该是这样的。

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::doStuffAobj::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");
}
© www.soinside.com 2019 - 2024. All rights reserved.