Java可以将方法存储在数组中吗?

15

我写了一些代码,只是使用for循环并更改调用的方法。我尝试使用for循环来使代码更简洁(以及出于好奇心,看看是否可以完成),但这样做时它无法编译,因为它不能将数组中的项识别为方法。我认为这就是我的代码:

String[] moveArray = {moveRight,moveDown,moveLeft,moveUp};
for (i = 0; i < 4; i++) {
    while (myWumpus.moveArray[i]) {
        myWumpus.moveArray[i];
        generator.updateDisplay();
    }
}

当我尝试编译时,出现了以下错误:

not a statement myWumpus.moveArray[i]();
';' expected myWumpus.moveArray[i]();

(它指的是while循环中的第一条语句)

所以,我想可能是因为我将它作为String类型的数组?是否有类型方法?这是否有可能?任何解决方案都可以 :). 此外,我可以使用4个while循环使其工作,所以您不需要向我展示该解决方案。

5个回答

17

你无法直接将方法存储在数组中。但是,你可以存储实现相同方法的不同对象。例如:

Mover[] moveArray = {new RightMover(), new DownMover() new LeftMover(), new UpMover() };
for (i = 0; i < 4; i++) {
    while (myWumpus.moveArray[i]) {
        moveArray[i].move();
        generator.updateDisplay();
    }
}

一种变化使用枚举类型。在方法调用中,需要通过参数传递被操作的对象,而不是构造函数。 - Tom Hawtin - tackline

8

是的,您可以使用反射将方法存储在数组中,但在这种情况下,您实际想要做的可能是使用多态性

关于您的问题,多态性的一个示例 - 假设您创建了以下接口:

public interface MoveCommand {
    void move();
}

您可以按照以下方式创建实现:
public class MoveLeftCommand implements MoveCommand {
    public void move() {
        System.out.println("LEFT");
    }
}

等等其他移动选项。您可以将它们存储在MoveCommand[]或类似List<MoveCommand>的集合中,然后迭代数组/集合,在每个元素上调用move()方法,例如:

public class Main {

    public static void main(String[] args) {
        List<MoveCommand> commands = new ArrayList<MoveCommand>();
        commands.add(new MoveLeftCommand());
        commands.add(new MoveRightCommand());
        commands.add(new MoveLeftCommand());

        for (MoveCommand command:commands) {
            command.move();
        }
    }

}

多态性非常强大,上面是一个被称为命令模式的简单示例。祝您在Wumpus World实现中愉快 :)


6

在Java中,你不能将方法存储在数组中,因为方法在Java中不是一等对象。这是一些人喜欢使用Python、Scheme等其他语言的原因。

解决方法是创建一个包含一个方法的接口,然后创建四个实现该接口的类——MoveRight、MoveLeft等类。然后,您可以将这些类的实例存储在数组中,并以相同的方式调用它们。


1
java.lang.reflect.Method 是一个一等对象,但我同意你提出的通用解决方案。 - Brian Agnew
1
@Brian:是的,但它是代表方法的对象,本质上并不是一个方法。你不能“调用”Method的实例(你在实例上调用方法)。 - Draemon

6
您不能以那种方式调用方法。但是您可以使用反射来调用:
只需将while循环中的第一行更改为:
Method m = myWumps.getClass().getMethod(moveArray[i]); // if the method is void
m.invoke(myWumps);

你需要声明/捕获一些异常。

但最好避免使用反射,而是使用命令模式


避免使用反射有什么好处?反射会消耗时间和内存吗?上面的代码看起来非常整洁。 - chrisTina

2
Java 8及更高版本的更新答案:
自从Java 8引入了lambda表达式和方法引用,现在就可以将各种方法存储在变量中了。一个主要问题是,在Java中,数组目前不支持泛型对象,这使得在数组中存储方法变得困难。但是它们可以存储在其他数据结构中,比如List。
所以,对于一些简单的例子,您可以编写类似以下的代码:
List<Comparator<String>> stringComparators = new ArrayList<>();
Comparator<String> comp1 = (s1, s2) -> Integer.compare(s1.length(), s2.length());
stringComparators.add(comp1);

或者

List<Consumer<String>> consumers = new ArrayList<>();
Consumer<String> consumer1 = System.out::println;
consumers.add(consumer1);

然后通过循环迭代List获取方法。

所以只是为了确保我理解,这个答案是“在Java 8的新答案中,答案仍然是否定的”? - TylerH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接