我正在寻找一种通过引用传递方法的方法 . 我知道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());
14 回答
首先使用要作为参数传递的方法定义接口
用该方法实现一个类
//这样调用
这允许您将cmd作为参数传递并调用接口中定义的方法调用
使用
java.lang.reflect.Method
对象并调用invoke
我不是java专家但是我这样解决你的问题:
我在我的特殊界面中定义参数
最后,我在调用 initialize 方法时实现 getSearchText 方法 .
如果您不需要这些方法来返回某些内容,则可以使它们返回Runnable对象 .
然后使用它像:
在Java 8中,您现在可以使用Lambda Expressions和方法引用更轻松地传递方法 . 首先,一些背景:功能接口是一个只有一个抽象方法的接口,尽管它可以包含任意数量的default methods(Java 8中的新增功能)和静态方法 . lambda表达式可以快速实现抽象方法,如果不使用lambda表达式,则不需要所有不必要的语法 .
没有lambda表达式:
使用lambda表达式:
以下是the Java tutorial on Lambda Expressions的摘录:
以下是使用lambda表达式“传递方法”的方法:
通过使用方法引用,可以进一步缩短类
C
,如下所示:我没有找到任何关于如何使用
java.util.function.Function
作为参数函数的简单方法的示例 . 这是一个简单的例子:基本上你有一个带有默认构造函数的
Foo
对象 .method
将作为parametrisedMethod
的参数调用,其类型为Function<String, Foo>
.Function<String, Foo>
表示该函数将String
作为参数并返回Foo
.Foo::Method
对应一个像x -> Foo.method(x);
这样的lambdaparametrisedMethod(Foo::method)
可以看作x -> parametrisedMethod(Foo.method(x))
.apply("from a method")
基本上是做parametrisedMethod(Foo.method("from a method"))
然后将在输出中返回:
该示例应该按原样运行,然后您可以使用不同的类和接口从上面的答案中尝试更复杂的东西 .
这是一个基本的例子:
输出:
Java确实有一种传递名称并调用它的机制 . 它是反射机制的一部分 . 您的函数应该使用类Method的其他参数 .
从Java 8开始,有一个
Function<T, R>
接口(docs),它有方法您可以使用它将函数作为参数传递给其他函数 . T是函数的输入类型,R是返回类型 .
在您的示例中,您需要传递一个函数,该函数将
Component
类型作为输入并且不返回任何内容 -Void
. 在这种情况下Function<T, R>
不是最好的选择,因为没有Void类型的自动装箱 . 您正在寻找的接口使用方法称为Consumer<T>
(docs)它看起来像这样:
你可以使用方法引用来调用它:
假设您已在同一个类中定义了changeColor()和changeSize()方法 .
如果您的方法恰好接受多个参数,则可以使用
BiFunction<T, U, R>
- T和U是输入参数的类型,R是返回类型 . 还有BiConsumer<T, U>
(两个参数,没有返回类型) . 不幸的是,对于3个或更多输入参数,您必须自己创建一个接口 . 例如:编辑:从Java 8开始,lambda expressions是一个很好的解决方案,因为other answers已经指出 . 下面的答案是为Java 7及更早版本编写的......
看看command pattern .
编辑:作为Pete Kirkham points out,还有另一种使用Visitor的方法 . 访问者方法更复杂 - 您的节点都需要使用
acceptVisitor()
方法访问者 - 但是如果您需要遍历更复杂的对象图,那么值得检查 .使用Observer模式(有时也称为Listener模式):
new ComponentDelegate()...
声明实现接口的匿名类型 .上次我检查时,Java无法原生地做你想做的事情;你必须使用'解决方法'来克服这些限制 . 据我所知,接口是另一种选择,但不是一个好的选择 . 也许谁告诉你这意味着这样的事情:
您随后调用的内容:
虽然这对于Java 7及更低版本尚未生效,但我相信我们应该展望未来,并至少认识到the changes会出现在新版本中,例如Java 8 .
也就是说,这个新版本带来了lambdas和Java的方法引用(以及new APIs,这是这个问题的另一个有效解决方案 . 虽然它们仍然需要一个接口,但是没有创建新对象,并且由于处理不同,额外的类文件不需要污染输出目录由JVM .
两种风格(lambda和方法引用)都需要一个可用的接口,该方法使用其签名:
从这里开始,方法的名称无关紧要 . 在接受lambda的情况下,也可以使用方法参考 . 例如,要在此处使用我们的签名:
这只是一个简单的接口调用,直到lambda1被传递:
这将输出:
方法参考类似 . 鉴于:
主要:
输出将是
real static method
. Method references can be static, instance, non-static with arbitrary instances, and even constructors . 对于构造函数,将使用类似于ClassName::new
的东西 .1有些人认为这不是lambda,因为它有副作用 . 然而,它确实说明了以更直接可视化的方式使用它 .
我不认为lambdas是为了这个... Java不是一种函数式编程语言,因此我们不会将方法作为参数传递 . 话虽如此,请记住Java是面向对象的,考虑到这一点,我们可以做任何我们想做的事情 . 第一个想法是简单地传递一个“包含方法的对象”作为参数 . 因此,只要您需要“传递”该方法,只需传递该类的实例即可 . 请注意,在定义方法时,应将参数作为参数添加到包含该方法的类的实例 . 这应该可行,但它不是我们想要的,因为你不能重新定义方法,除非你有权访问类代码,并且在许多情况下这是不可能的;而且,我认为如果有人需要将方法作为参数传递,那是因为该方法的行为应该是动态的 . 我的意思是,使用您的类的程序员应该能够选择应该返回的方法,而不是它的类型 . 幸运的是,Java有一个美观而简单的解决方案:抽象类 . 简而言之,当您知道方法的“签名”时,会使用抽象类,但不知道它的行为......您可以将方法的名称和类型包装在抽象类中,并将该类的实例作为方法的参数......等等......是不是和以前一样?你可以有一个抽象类的实例吗?不和不......但是也是......当你创建一个抽象方法时你还必须在扩展抽象类的类中重新定义它,并且由于java的动态绑定,Java将始终(除非你声明它是静态的,私有的和其他一些东西)使用它的重新定义版本 . 这是一个例子......假设我们要将一个函数应用于数字数组:所以如果我们想要平方输入输出应该看起来像这样[1,2,3,4,...] - > [1,4,9,16 ,...](在像haskell这样的函数式编程语言中,这很简单,感谢像'map'这样的工具......) . 请注意,对于数字的平方没有什么特别之处,我们可以应用任何我们想要的函数吨 . 所以代码应该是这样的[args],f - > [f(args)] . 背部to java =>一个函数只是一个方法,所以我们想要的是一个将另一个函数应用于数组的函数 . 简而言之,我们需要将方法作为参数传递 . 这是我怎么做的==>
1)定义WRAPPER抽象类和方法
2)使用APPLY_TO_ARRAY方法定义类
3)创建一个TESTER-CLASS并且有一些乐趣
请注意,我们需要传递一个Function类型的对象,因为Testclass扩展了我们可以使用它的Function类,所以强制转换是自动的 .