سؤال

هل هناك طريقة لتمرير استدعاء دالة أخرى في جافا الأسلوب ؟

سلوك أحاول تقليد هو .صافي مندوب يتم تمريرها إلى الدالة.

رأيت الناس تقترح إنشاء كائن منفصل ولكن هذا يبدو مبالغة ، ومع ذلك أنا على علم أنه في بعض الأحيان مبالغة هو الطريقة الوحيدة لفعل الأشياء.

هل كانت مفيدة؟

المحلول

إذا كنت تعني سومثينغ مثل مندوب مجهول. NET، وأعتقد أن الطبقة مجهولة جافا ويمكن أن تستخدم أيضا.

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));

    }
}

نصائح أخرى

منذ جافا 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));

يمكنك العثور على مثال على جيثب, هنا: julien-دينر/MethodReference.

عن البساطة ، يمكنك استخدام Runnable:

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

الاستخدام:

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

القليل من نيتبيكينج:

لقد يبدو الناس تقترح إنشاء منفصلة كائن ولكن يبدو أن مبالغة

يمر الاستدعاء يشمل إنشاء كائن منفصل في كثير جدا من أي OO اللغة ، لذلك لا يمكن اعتباره مبالغة.ما قد يعني أن في جاوة ، فإنه يتطلب منك إنشاء فئة منفصلة ، وهو أكثر مطول (وأكثر كثيفة الموارد) في لغة صريحة وظائف من الدرجة الأولى أو الإغلاق.ومع ذلك ، مجهول فصول على الأقل الحد من الإسهاب و يمكن استخدامها مضمنة.

حتى الآن أرى أن هناك ما هو أكثر الطريقة المفضلة التي ما كنت أبحث عنه..انها في الاساس المستمدة من هذه الإجابات ولكن اضطررت إلى التعامل مع ذلك إلى المزيد من زائدة و كفاءة.. و أعتقد أن الجميع يبحث عن ما خرجت به

إلى نقطة::

أولا جعل واجهة بهذه البساطة

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

الآن لجعل هذا رد تشغيل أي وقت مضى عندما كنت ترغب في القيام به للتعامل مع النتائج على الأرجح بعد استدعاء متزامن و تريد تشغيل بعض الاشياء التي تعتمد على هذه reuslts

// 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 هي الدالة التي تأخذ بعض الوقت تريد إضافة رد عليه أن يخطر لك عندما جاءت النتائج, إضافة الإتصال واجهة كمعلمة إلى هذا الأسلوب

أتمنى وجهة نظري هو واضح ، والتمتع ;)

وهذا من السهل جدا في جاوة 8 مع lambdas.

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

وهناك طريقة ليست (حتى الآن) كائن من الدرجة الأولى في جاوة. لا يمكنك تمرير مؤشر دالة على أنها رد. بدلا من ذلك، إنشاء كائن (والتي عادة ما تنفذ واجهة) الذي يحتوي على الطريقة التي تحتاج إليها وتمرير ذلك.

ومقترحات للإغلاق في جافا والتي من شأنها أن توفر سلوك كنت تبحث عن-بذلت، ولكنها ستدرج لا شيء في القادم الافراج جافا 7.

وعندما كنت بحاجة إلى هذا النوع من الوظائف في جاوة، وعادة ما تستخدم في نمط المراقب . فإنه لا يعني كائن اضافية، ولكن اعتقد انها وسيلة نظيفة للذهاب، وهو نمط مفهومة على نطاق واسع، مما يساعد على سهولة قراءة التعليمات البرمجية.

والتحقق من إغلاق الكيفية التي تم تنفيذها في المكتبة lambdaj. لديهم في الواقع سلوك مشابه جدا لC # المندوبين:

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

وحاولت استخدام java.lang.reflect لتنفيذ "رد"، وهنا عينة:

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 ();
    }
}

ويمكنك أيضا القيام theCallback باستخدام نمط 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);
    }
}

وأنها قديمة بعض الشيء، ولكن مع ذلك ... لقد وجدت إجابة لبيتر ويلكنسون لطيفة باستثناء حقيقة أنه لا يعمل لأنواع بدائية مثل الباحث / صحيح. المشكلة هي .getClass() لparameters[i]، والتي ترجع لjava.lang.Integer سبيل المثال، والتي من ناحية أخرى لن يتم تفسيرها بشكل صحيح من قبل getMethod(methodName,parameters[]) (خطأ جاوة) ...

وأنا دمجها مع اقتراح دانيال Spiewak (<لأ href = "https://stackoverflow.com/questions/180097/dynamically-find-the-class-that-represents-a-primitive-java-type" > في رده على هذا )؛ وتضمنت خطوات لتحقيق النجاح: اصطياد NoSuchMethodException -> getMethods() -> تبحث عن مطابقة احدا تلو method.getName() -> ثم صراحة حلقات خلال قائمة المعلمات وتطبيق حل دانيلز، مثل تحديد المباريات نوع ويطابق التوقيع

.

وأعتقد أن استخدام فئة مجردة هي أكثر أناقة، مثل هذا:

// 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"

وأساسا إذا كنت تريد أن تجعل الكائن من واجهة هو غير ممكن، لأن واجهة لا يمكن أن يكون الكائنات.

والخيار هو السماح لبعض الطبقة تنفيذ واجهة ثم استدعاء هذه الوظيفة باستخدام كائن من تلك الفئة. ولكن هذا النهج هو مطول حقا.

وبدلا من ذلك، إرسال HelloWorld جديد () (* oberserve هذا هو واجهة ليس فئة) ومن ثم متابعة هذا الامر مع defination من أساليب الواجهة نفسها. (* هذا defination هو في واقع الطبقة مجهول). ثم تحصل على مرجع كائن من خلالها يمكنك استدعاء الأسلوب نفسه.

وإنشاء واجهة، وإنشاء واجهة العقار نفسه في استدعاء فئة.

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