Java传递方法作为参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2186931/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Pass Method as Parameter
提问by
I am looking for a way to pass a method by reference. I understand that Java does not pass methods as parameters, however, I would like to get an alternative.
我正在寻找一种通过引用传递方法的方法。我知道 Java 不会将方法作为参数传递,但是,我想获得替代方法。
I've been told interfaces are the alternative to passing methods as parameters but I don't understand how an interface can act as a method by reference. If I understand correctly an interface is simply an abstract set of methods that are not defined. I don't want to send an interface that needs to be defined every time because several different methods could call the same method with the same parameters.
有人告诉我接口是将方法作为参数传递的替代方法,但我不明白接口如何通过引用充当方法。如果我理解正确,接口只是一组未定义的抽象方法。我不想发送每次都需要定义的接口,因为几个不同的方法可以使用相同的参数调用相同的方法。
What I would like to accomplish is something similar to this:
我想完成的是类似的事情:
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
}
invoked such as:
调用,例如:
setAllComponents(this.getComponents(), changeColor());
setAllComponents(this.getComponents(), changeSize());
采纳答案by Dan Vinton
Edit: as of Java 8, lambda expressionsare a nice solution as otheranswershave pointed out. The answer below was written for Java 7 and earlier...
编辑:从 Java 8 开始,正如其他答案所指出的那样,lambda 表达式是一个不错的解决方案。下面的答案是为 Java 7 及更早版本编写的......
Take a look at the command pattern.
看看命令模式。
// 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");
}
}
Edit:as Pete Kirkham points out, there's another way of doing this using a Visitor. The visitor approach is a little more involved - your nodes all need to be visitor-aware with an acceptVisitor()
method - but if you need to traverse a more complex object graph then it's worth examining.
编辑:正如Pete Kirkham 指出的那样,还有另一种使用Visitor 的方法。访问者方法稍微复杂一点——你的节点都需要通过一个acceptVisitor()
方法来感知访问者——但是如果你需要遍历一个更复杂的对象图,那么值得研究一下。
回答by Vinodh Ramasubramanian
Use the java.lang.reflect.Method
object and call invoke
使用java.lang.reflect.Method
对象并调用invoke
回答by EricSchaefer
Use the Observer pattern (sometimes also called Listener pattern):
使用观察者模式(有时也称为监听者模式):
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()...
declares an anonymous type implementing the interface.
new ComponentDelegate()...
声明一个实现接口的匿名类型。
回答by stacker
First define an Interface with the method you want to pass as a parameter
首先定义一个接口,其中包含要作为参数传递的方法
public interface Callable {
public void call(int param);
}
Implement a class with the method
用方法实现一个类
class Test implements Callable {
public void call(int param) {
System.out.println( param );
}
}
// Invoke like that
// 像这样调用
Callable cmd = new Test();
This allows you to pass cmd as parameter and invoke the method call defined in the interface
这允许您将 cmd 作为参数传递并调用接口中定义的方法调用
public invoke( Callable callable ) {
callable.call( 5 );
}
回答by user246091
Last time I checked, Java is not capable of natively doing what you want; you have to use 'work-arounds' to get around such limitations. As far as I see it, interfaces ARE an alternative, but not a good alternative. Perhaps whoever told you that was meaning something like this:
上次我检查时,Java 本身不能做你想做的事;您必须使用“变通办法”来绕过此类限制。在我看来,接口是一种替代方案,但不是一个好的替代方案。也许谁告诉你的意思是这样的:
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
}
Which you'd then invoke with:
然后你会调用它:
setAllComponents(this.getComponents(), new ChangeColor());
setAllComponents(this.getComponents(), new ChangeSize());
回答by David Gruzman
Java do have a mechanism to pass name and call it. It is part of the reflection mechanism. Your function should take additional parameter of class Method.
Java 确实有一种机制来传递名称并调用它。它是反射机制的一部分。您的函数应该采用类 Method 的附加参数。
public void YouMethod(..... Method methodToCall, Object objWithAllMethodsToBeCalled)
{
...
Object retobj = methodToCall.invoke(objWithAllMethodsToBeCalled, arglist);
...
}
回答by nanofarad
While this is not yet valid for Java 7 and below, I believe that we should look to the future and at least recognize the changesto come in new versions such as Java 8.
虽然这对 Java 7 及更低版本尚不适用,但我相信我们应该展望未来,至少认识到 Java 8 等新版本中的变化。
Namely, this new version brings lambdasand method references to Java (along with new APIs, which are another valid solution to this problem. While they still require an interface no new objects are created, and extra classfiles need not pollute output directories due to different handling by the JVM.
也就是说,这个新版本为Java带来了lambdas和方法引用(以及新的 APIs,这是解决这个问题的另一个有效方法。虽然它们仍然需要一个接口,但没有创建新对象,额外的类文件不需要由于不同的输出目录而污染输出目录)由 JVM 处理。
Both flavors(lambda and method reference) require an interface available with a single method whose signature is used:
两种风格(lambda 和方法引用)都需要一个可用于单个方法的接口,该方法使用其签名:
public interface NewVersionTest{
String returnAString(Object oIn, String str);
}
Names of methods will not matter from here on. Where a lambda is accepted, a method reference is as well. For example, to use our signature here:
从这里开始,方法的名称将不再重要。在接受 lambda 的地方,方法引用也是如此。例如,在这里使用我们的签名:
public static void printOutput(NewVersionTest t, Object o, String s){
System.out.println(t.returnAString(o, s));
}
This is just a simple interface invocation, up until the lambda1gets passed:
这只是一个简单的接口调用,直到 lambda 1被传递:
public static void main(String[] args){
printOutput( (Object oIn, String sIn) -> {
System.out.println("Lambda reached!");
return "lambda return";
}
);
}
This will output:
这将输出:
Lambda reached!
lambda return
Method references are similar. Given:
方法引用类似。鉴于:
public class HelperClass{
public static String testOtherSig(Object o, String s){
return "real static method";
}
}
and main:
和主要:
public static void main(String[] args){
printOutput(HelperClass::testOtherSig);
}
the output would be real static method
. Method references can be static, instance, non-static with arbitrary instances, and even constructors. For the constructor something akin to ClassName::new
would be used.
输出将是real static method
. 方法引用可以是静态的、实例的、具有任意实例的非静态的,甚至是构造函数。对于构造函数,ClassName::new
将使用类似的东西。
1This is not considered a lambda by some, as it has side effects. It does illustrate, however, the use of one in a more straightforward-to-visualize fashion.
1这不被一些人认为是 lambda,因为它有副作用。然而,它确实以一种更直观的方式说明了一个的使用。
回答by Smig
If you don't need these methods to return something, you could make them return Runnable objects.
如果您不需要这些方法返回某些东西,您可以让它们返回 Runnable 对象。
private Runnable methodName (final int arg) {
return (new Runnable() {
public void run() {
// do stuff with arg
}
});
}
Then use it like:
然后像这样使用它:
private void otherMethodName (Runnable arg){
arg.run();
}
回答by The Guy with The Hat
In Java 8, you can now pass a method more easily using Lambda Expressionsand Method References. First, some background: a functional interface is an interface that has one and only one abstract method, although it can contain any number of default methods(new in Java 8) and static methods. A lambda expression can quickly implement the abstract method, without all the unnecessary syntax needed if you don't use a lambda expression.
在 Java 8 中,您现在可以使用Lambda 表达式和方法引用更轻松地传递方法。首先,一些背景知识:函数式接口是一个只有一个抽象方法的接口,尽管它可以包含任意数量的默认方法(Java 8 中的新方法)和静态方法。lambda 表达式可以快速实现抽象方法,如果不使用 lambda 表达式,则不需要所有不必要的语法。
Without lambda expressions:
没有 lambda 表达式:
obj.aMethod(new AFunctionalInterface() {
@Override
public boolean anotherMethod(int i)
{
return i == 982
}
});
With lambda expressions:
使用 lambda 表达式:
obj.aMethod(i -> i == 982);
Here is an excerpt from the Java tutorial on Lambda Expressions:
以下是关于 Lambda 表达式的 Java 教程的摘录:
Syntax of Lambda Expressions
A lambda expression consists of the following:
A comma-separated list of formal parameters enclosed in parentheses. The CheckPerson.test method contains one parameter, p, which represents an instance of the Person class.
Note: You can omit the data type of the parameters in a lambda expression. In addition, you can omit the parentheses if there is only one parameter. For example, the following lambda expression is also valid:p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25
The arrow token,
->
A body, which consists of a single expression or a statement block. This example uses the following expression:
p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25
If you specify a single expression, then the Java runtime evaluates the expression and then returns its value. Alternatively, you can use a return statement:
p -> { return p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25; }
A return statement is not an expression; in a lambda expression, you must enclose statements in braces ({}). However, you do not have to enclose a void method invocation in braces. For example, the following is a valid lambda expression:
email -> System.out.println(email)
Note that a lambda expression looks a lot like a method declaration; you can consider lambda expressions as anonymous methods—methods without a name.
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 表达式视为匿名方法——没有名称的方法。
Here is how you can "pass a method" using a lambda expression:
以下是使用 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));
}
}
Class C
can be shortened even a bit further by the use of method references like so:
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);
}
}
回答by BullyWiiPlaza
Here is a basic example:
这是一个基本示例:
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);
}
}
Output:
输出:
Do println
Do print