Java代表?
Java语言是否具有代理功能,类似于Chas对代理的支持方式?
解决方案
回答
短篇小说:-------------------不。
Introduction The newest version of the Microsoft Visual J++ development environment supports a language construct called delegates or bound method references. This construct, and the new keywords delegate and multicast introduced to support it, are not a part of the JavaTM programming language, which is specified by the Java Language Specification and amended by the Inner Classes Specification included 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 unnecessary because 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 harmful because 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.
回答
不是,不是
通过使用反射获取可以随后调用的Method对象,我们可能能够实现相同的效果,另一种方法是使用单个"调用"或者"执行"方法创建一个接口,然后实例化它们以调用该方法。我们感兴趣的对象(即使用匿名内部类)。
我们可能还会发现本文有趣/有用:Java程序员研究CDelegates
回答
尽管它几乎不那么干净,但是我们可以使用Java代理实现类似Cdelegates的功能。
回答
我已经使用反射在Java中实现了回调/委托支持。详细信息和工作源可在我的网站上找到。
怎么运行的
有一个名为Callback的原理类,以及一个名为WithParms的嵌套类。需要回调的API将把Callback对象作为参数,并在必要时创建一个Callback.WithParms作为方法变量。由于此对象的许多应用程序都是递归的,因此可以很干净地工作。
由于性能仍然是我的重中之重,因此我不想创建一个一次性对象数组来保存每次调用的参数,毕竟在大型数据结构中可能有成千上万的元素,并且在消息处理场景中我们最终可能每秒处理数千个数据结构。
为了确保线程安全,对于API方法的每次调用,参数数组都必须唯一地存在,并且为了提高效率,应为回调的每次调用使用相同的参数数组。我需要第二个对象,该对象创建起来很便宜,以便将回调与参数数组绑定以进行调用。但是,在某些情况下,由于其他原因,调用者将已经具有参数数组。由于这两个原因,参数数组不属于Callback对象。同样,调用的选择(将参数作为数组或者作为单个对象传递)也属于使用回调的API手中,从而使API能够使用最适合其内部工作方式的任何调用。
然后,WithParms嵌套类是可选的,有两个用途,它包含回调调用所需的参数对象数组,并提供10个重载invoke()方法(具有1到10个参数),这些方法将加载参数数组,然后调用回调目标。
下面是一个使用回调处理目录树中文件的示例。这是一个初始验证阶段,它仅对要处理的文件进行计数,并确保没有超过预定的最大大小。在这种情况下,我们仅使用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():
/** * 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; }
此示例说明了此方法的优点,该方法将应用程序特定的逻辑抽象到回调中,并且在完全可重用的静态实用程序方法中很好地塞满了递归遍历目录树的工作。而且,我们不必为每种新用途重复付出定义和实现接口的代价。当然,接口的论点是它对实现的内容更为明确(它是强制执行的,而不是简单记录的文档),但实际上,我发现正确设置回调定义并不是问题。
定义和实现一个接口并不是真的很糟糕(除非像我一样分发小程序,否则避免创建额外的类实际上很重要),但是真正引人注目的是当我们在一个类中有多个回调时。不仅被迫将它们每个都推入一个单独的内部类中,这在部署的应用程序中增加了开销,而且编程非常繁琐,而且所有样板代码实际上只是"噪音"。
回答
你读过这个吗:
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.
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:
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.