Java Pass 方法作为参数

2022-08-31 04:46:53

我正在寻找一种通过引用传递方法的方法。我知道Java不将方法作为参数传递,但是,我想得到一个替代方案。

我被告知接口是将方法作为参数传递的替代方法,但我不明白接口如何通过引用充当方法。如果我理解正确,接口只是一组未定义的抽象方法。我不想发送一个需要每次都定义的接口,因为几个不同的方法可以使用相同的参数调用相同的方法。

我想完成的是类似于以下内容:

public void setAllComponents(Component[] myComponentArray, Method myMethod) {
    for (Component leaf : myComponentArray) {
        if (leaf instanceof Container) { //recursive call if Container
            Container node = (Container) leaf;
            setAllComponents(node.getComponents(), myMethod);
        } //end if node
        myMethod(leaf);
    } //end looping through components
}

调用,例如:

setAllComponents(this.getComponents(), changeColor());
setAllComponents(this.getComponents(), changeSize());

答案 1

编辑:从Java 8开始,正如其他答案所指出的那样,lambda表达式是一个不错的解决方案。下面的答案是为Java 7及更早版本编写的...


查看命令模式

// NOTE: code not tested, but I believe this is valid java...
public class CommandExample 
{
    public interface Command 
    {
        public void execute(Object data);
    }

    public class PrintCommand implements Command 
    {
        public void execute(Object data) 
        {
            System.out.println(data.toString());
        }    
    }

    public static void callCommand(Command command, Object data) 
    {
        command.execute(data);
    }

    public static void main(String... args) 
    {
        callCommand(new PrintCommand(), "hello world");
    }
}

编辑:正如Pete Kirkham指出的那样,还有另一种方法可以使用访客来做到这一点。访问者方法稍微复杂一些 - 您的节点都需要使用方法对访问者进行感知 - 但是如果您需要遍历更复杂的对象图,那么值得检查。acceptVisitor()


答案 2

在 Java 8 中,您现在可以使用 Lambda 表达式和方法引用更轻松地传递方法。首先,一些背景知识:功能接口是一个只有一个抽象方法的接口,尽管它可以包含任意数量的默认方法(Java 8中的新功能)和静态方法。lambda 表达式可以快速实现抽象方法,如果您不使用 lambda 表达式,则无需所有不必要的语法。

没有 lambda 表达式:

obj.aMethod(new AFunctionalInterface() {
    @Override
    public boolean anotherMethod(int i)
    {
        return i == 982
    }
});

使用 lambda 表达式:

obj.aMethod(i -> i == 982);

以下是有关 Lambda 表达式的 Java 教程的摘录

Lambda 表达式的语法

lambda 表达式由以下内容组成:

  • 用逗号分隔的形式参数列表,括在括号中。CheckPerson.test 方法包含一个参数 p,它表示 Person 类的一个实例。

    注意:您可以在 lambda 表达式中省略参数的数据类型。此外,如果只有一个参数,则可以省略括号。例如,以下 lambda 表达式也是有效的:

    p -> p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25
    
  • 箭头令牌,->

  • 由单个表达式或语句块组成的正文。此示例使用以下表达式:

    p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25
    

    如果指定单个表达式,则 Java 运行时将计算该表达式,然后返回其值。或者,您可以使用 return 语句:

    p -> {
        return p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25;
    }
    

    return 语句不是表达式;在 lambda 表达式中,必须将语句括在大括号 ({}) 中。但是,您不必将 void 方法调用括在大括号中。例如,下面是一个有效的 lambda 表达式:

    email -> System.out.println(email)
    

请注意,lambda 表达式看起来很像方法声明;您可以将 lambda 表达式视为匿名方法, 即没有名称的方法。


以下是使用 lambda 表达式“传递方法”的方法:

interface I {
    public void myMethod(Component component);
}

class A {
    public void changeColor(Component component) {
        // code here
    }

    public void changeSize(Component component) {
        // code here
    }
}
class B {
    public void setAllComponents(Component[] myComponentArray, I myMethodsInterface) {
        for(Component leaf : myComponentArray) {
            if(leaf instanceof Container) { // recursive call if Container
                Container node = (Container)leaf;
                setAllComponents(node.getComponents(), myMethodInterface);
            } // end if node
            myMethodsInterface.myMethod(leaf);
        } // end looping through components
    }
}
class C {
    A a = new A();
    B b = new B();

    public C() {
        b.setAllComponents(this.getComponents(), component -> a.changeColor(component));
        b.setAllComponents(this.getComponents(), component -> a.changeSize(component));
    }
}

通过使用方法引用,类可以进一步缩短,如下所示:C

class C {
    A a = new A();
    B b = new B();

    public C() {
        b.setAllComponents(this.getComponents(), a::changeColor);
        b.setAllComponents(this.getComponents(), a::changeSize);
    }
}