variable - java interface範例




Java Pass方法作為參數 (8)

我正在尋找一種通過引用來傳遞方法的方法。 我明白,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());

Java確實有一個機制來傳遞名稱並調用它。 它是反射機制的一部分。 您的函數應該採用類Method的附加參數。

public void YouMethod(..... Method methodToCall, Object objWithAllMethodsToBeCalled)
{
...
Object retobj = methodToCall.invoke(objWithAllMethodsToBeCalled, arglist);
...
}

編輯 :從Java 8開始, lambda表達式是other answers指出的一個很好的解決方案。 下面的答案是為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指出的 ,還有另一種使用Visitor進行此操作的方法。 訪問者方法有一點涉及 - 你的節點都需要用acceptVisitor()方法來訪問感知 - 但是如果你需要遍歷一個更複雜的對像圖,那麼這是值得研究的。


使用java.lang.reflect.Method對象並調用invoke


使用觀察者模式(有時也稱為監聽者模式):

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()...聲明一個實現接口的匿名類型。


在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;
    }
    

    返回語句不是表達式; 在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));
    }
}

如果你不需要這些方法來返回一些東西,你可以讓它們返回Runnable對象。

private Runnable methodName (final int arg){
    return new Runnable(){
       public void run(){
          // do stuff with arg
       }
    }
}

然後像這樣使用它:

private void otherMethodName (Runnable arg){
    arg.run();
}

我不是一個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());
          }
        })

這是一個基本的例子:

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




interface