Java Pass方法作为参数
我正在寻找一种通过引用来传递方法的方法。 我明白,Java不会传递方法作为参数,但是,我想获得一个替代scheme。
我已经被告知接口是传递方法作为参数的替代方法,但我不明白接口如何作为引用的方法。 如果我理解正确,一个接口就是一个抽象的未定义的方法集合。 我不想发送一个需要每次定义的接口,因为几个不同的方法可能调用相同的参数相同的方法。
我想要做的是类似这样的事情:
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());
编辑 :从Java 8开始, lambdaexpression式是其他 答案指出的一个很好的解决scheme。 下面的答案是为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()
方法来访问感知 – 但是如果你需要遍历一个更复杂的对象图,那么这是值得研究的。
在Java 8中,现在可以使用Lambdaexpression式更轻松地传递一个方法。 首先是一些背景。 function接口是一个只有一个抽象方法的接口,尽pipe它可以包含任意数量的默认方法 (Java 8中的新增function)和静态方法。 如果不使用lambdaexpression式,lambdaexpression式可以快速实现抽象方法,而不需要所有不必要的语法。
没有lambdaexpression式:
obj.aMethod(new AFunctionalInterface() { @Override public boolean anotherMethod(int i) { return i == 982 } });
用lambdaexpression式:
obj.aMethod(i -> i == 982);
下面是关于Lambdaexpression式的Java教程的摘录:
Lambdaexpression式的语法
一个lambdaexpression式包含以下内容:
用逗号分隔的括号内的forms参数列表。 CheckPerson.test方法包含一个参数p,它表示Person类的一个实例。
注意 :您可以省略lambdaexpression式中参数的数据types。 另外,如果只有一个参数,则可以省略括号。 例如,下面的lambdaexpression式也是有效的:
p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25
箭头标记
->
一个由单个expression式或语句块组成的主体。 这个例子使用下面的expression式:
p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25
如果指定单个expression式,则Java运行时将评估expression式,然后返回其值。 或者,您可以使用返回语句:
p -> { return p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25; }
返回语句不是一个expression式; 在lambdaexpression式中,必须将括号括在括号({})中。 但是,您不必在大括号中包含void方法调用。 例如,以下是有效的lambdaexpression式:
email -> System.out.println(email)
请注意,lambdaexpression式看起来很像一个方法声明; 您可以将lambdaexpression式视为匿名方法 – 没有名称的方法。
以下是如何使用lambdaexpression式“传递方法”:
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)); } }
使用java.lang.reflect.Method
对象并调用invoke
首先用你想作为parameter passing的方法来定义一个接口
public interface Callable { public void call(int param); }
用这个方法来实现一个类
class Test implements Callable { public void call(int param) { System.out.println( param ); } }
//像这样调用
Callable cmd = new Test();
这允许您将cmd作为parameter passing,并调用在接口中定义的方法调用
public invoke( Callable callable ) { callable.call( 5 ); }
尽pipe对于Java 7及以下版本来说,这还不是有效的,但我相信我们应该outlook未来,至less认识到Java 8等新版本的变化 。
也就是说,这个新版本带来了Java的lambdas和方法引用(以及新的API ,这是另一个有效的解决scheme,虽然它们仍然需要一个接口,但是没有创build新的对象,额外的类文件不需要污染输出目录由JVM处理。
这两种风格(lambda和方法引用)都要求使用一个使用其签名的方法的接口:
public interface NewVersionTest{ String returnAString(Object oIn, String str); }
方法的名称从这里不重要。 在接受lambda的情况下,方法引用也是如此。 例如,在这里使用我们的签名:
public static void printOutput(NewVersionTest t, Object o, String s){ System.out.println(t.returnAString(o, s)); }
这只是一个简单的接口调用,直到lambda 1通过:
public static void main(String[] args){ printOutput( (Object oIn, String sIn) -> { System.out.println("Lambda reached!"); return "lambda return"; } ); }
这将输出:
Lambda reached! lambda return
方法的参考是相似的。 鉴于:
public class HelperClass{ public static String testOtherSig(Object o, String s){ return "real static method"; } }
主要是:
public static void main(String[] args){ printOutput(HelperClass::testOtherSig); }
输出将是real static method
。 方法引用可以是静态的,实例,任意实例的非静态的,甚至是构造函数 。 对于构造函数,会使用类似于ClassName::new
东西。
1这不被认为是一个lambda,因为它有副作用。 但是,它确实说明了使用一种更直接的可视化方式。
上次我查了一下,Java不能自己做你想做的事情, 你必须使用“解决方法”来解决这些限制。 据我所知,接口是一种替代scheme,但不是一个好的select。 也许谁告诉你这个意思是这样的:
public interface ComponentMethod { public abstract void PerfromMethod(Container c); } public class ChangeColor implements ComponentMethod { @Override public void PerfromMethod(Container c) { // do color change stuff } } public class ChangeSize implements ComponentMethod { @Override public void PerfromMethod(Container c) { // do color change stuff } } public void setAllComponents(Component[] myComponentArray, ComponentMethod 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.PerfromMethod(leaf); } //end looping through components }
然后你会调用:
setAllComponents(this.getComponents(), new ChangeColor()); setAllComponents(this.getComponents(), new ChangeSize());
如果你不需要这些方法来返回一些东西,你可以让它们返回Runnable对象。
private Runnable methodName (final int arg){ return new Runnable(){ public void run(){ // do stuff with arg } } }
然后像这样使用它:
private void otherMethodName (Runnable arg){ arg.run(); }
使用观察者模式(有时也称为监听者模式):
interface ComponentDelegate { void doSomething(Component component); } public void setAllComponents(Component[] myComponentArray, ComponentDelegate delegate) { // ... delegate.doSomething(leaf); } setAllComponents(this.getComponents(), new ComponentDelegate() { void doSomething(Component component) { changeColor(component); // or do directly what you want } });
new ComponentDelegate()...
声明一个实现接口的匿名types。
Java有一个机制来传递名称和调用它。 这是反思机制的一部分。 您的函数应该采用类Method的附加参数。
public void YouMethod(..... Method methodToCall, Object objWithAllMethodsToBeCalled) { ... Object retobj = methodToCall.invoke(objWithAllMethodsToBeCalled, arglist); ... }
这里是一个基本的例子:
public class TestMethodPassing { private static void println() { System.out.println("Do println"); } private static void print() { System.out.print("Do print"); } private static void performTask(BasicFunctionalInterface functionalInterface) { functionalInterface.performTask(); } @FunctionalInterface interface BasicFunctionalInterface { void performTask(); } public static void main(String[] arguments) { performTask(TestMethodPassing::println); performTask(TestMethodPassing::print); } }
输出:
Do println Do print
我不是一个Java专家,但我解决你的问题是这样的:
@FunctionalInterface public interface AutoCompleteCallable<T> { String call(T model) throws Exception; }
我在我的特殊界面中定义参数
public <T> void initialize(List<T> entries, AutoCompleteCallable getSearchText) {....... //call here String value = getSearchText.call(item); ... }
最后,我在调用initialize方法的时候实现了getSearchText方法。
initialize(getMessageContactModelList(), new AutoCompleteCallable() { @Override public String call(Object model) throws Exception { return "custom string" + ((xxxModel)model.getTitle()); } })
从Java 8开始,有一个Function<T, R>
接口( docs ),它有方法
R apply(T t);
您可以使用它将函数作为parameter passing给其他函数。 T是函数的inputtypes,R是返回types。
在你的例子中,你需要传递一个把Component
types作为input的函数,并且什么都不返回 – Void
。 在这种情况下, Function<T, R>
不是最好的select,因为没有Voidtypes的自动装箱。 你正在寻找的接口被称为Consumer<T>
( docs )与方法
void accept(T t);
它看起来像这样:
public void setAllComponents(Component[] myComponentArray, Consumer<Component> myMethod) { for (Component leaf : myComponentArray) { if (leaf instanceof Container) { Container node = (Container) leaf; setAllComponents(node.getComponents(), myMethod); } myMethod.accept(leaf); } }
你可以使用方法引用来调用它:
setAllComponents(this.getComponents(), this::changeColor); setAllComponents(this.getComponents(), this::changeSize);
假设您已经在同一个类中定义了changeColor()和changeSize()方法。
如果您的方法碰巧接受多个参数,则可以使用BiFunction<T, U, R>
– T和U作为input参数的types,R是返回types。 还有BiConsumer<T, U>
(两个参数,没有返回types)。 不幸的是,对于3个以上的input参数,你必须自己创build一个接口。 例如:
public interface Function4<A, B, C, D, R> { R apply(A a, B b, C c, D d); }