문제

Java 메소드에서 호출 기능을 전달하는 방법이 있습니까?

내가 모방하려는 동작은 .NET 대의원이 함수로 전달되는 것입니다.

나는 사람들이 별도의 물건을 만드는 것을 제안하는 것을 보았지만 과도하게 보이는 것처럼 보이지만 때로는 과잉이 일을하는 유일한 방법이라는 것을 알고 있습니다.

도움이 되었습니까?

해결책

.NET 익명 대의원과 같은 것을 의미한다면 Java의 익명 클래스도 사용할 수 있다고 생각합니다.

public class Main {

    public interface Visitor{
        int doJob(int a, int b);
    }


    public static void main(String[] args) {
        Visitor adder = new Visitor(){
            public int doJob(int a, int b) {
                return a + b;
            }
        };

        Visitor multiplier = new Visitor(){
            public int doJob(int a, int b) {
                return a*b;
            }
        };

        System.out.println(adder.doJob(10, 20));
        System.out.println(multiplier.doJob(10, 20));

    }
}

다른 팁

Java 8 이후 람다와 메소드 참조가 있습니다.

예를 들어, 정의하겠습니다.

public class FirstClass {
    String prefix;
    public FirstClass(String prefix){
        this.prefix = prefix;
    }
    public String addPrefix(String suffix){
        return prefix +":"+suffix;
    }
}

그리고

import java.util.function.Function;

public class SecondClass {
    public String applyFunction(String name, Function<String,String> function){
        return function.apply(name);
    }
}

그런 다음 할 수 있습니다 :

FirstClass first = new FirstClass("first");
SecondClass second = new SecondClass();
System.out.println(second.applyFunction("second",first::addPrefix));

GitHub에서 예제를 찾을 수 있습니다. Julien-Diener/Methodreference.

단순화를 위해 a를 사용할 수 있습니다 실행 가능:

private void runCallback(Runnable callback)
{
    // Run callback
    callback.run();
}

용법:

runCallback(new Runnable()
{
    @Override
    public void run()
    {
        // Running callback
    }
});

약간의 nitpicking :

나는 사람들이 별도의 물건을 만드는 것을 제안하는 것처럼 보이지만 그것은 과잉처럼 보입니다.

콜백을 전달하려면 거의 모든 OO 언어로 별도의 개체를 만드는 것이 포함되므로 과잉으로 간주 될 수 없습니다. 아마도 당신이 의미하는 바는 Java에서는 명백한 일류 기능이나 폐쇄가있는 언어보다 더 장악 (그리고 더 많은 자원 집약적)를 만들어야한다는 것입니다. 그러나 익명의 클래스는 최소한 구두 성을 줄이고 인라인으로 사용할 수 있습니다.

그러나 나는 내가 찾고 있던 가장 선호되는 방법이 있음을 알았습니다. 그것은 기본적 으로이 답변에서 파생되었지만 더 중복적이고 효율적으로 그것을 조작해야했습니다. 그리고 나는 모두 내가 내가 생각하는 것을 찾는 것 같아요

요점에 ::

먼저 인터페이스를 만듭니다 그 간단합니다

public interface myCallback {
    void onSuccess();
    void onError(String err);
}

이제 결과를 처리하기 위해이 콜백을 실행하려면 - 비동기 호출 후 가능성이 더 높으면이 재사용에 의존하는 물건을 실행하고 싶을 가능성이 높습니다.

// import the Interface class here

public class App {

    public static void main(String[] args) {
        // call your method
        doSomething("list your Params", new myCallback(){
            @Override
            public void onSuccess() {
                // no errors
                System.out.println("Done");
            }

            @Override
            public void onError(String err) {
                // error happen
                System.out.println(err);
            }
        });
    }

    private void doSomething(String param, // some params..
                             myCallback callback) {
        // now call onSuccess whenever you want if results are ready
        if(results_success)
            callback.onSuccess();
        else
            callback.onError(someError);
    }

}

doSomething 결과가 올 때 콜백을 추가하려면 시간이 걸리는 기능 이후이 메소드의 콜백 인터페이스를 매개 변수로 추가하십시오.

내 요점이 분명하기를 바랍니다.

Lambdas와 함께 Java 8에서는 매우 쉽습니다.

public interface Callback {
    void callback();
}

public class Main {
    public static void main(String[] args) {
        methodThatExpectsACallback(() -> System.out.println("I am the callback."));
    }
    private static void methodThatExpectsACallback(Callback callback){
        System.out.println("I am the method.");
        callback.callback();
    }
}

나는 반사 라이브러리를 사용하여 흥미롭게 구현한다는 아이디어를 발견했으며 이것을 잘 생각했습니다. 유일한 다운 사이드는 유효한 매개 변수를 전달하는 컴파일 타임 체크를 잃는 것입니다.

public class CallBack {
    private String methodName;
    private Object scope;

    public CallBack(Object scope, String methodName) {
        this.methodName = methodName;
        this.scope = scope;
    }

    public Object invoke(Object... parameters) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Method method = scope.getClass().getMethod(methodName, getParameterClasses(parameters));
        return method.invoke(scope, parameters);
    }

    private Class[] getParameterClasses(Object... parameters) {
        Class[] classes = new Class[parameters.length];
        for (int i=0; i < classes.length; i++) {
            classes[i] = parameters[i].getClass();
        }
        return classes;
    }
}

당신은 이것처럼 그것을 사용합니다

public class CallBackTest {
    @Test
    public void testCallBack() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        TestClass testClass = new TestClass();
        CallBack callBack = new CallBack(testClass, "hello");
        callBack.invoke();
        callBack.invoke("Fred");
    }

    public class TestClass {
        public void hello() {
            System.out.println("Hello World");
        }

        public void hello(String name) {
            System.out.println("Hello " + name);
        }
    }
}

방법은 Java의 일류 객체가 아닙니다. 콜백으로 함수 포인터를 전달할 수 없습니다. 대신, 필요한 메소드가 포함 된 객체 (일반적으로 인터페이스를 구현하고)를 만들고 전달하십시오.

당신이 찾고있는 행동을 제공 할 Java의 폐쇄 제안은 만들어졌지만 다가오는 Java 7 릴리스에는 아무도 포함되지 않을 것입니다.

Java에서 이런 종류의 기능이 필요할 때는 보통 사용합니다. 관찰자 패턴. 여분의 객체를 암시하지만, 그것은 깨끗한 방법이라고 생각하며, 널리 이해되는 패턴으로 코드 가독성에 도움이됩니다.

Lambdaj Library에서 폐쇄를 구현 한 방법을 확인하십시오. 그들은 실제로 C# 대표와 매우 유사한 행동을 가지고 있습니다.

http://code.google.com/p/lambdaj/wiki/closures

'콜백'을 구현하기 위해 java.lang.reflct를 사용해 보았습니다. 샘플은 다음과 같습니다.

package StackOverflowQ443708_JavaCallBackTest;

import java.lang.reflect.*;
import java.util.concurrent.*;

class MyTimer
{
    ExecutorService EXE =
        //Executors.newCachedThreadPool ();
        Executors.newSingleThreadExecutor ();

    public static void PrintLine ()
    {
        System.out.println ("--------------------------------------------------------------------------------");
    }

    public void SetTimer (final int timeout, final Object obj, final String methodName, final Object... args)
    {
        SetTimer (timeout, obj, false, methodName, args);
    }
    public void SetTimer (final int timeout, final Object obj, final boolean isStatic, final String methodName, final Object... args)
    {
        Class<?>[] argTypes = null;
        if (args != null)
        {
            argTypes = new Class<?> [args.length];
            for (int i=0; i<args.length; i++)
            {
                argTypes[i] = args[i].getClass ();
            }
        }

        SetTimer (timeout, obj, isStatic, methodName, argTypes, args);
    }
    public void SetTimer (final int timeout, final Object obj, final String methodName, final Class<?>[] argTypes, final Object... args)
    {
        SetTimer (timeout, obj, false, methodName, argTypes, args);
    }
    public void SetTimer (final int timeout, final Object obj, final boolean isStatic, final String methodName, final Class<?>[] argTypes, final Object... args)
    {
        EXE.execute (
            new Runnable()
            {
                public void run ()
                {
                    Class<?> c;
                    Method method;
                    try
                    {
                        if (isStatic) c = (Class<?>)obj;
                        else c = obj.getClass ();

                        System.out.println ("Wait for " + timeout + " seconds to invoke " + c.getSimpleName () + "::[" + methodName + "]");
                        TimeUnit.SECONDS.sleep (timeout);
                        System.out.println ();
                        System.out.println ("invoking " + c.getSimpleName () + "::[" + methodName + "]...");
                        PrintLine ();
                        method = c.getDeclaredMethod (methodName, argTypes);
                        method.invoke (obj, args);
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                    finally
                    {
                        PrintLine ();
                    }
                }
            }
        );
    }
    public void ShutdownTimer ()
    {
        EXE.shutdown ();
    }
}

public class CallBackTest
{
    public void onUserTimeout ()
    {
        System.out.println ("onUserTimeout");
    }
    public void onTestEnd ()
    {
        System.out.println ("onTestEnd");
    }
    public void NullParameterTest (String sParam, int iParam)
    {
        System.out.println ("NullParameterTest: String parameter=" + sParam + ", int parameter=" + iParam);
    }
    public static void main (String[] args)
    {
        CallBackTest test = new CallBackTest ();
        MyTimer timer = new MyTimer ();

        timer.SetTimer ((int)(Math.random ()*10), test, "onUserTimeout");
        timer.SetTimer ((int)(Math.random ()*10), test, "onTestEnd");
        timer.SetTimer ((int)(Math.random ()*10), test, "A-Method-Which-Is-Not-Exists");    // java.lang.NoSuchMethodException

        timer.SetTimer ((int)(Math.random ()*10), System.out, "println", "this is an argument of System.out.println() which is called by timer");
        timer.SetTimer ((int)(Math.random ()*10), System.class, true, "currentTimeMillis");
        timer.SetTimer ((int)(Math.random ()*10), System.class, true, "currentTimeMillis", "Should-Not-Pass-Arguments");    // java.lang.NoSuchMethodException

        timer.SetTimer ((int)(Math.random ()*10), String.class, true, "format", "%d %X", 100, 200); // java.lang.NoSuchMethodException
        timer.SetTimer ((int)(Math.random ()*10), String.class, true, "format", "%d %X", new Object[]{100, 200});

        timer.SetTimer ((int)(Math.random ()*10), test, "NullParameterTest", new Class<?>[]{String.class, int.class}, null, 888);

        timer.ShutdownTimer ();
    }
}

당신은 또한 할 수 있습니다Callback 사용 Delegate 무늬:

Callback.java

public interface Callback {
    void onItemSelected(int position);
}

PagerActivity.java

public class PagerActivity implements Callback {

    CustomPagerAdapter mPagerAdapter;

    public PagerActivity() {
        mPagerAdapter = new CustomPagerAdapter(this);
    }

    @Override
    public void onItemSelected(int position) {
        // Do something
        System.out.println("Item " + postion + " selected")
    }
}

CustomPagerAdapter.java

public class CustomPagerAdapter {
    private static final int DEFAULT_POSITION = 1;
    public CustomPagerAdapter(Callback callback) {
        callback.onItemSelected(DEFAULT_POSITION);
    }
}

최근에 다음과 같은 일을 시작했습니다.

public class Main {
    @FunctionalInterface
    public interface NotDotNetDelegate {
        int doSomething(int a, int b);
    }

    public static void main(String[] args) {
        // in java 8 (lambdas):
        System.out.println(functionThatTakesDelegate((a, b) -> {return a*b;} , 10, 20));

    }

    public static int functionThatTakesDelegate(NotDotNetDelegate del, int a, int b) {
        // ...
        return del.doSomething(a, b);
    }
}

그럼에도 불구하고 조금 늙었지만 ... Peter Wilkinson의 대답은 int/integer와 같은 원시적 유형에 효과가 없다는 사실을 제외하고는 좋은 것을 발견했습니다. 문제는 .getClass()parameters[i], 예를 들어 반환합니다 java.lang.Integer, 반면에 올바르게 해석되지 않을 것입니다. getMethod(methodName,parameters[]) (자바의 잘못) ...

나는 그것을 Daniel Spiewak의 제안과 결합했습니다.이것에 대한 그의 대답에서); 성공 단계 : 잡기 NoSuchMethodException -> getMethods() -> 일치하는 것을 찾고 있습니다 method.getName() -> 그런 다음 매개 변수 목록을 통해 명시 적으로 루핑하고 Daniels 솔루션을 적용하여 유형 일치 및 서명 일치를 식별합니다.

나는 추상 수업을 사용하는 것이 더 우아하다고 생각합니다.

// Something.java

public abstract class Something {   
    public abstract void test();        
    public void usingCallback() {
        System.out.println("This is before callback method");
        test();
        System.out.println("This is after callback method");
    }
}

// CallbackTest.java

public class CallbackTest extends Something {
    @Override
    public void test() {
        System.out.println("This is inside CallbackTest!");
    }

    public static void main(String[] args) {
        CallbackTest myTest = new CallbackTest();
        myTest.usingCallback();
    }    
}

/*
Output:
This is before callback method
This is inside CallbackTest!
This is after callback method
*/
public class HelloWorldAnonymousClasses {

    //this is an interface with only one method
    interface HelloWorld {
        public void printSomething(String something);
    }

    //this is a simple function called from main()
    public void sayHello() {

    //this is an object with interface reference followed by the definition of the interface itself

        new HelloWorld() {
            public void printSomething(String something) {
                System.out.println("Hello " + something);
            }
        }.printSomething("Abhi");

     //imagine this as an object which is calling the function'printSomething()"
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp =
                new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }
}
//Output is "Hello Abhi"

기본적으로 인터페이스의 객체를 만들려면 인터페이스에 객체를 가질 수 없기 때문에 불가능합니다.

옵션은 일부 클래스가 인터페이스를 구현 한 다음 해당 클래스의 객체를 사용하여 해당 함수를 호출하도록하는 것입니다. 그러나이 접근법은 실제로 장점입니다.

또는 New HelloWorld () (*Oberserve 이것은 클래스가 아닌 인터페이스입니다)를 작성한 다음 인터페이스 메소드 자체의 정의로이를 따르십시오. (*이 정의는 실제로 익명 클래스입니다). 그런 다음 메소드 자체를 호출 할 수있는 객체 참조를 얻습니다.

인터페이스를 만들고 콜백 클래스에서 동일한 인터페이스 속성을 만듭니다.

interface dataFetchDelegate {
    void didFetchdata(String data);
}
//callback class
public class BackendManager{
   public dataFetchDelegate Delegate;

   public void getData() {
       //Do something, Http calls/ Any other work
       Delegate.didFetchdata("this is callbackdata");
   }

}

이제 다시 호출하려는 클래스에서 위의 생성 된 인터페이스를 구현하십시오. 또한 클래스의 "이"객체/참조를 통과시킬 수 있습니다.

public class Main implements dataFetchDelegate
{       
    public static void main( String[] args )
    {
        new Main().getDatafromBackend();
    }

    public void getDatafromBackend() {
        BackendManager inc = new BackendManager();
        //Pass this object as reference.in this Scenario this is Main Object            
        inc.Delegate = this;
        //make call
        inc.getData();
    }

    //This method is called after task/Code Completion
    public void didFetchdata(String callbackData) {
        // TODO Auto-generated method stub
        System.out.println(callbackData);
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top