Java 代表?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44912/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:34:05  来源:igfitidea点击:

Java Delegates?

javadelegates

提问by markus

Does the Java language have delegate features, similar to how C# has support for delegates?

Java 语言是否具有委托功能,类似于 C# 对委托的支持?

采纳答案by Matt Sheppard

Not really, no.

不是真的,不是。

You may be able to achieve the same effect by using reflection to get Method objects you can then invoke, and the other way is to create an interface with a single 'invoke' or 'execute' method, and then instantiate them to call the method your interested in (i.e. using an anonymous inner class).

您也许可以通过使用反射来获取可以调用的 Method 对象来达到相同的效果,另一种方法是创建一个具有单个“invoke”或“execute”方法的接口,然后将它们实例化以调用该方法您感兴趣(即使用匿名内部类)。

You might also find this article interesting / useful : A Java Programmer Looks at C# Delegates (@archive.org)

您可能还会发现这篇文章很有趣/有用:Java Programmer Looks at C# Delegates (@archive.org)

回答by Patrick

Short story: -------------------no.

短篇小说:--------------------没有

Introduction

The newest version of the Microsoft Visual J++ development environment supports a language construct called delegatesor bound method references. This construct, and the new keywords delegateand multicastintroduced to support it, are not a part of the JavaTMprogramming language, which is specified by the Java Language Specificationand amended by the Inner Classes Specificationincluded in the documentation for the JDKTM 1.1 software.

It is unlikely that the Java programming language will ever include this construct. Sun already carefully considered adopting it in 1996, to the extent of building and discarding working prototypes. Our conclusion was that bound method references are unnecessary and detrimental to the language. This decision was made in consultation with Borland International, who had previous experience with bound method references in Delphi Object Pascal.

We believe bound method references are unnecessarybecause another design alternative, inner classes, provides equal or superior functionality. In particular, inner classes fully support the requirements of user-interface event handling, and have been used to implement a user-interface API at least as comprehensive as the Windows Foundation Classes.

We believe bound method references are harmfulbecause they detract from the simplicity of the Java programming language and the pervasively object-oriented character of the APIs. Bound method references also introduce irregularity into the language syntax and scoping rules. Finally, they dilute the investment in VM technologies because VMs are required to handle additional and disparate types of references and method linkage efficiently.

介绍

最新版本的 Microsoft Visual J++ 开发环境支持一种称为委托绑定方法引用的语言结构。此构造以及为支持它delegatemulticast引入的新关键字不是 Java TM编程语言的一部分,Java TM编程语言由Java 语言规范指定并由JDKTM 1.1 软件文档中包含的内部类规范修订。

Java 编程语言不太可能包含这种构造。Sun 在 1996 年就已经仔细考虑采用它,以构建和丢弃工作原型。我们的结论是绑定方法引用是不必要的并且对语言有害。该决定是在与 Borland International 协商后做出的,Borland International 以前在 Delphi Object Pascal 中具有绑定方法引用的经验。

我们认为绑定方法引用是不必要的,因为另一个设计替代方案,内部类,提供了相同或更好的功能。特别是,内部类完全支持用户界面事件处理的要求,并且已经用于实现至少与 Windows 基础类一样全面的用户界面 API。

我们认为绑定方法引用是有害的,因为它们有损 Java 编程语言的简单性和 API 普遍的面向对象特性。绑定方法引用还会在语言语法和范围规则中引入不规则性。最后,它们稀释了对 VM 技术的投资,因为 VM 需要有效地处理额外和不同类型的引用和方法链接。

回答by John Meagher

While it is nowhere nearly as clean, but you could implement something like C# delegates using a Java Proxy.

虽然它几乎没有那么干净,但您可以使用 Java Proxy实现类似 C# 委托的东西。

回答by Lawrence Dol

I have implemented callback/delegate support in Java using reflection. Details and working source are available on my website.

我已经使用反射在 Java 中实现了回调/委托支持。详细信息和工作来源可在我的网站上找到

How It Works

这个怎么运作

There is a principle class named Callback with a nested class named WithParms. The API which needs the callback will take a Callback object as a parameter and, if neccessary, create a Callback.WithParms as a method variable. Since a great many of the applications of this object will be recursive, this works very cleanly.

有一个名为 Callback 的原理类和一个名为 WithParms 的嵌套类。需要回调的 API 将接受一个 Callback 对象作为参数,并在必要时创建一个 Callback.WithParms 作为方法变量。由于这个对象的很多应用程序都是递归的,所以这非常干净。

With performance still a high priority to me, I didn't want to be required to create a throwaway object array to hold the parameters for every invocation - after all in a large data structure there could be thousands of elements, and in a message processing scenario we could end up processing thousands of data structures a second.

由于性能仍然是我的重中之重,我不想被要求创建一个一次性对象数组来保存每次调用的参数 - 毕竟在大型数据结构中可能有数千个元素,并且在消息处理中我们可能最终每秒处理数千个数据结构。

In order to be threadsafe the parameter array needs to exist uniquely for each invocation of the API method, and for efficiency the same one should be used for every invocation of the callback; I needed a second object which would be cheap to create in order to bind the callback with a parameter array for invocation. But, in some scenarios, the invoker would already have a the parameter array for other reasons. For these two reasons, the parameter array does not belong in the Callback object. Also the choice of invocation (passing the parameters as an array or as individual objects) belongs in the hands of the API using the callback enabling it to use whichever invocation is best suited to its inner workings.

为了线程安全,API 方法的每次调用都需要唯一存在的参数数组,并且为了提高效率,每次调用回调都应该使用相同的参数数组;我需要创建第二个对象,以便将回调与参数数组绑定以进行调用。但是,在某些情况下,由于其他原因,调用者已经拥有一个参数数组。由于这两个原因,参数数组不属于回调对象。此外,调用的选择(将参数作为数组或作为单个对象传递)属于使用回调的 API 的手中,使其能够使用最适合其内部工作的调用。

The WithParms nested class, then, is optional and serves two purposes, it contains the parameter object array needed for the callback invocations, and it provides 10 overloaded invoke() methods (with from 1 to 10 parameters) which load the parameter array and then invoke the callback target.

WithParms 嵌套类是可选的,有两个用途,它包含回调调用所需的参数对象数组,它提供 10 个重载的 invoke() 方法(具有 1 到 10 个参数),这些方法加载参数数组,然后调用回调目标。

What follows is an example using a callback to process the files in a directory tree. This is an initial validation pass which just counts the files to process and ensure none exceed a predetermined maximum size. In this case we just create the callback inline with the API invocation. However, we reflect the target method out as a static value so that the reflection is not done every time.

下面是一个使用回调处理目录树中文件的示例。这是一个初始验证通过,它只计算要处理的文件并确保没有超过预定的最大大小。在这种情况下,我们只创建与 API 调用内联的回调。但是,我们将目标方法反射为静态值,因此不会每次都进行反射。

static private final Method             COUNT =Callback.getMethod(Xxx.class,"callback_count",true,File.class,File.class);

...

IoUtil.processDirectory(root,new Callback(this,COUNT),selector);

...

private void callback_count(File dir, File fil) {
    if(fil!=null) {                                                                             // file is null for processing a directory
        fileTotal++;
        if(fil.length()>fileSizeLimit) {
            throw new Abort("Failed","File size exceeds maximum of "+TextUtil.formatNumber(fileSizeLimit)+" bytes: "+fil);
            }
        }
    progress("Counting",dir,fileTotal);
    }

IoUtil.processDirectory():

IoUtil.processDirectory():

/**
 * Process a directory using callbacks.  To interrupt, the callback must throw an (unchecked) exception.
 * Subdirectories are processed only if the selector is null or selects the directories, and are done
 * after the files in any given directory.  When the callback is invoked for a directory, the file
 * argument is null;
 * <p>
 * The callback signature is:
 * <pre>    void callback(File dir, File ent);</pre>
 * <p>
 * @return          The number of files processed.
 */
static public int processDirectory(File dir, Callback cbk, FileSelector sel) {
    return _processDirectory(dir,new Callback.WithParms(cbk,2),sel);
    }

static private int _processDirectory(File dir, Callback.WithParms cbk, FileSelector sel) {
    int                                 cnt=0;

    if(!dir.isDirectory()) {
        if(sel==null || sel.accept(dir)) { cbk.invoke(dir.getParent(),dir); cnt++; }
        }
    else {
        cbk.invoke(dir,(Object[])null);

        File[] lst=(sel==null ? dir.listFiles() : dir.listFiles(sel));
        if(lst!=null) {
            for(int xa=0; xa<lst.length; xa++) {
                File ent=lst[xa];
                if(!ent.isDirectory()) {
                    cbk.invoke(dir,ent);
                    lst[xa]=null;
                    cnt++;
                    }
                }
            for(int xa=0; xa<lst.length; xa++) {
                File ent=lst[xa];
                if(ent!=null) { cnt+=_processDirectory(ent,cbk,sel); }
                }
            }
        }
    return cnt;
    }

This example illustrates the beauty of this approach - the application specific logic is abstracted into the callback, and the drudgery of recursively walking a directory tree is tucked nicely away in a completely reusable static utility method. And we don't have to repeatedly pay the price of defining and implementing an interface for every new use. Of course, the argument foran interface is that it is far more explicit about what to implement (it's enforced, not simply documented) - but in practice I have not found it to be a problem to get the callback definition right.

这个例子说明了这种方法的美妙之处——应用程序特定的逻辑被抽象到回调中,递归遍历目录树的苦差事被很好地隐藏在一个完全可重用的静态实用方法中。而且我们不必为每个新用途重复定义和实现接口的代价。当然,参数一个接口,这是迄今为止关于如何落实更明确(它是强制执行的,不是简单的记录) -但在实践中我还没有发现它是得到回调定义权的问题。

Defining and implementing an interface is not really so bad (unless you're distributing applets, as I am, where avoiding creating extra classes actually matters), but where this really shines is when you have multiple callbacks in a single class. Not only is being forced to push them each into a separate inner class added overhead in the deployed application, but it's downright tedious to program and all that boiler-plate code is really just "noise".

定义和实现一个接口并不是那么糟糕(除非你像我一样分发小程序,避免创建额外的类实际上很重要),但是当你在一个类中有多个回调时,这真的很重要。不仅被迫将它们每个都推送到单独的内部类中会增加已部署应用程序的开销,而且编程非常乏味,而且所有样板代码实际上只是“噪音”。

回答by Michael

Have you read this:

你读过这个吗:

Delegates are a useful construct in event-based systems. Essentially Delegates are objects that encode a method dispatch on a specified object. This document shows how java inner classes provide a more generic solution to such problems.

What is a Delegate? Really it is very similar to a pointer to member function as used in C++. But a delegate contains the target object alongwith the method to be invoked. Ideally it would be nice to be able to say:

obj.registerHandler(ano.methodOne);

..and that the method methodOne would be called on ano when some specific event was received.

This is what the Delegate structure achieves.

Java Inner Classes

It has been argued that Java provides this functionality via anonymous inner classes and thus does not need the additional Delegate construct.

委托是基于事件的系统中的有用构造。本质上,委托是对指定对象上的方法分派进行编码的对象。本文档展示了 Java 内部类如何为此类问题提供更通用的解决方案。

什么是委托?实际上,它与 C++ 中使用的指向成员函数的指针非常相似。但是委托包含目标对象以及要调用的方法。理想情况下,能够说:

obj.registerHandler(ano.methodOne);

..并且当收到某个特定事件时,将在 ano 上调用方法 methodOne。

这就是 Delegate 结构实现的目标。

Java 内部类

有人认为 Java 通过匿名内部类提供此功能,因此不需要额外的 Delegate 构造。

obj.registerHandler(new Handler() {
        public void handleIt(Event ev) {
            methodOne(ev);
        }
      } );

At first glance this seems correct but at the same time a nuisance. Because for many event processing examples the simplicity of the Delegates syntax is very attractive.

General Handler

However, if event-based programming is used in a more pervasive manner, say, for example, as a part of a general asynchronous programming environment, there is more at stake.

In such a general situation, it is not sufficient to include only the target method and target object instance. In general there may be other parameters required, that are determined within the context when the event handler is registered.

In this more general situation, the java approach can provide a very elegant solution, particularly when combined with use of final variables:

乍一看,这似乎是正确的,但同时也令人讨厌。因为对于许多事件处理示例来说,Delegates 语法的简单性非常有吸引力。

一般处理程序

但是,如果以更普遍的方式使用基于事件的编程,例如,作为通用异步编程环境的一部分,则风险更大。

在这种一般情况下,仅包含目标方法和目标对象实例是不够的。通常,可能需要其他参数,这些参数是在注册事件处理程序时在上下文中确定的。

在这种更一般的情况下,java 方法可以提供非常优雅的解决方案,尤其是在结合使用 final 变量时:

void processState(final T1 p1, final T2 dispatch) { 
  final int a1 = someCalculation();

  m_obj.registerHandler(new Handler() {
    public void handleIt(Event ev) {
     dispatch.methodOne(a1, ev, p1);
    }
  } );
}

final * final * final

Got your attention?

Note that the final variables are accessible from within the anonymous class method definitions. Be sure to study this code carefully to understand the ramifications. This is potentially a very powerful technique. For example, it can be used to good effect when registering handlers in MiniDOM and in more general situations.

By contrast, the Delegate construct does not provide a solution for this more general requirement, and as such should be rejected as an idiom on which designs can be based.

决赛 * 决赛 * 决赛

引起你的注意了吗?

请注意,可以从匿名类方法定义中访问最终变量。请务必仔细研究此代码以了解其后果。这可能是一种非常强大的技术。例如,在 MiniDOM 中注册处理程序时以及更一般的情况下,它可以很好地使用。

相比之下,Delegate 结构没有为这个更普遍的要求提供解决方案,因此应该拒绝作为设计可以基于的习语。

回答by Dominic Fox

No, but they're fakeable using proxies and reflection:

不,但它们可以使用代理和反射来伪造:

  public static class TestClass {
      public String knockKnock() {
          return "who's there?";
      }
  }

  private final TestClass testInstance = new TestClass();

  @Test public void
  can_delegate_a_single_method_interface_to_an_instance() throws Exception {
      Delegator<TestClass, Callable<String>> knockKnockDelegator = Delegator.ofMethod("knockKnock")
                                                                   .of(TestClass.class)
                                                                   .to(Callable.class);
      Callable<String> callable = knockKnockDelegator.delegateTo(testInstance);
      assertThat(callable.call(), is("who's there?"));
  }

The nice thing about this idiom is that you can verify that the delegated-to method exists, and has the required signature, at the point where you create the delegator (although not at compile-time, unfortunately, although a FindBugs plug-in might help here), then use it safely to delegate to various instances.

这个习惯用法的好处是,您可以在创建委托程序时验证委托方法是否存在,并具有所需的签名(尽管不是在编译时,不幸的是,虽然 FindBugs 插件可能help here),然后安全地使用它来委托给各种实例。

See the karg code on githubfor more testsand implementation.

有关更多测试实现,请参阅github 上karg 代码

回答by Manasvi Sareen

No, but it has similar behavior, internally.

不,但它在内部具有类似的行为。

In C# delegates are used to creates a separate entry point and they work much like a function pointer.

在 C# 中,委托用于创建单独的入口点,它们的工作方式与函数指针非常相似。

In java there is no thing as function pointer (on a upper look) but internally Java needs to do the same thing in order to achieve these objectives.

在 Java 中没有函数指针(从上往下看),但在内部 Java 需要做同样的事情才能实现这些目标。

For example, creating threads in Java requires a class extending Thread or implementing Runnable, because a class object variable can be used a memory location pointer.

比如在Java中创建线程需要一个继承Thread或者实现Runnable的类,因为一个类对象变量可以作为一个内存位置指针。

回答by Dave Cousineau

Depending precisely what you mean, you can achieve a similar effect (passing around a method) using the Strategy Pattern.

根据您的意思,您可以使用策略模式实现类似的效果(传递方法)。

Instead of a line like this declaring a named method signature:

而不是像这样声明命名方法签名的行:

// C#
public delegate void SomeFunction();

declare an interface:

声明一个接口:

// Java
public interface ISomeBehaviour {
   void SomeFunction();
}

For concrete implementations of the method, define a class that implements the behaviour:

对于方法的具体实现,定义一个实现行为的类:

// Java
public class TypeABehaviour implements ISomeBehaviour {
   public void SomeFunction() {
      // TypeA behaviour
   }
}

public class TypeBBehaviour implements ISomeBehaviour {
   public void SomeFunction() {
      // TypeB behaviour
   }
}

Then wherever you would have had a SomeFunctiondelegate in C#, use an ISomeBehaviourreference instead:

然后,无论您SomeFunction在 C# 中拥有委托的任何地方,都改用ISomeBehaviour引用:

// C#
SomeFunction doSomething = SomeMethod;
doSomething();
doSomething = SomeOtherMethod;
doSomething();

// Java
ISomeBehaviour someBehaviour = new TypeABehaviour();
someBehaviour.SomeFunction();
someBehaviour = new TypeBBehaviour();
someBehaviour.SomeFunction();

With anonymous inner classes, you can even avoid declaring separate named classes and almost treat them like real delegate functions.

使用匿名内部类,您甚至可以避免声明单独的命名类,几乎将它们视为真正的委托函数。

// Java
public void SomeMethod(ISomeBehaviour pSomeBehaviour) {
   ...
}

...

SomeMethod(new ISomeBehaviour() { 
   @Override
   public void SomeFunction() {
      // your implementation
   }
});

This should probably only be used when the implementation is very specific to the current context and wouldn't benefit from being reused.

这可能只应该在实现非常特定于当前上下文并且不会从重用中受益时使用。

And then of course in Java 8, these do become basically lambda expressions:

然后当然在 Java 8 中,这些基本上变成了 lambda 表达式:

// Java 8
SomeMethod(() -> { /* your implementation */ });

回答by Leve

Java doesn't have delegates and is proud of it :). From what I read here I found in essence 2 ways to fake delegates: 1. reflection; 2. inner class

Java 没有委托,并为此感到自豪:)。从我在这里读到的内容,我发现本质上有两种伪造委托的方法:1. 反射;2.内部类

Reflections are slooooow! Inner class does not cover the simplest use-case: sort function. Do not want to go into details, but the solution with inner class basically is to create a wrapper class for an array of integers to be sorted in ascending order and an class for an array of integers to be sorted in descending order.

反射是slooooow!内部类不包括最简单的用例:排序函数。不想赘述,内部类的解决方案基本上是为整数数组按升序排序创建一个包装类,并为整数数组按降序排序创建一个类。

回答by user3311658

I know this post is old, but Java 8 has added lambdas, and the concept of a functional interface, which is any interface with only one method. Together these offer similar functionality to C# delegates. See here for more info, or just google Java Lambdas. http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html

我知道这篇文章很旧,但 Java 8 添加了 lambda 表达式和函数式接口的概念,即任何只有一个方法的接口。它们一起提供了与 C# 委托类似的功能。有关更多信息,请参阅此处,或仅使用 google Java Lambdas。 http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html