ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

A Java Programmer Looks at C# Delegates
Pages: 1, 2

Implementing Delegates in Java

The code presented in this article implements a significant portion of the functionality of C# delegates in Java. Two ways of accomplishing this will be presented. In the first case, the developer describes the method to be delegated by providing a list of the parameter and return classes. In the second case, the parameters are deduced by examining a suitable interface that declares a single method. The code presents a factory class, Delegator, capable of handling either case. The factory method, build, returns an object implementing the Delegate interface. Where the Delegator has been constructed with an interface, the return is a Proxy implementing that interface.

The Delegator Class

Two methods may be considered comparable if the argument lists of each method are assignable the same common list of classes and if the return types are assignable to a common type. As an example, if Foo is a superclass of Bar, the two methods

public String m1(Foo p1);
public Object m2(Bar p1);

both match a signature taking Bar and returning Object. We may express this signature in code by providing a Class object that represents the return type and an array of Class to represent the parameter types. We may also express this signature by providing an interface with a single method to be used as an exemplar.

A method may match the signature described by a Delegator in the weak sense that all arguments are assignable to the declared types rather than the stronger test required by a Java interface that the arguments be identical. Also note that methods are considered comparable even it they throw different exceptions. Delegation will convert all exceptions into a runtime DelegateInvokeException emulating C# behavior (all C# exceptions act like RuntimeExceptions).

Delegator provides a factory method, build, which associates the method template with a specific implementation. The implementation is a combination of either an instance method and a target instance or a static method. In either case, the method must be compatible with the requested signature. The object returned by the build method will satisfy the Delegate interface, which contains the method:

public Object invoke(Object[] args);

The returned object is a thin wrapper that invokes the method on the supplied object, converting any checked exceptions returned by the wrapped object into a runtime DelegateInvokeException. The code in Scenario 1 shows use of this basic type of Delegate object.

Scenario 1. Using a generic Delegate object

Java Code

class Class1 {
    public void show(String s) { System.out.println(s); }

class Class2 {
    public void display(String s) { System.out.println(s); }

// allows static method as well
class Class3 {
    public static void staticDisplay(String s) { System.out.println(s); }

public class TestDelegate  {
    public static final Class[] OUTPUT_ARGS = { String.class };
    public final Delegator DO_SHOW = new Delegator(OUTPUT_ARGS,Void.TYPE);

    public void main(String[] args)  {
        Delegate[] items = new Delegate[3];

        items[0] = DO_SHOW .build(new Class1(),"show,);
        items[1] = DO_SHOW.build (new Class2(),"display");
        items[2] = DO_SHOW.build(Class3.class, "staticDisplay");

        for(int i = 0; i < items.length; i++) {
            items[i].invoke("Hello World");

The code described above offers many of the advantages of C# delegates. Methods, either static or dynamic, can be treated in a uniform manner. The complexity in calling methods through reflection is reduced and the code is reusable, in the sense of requiring no additional classes in the user code. Note we are calling an alternate convenience version of invoke, where a method with one parameter can be called without creating an object array.

Scenario 2. Delegating via an interface

One advantage of C# delegates that is still missing is static type checking enforced by the compiler. In the example above, it is possible to call invoke on a returned Delegate with a Date object, and the error will not be discovered until run time. In order to get the full benefits of compiler support, it is necessary to construct the Delegator with an interface. The interface may be well-known or special-purpose, but should declare a single method. The signature of that method becomes the template used by the Delegator. In addition, the returned object will be a proxy that implements the requested interface.

Java Code

// interface to implement
public static interface IStringDisplay {
    public void doDisplay(String s);

public final Delegator ST_DEL  = new Delegator(IStringDisplay.class);

public void testDelegate() 
    IStringDisplay[] items = new IStringDisplay[3];

    // build the delegates
    items[0] = (IStringDisplay) ST_DEL.build(new Class1(),"show");
    items[1] = (IStringDisplay) ST_DEL.build(new Class1()2,"display");
    items[2] = (IStringDisplay) ST_DEL.build(Class3.class,"staticDisplay");

    // call the delegates
    for(int i = 0; i < items.length; i++) {

Note that while a cast is required to convert the value returned from the build method into an instance of the desired interface, invocations of the delegated method are now made through the interface with full static type checking.

Thread Delegates

One major use of delegates in C# is in threading. Rather than constructing a thread with an instance of Runnable, threads in C# are constructed by using a delegate, Thread.ThreadStart, with the appropriate signature. In Java, a similar problem exists where a developer wants to call a no-argument method as the active portion of a Runnable. While this may be accomplished with an anonymous inner class, the construct is clumsy and reduces the readability of the code.

This important usage pattern is supported by the Delegator class, which implements convenience methods to create delegates implementing Runnable. This is done by providing a static, final instance variable holding a Delegator constructed using the well-known interface Runnable, implementing two static methods that build delegates using this Delegator and cast the returned object to the underlying interface. Similar code could be used any time it is necessary to build many delegates that all implement a particular interface.

Java Code

static final Delegator RUNNABLE_DELEGATE = new Delegator(Runnable.class);

public static Runnable buildRunnable(Object o,String methodName) {

public static Runnable buildRunnable(Class c,String methodName) {

The above code can be called with a line such as:

Runnable r = Delegator. buildRunnable(this,methodName);

Note that because a special-purpose method has been used, there is no need to cast the return value from buildRunnable. The cast is performed in the method implementation.

How It Works

The critical code is in the method build. This method constructs a DelegateProxy, exposed through an Delegate interface that is a wrapper around the method named in the call to build. If the Delegator was constructed by specifying an interface, the returned object is wrapped in a dynamic Proxy so that it will appear to the Java runtime as an instance of the requested interface.

Java Code

  * @param target non-null target with a bindable method
  * @param MethodName  name of the  method
  * @return non-null IDelegate. If getInterface() is non-null the returned 
  * Delegate will be a dynamic proxy implementing that interface

public Delegate build(Object target,String methodName)
    Class myInterface         = getInterface();
    DelegateProxy theDelegate = new DelegateProxy(target,methodName,this);

    // build a dynamic proxy
    if(myInterface != null) {
        Class[] interfaces = { myInterface,Delegate.class };
        Delegate ret       = (Delegate)java.lang.reflect.Proxy.newProxyInstance(
                              interfaces, theDelegate);

    return theDelegate;

The constructor DelegateProxy(target,methodName,this) uses reflection to find the best method in the target class matching the signature contained in the Delegator. When an interface has been specified, the DelegateProxy can be used as an InvocationHandler to construct a Proxy implementing the specified interface. The returned object may then be called using the Delegate's invoke method or, if an interface is specified in the Delegator, cast to that interface and used as an instance of that interface.


Sufficient information to build delegates is present once classes are loaded. Binding a delegate is a non-trivial operation requiring identification of an appropriate method in the target class. When a delegate is constructed with an instance method, the build call can occur any time after the target instance has been created. Delegates invoking static methods can be constructed at load time. It is usually a good idea to build delegatees as early as possible, caching them for later use. Actually performing method calls through delegates is relatively cheap.

Related Reading

Java Enterprise Best Practices
By The O'Reilly Java Authors

Timing and Performance Costs

The most logical use of delegates involves messaging and event handling where the code is infrequently executed; i.e., not in a tight loop. In these situations, executing the code contained in the target method usually takes significantly longer than the process of finding and invoking the method. In addition, Hotspot and JDK 1.4 have significantly reduced the cost of method calls. I found that executing the loop in TestDelegate (three calls) for 10,000,000 iterations took 43 seconds on a 1.5GHz Athlon processor running JDK 1.4 under Windows 2000. This averages slightly more than one microsecond per call. This cost can be ignored in all but the tightest loops.


This approach represents an implementation of the Adapter pattern (Gamma et al, Design Patterns). It differs from a Proxy in that an Adapter maps a number of different methods into identical calls, allowing multiple objects implementing methods with different names but compatible signatures to be used interchangeably. It will also work with or without a target interface to implement. The Delegator class simplifies and generalizes the steps in creating an Adapter. Delegates are simple to use, and a single delegate instance may be reused multiple times.

Where an interface is known or can be constructed, use of delegates provides a simple, readable way to coerce a method into implementing the actions in that interface. Common interfaces, such as Runnable and many event listeners, may easily be mapped to any matching public method. In these cases, the Java code is almost as simple as the code that could be written using C#'s built-in delegate construct.

In my own development, I find that delegates implementing interfaces are more useful than those using invoke. The buildRunnable method is especially useful. In Swing programming, where large numbers of Runnables are needed to pass control to the swing thread, the ability to turn methods into Runnables is particularly useful. Delegates allow me to largely eliminate the need for anonymous inner classes, improving the readability of my code.


Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Addison Wesley Professional Computing Series, 1994.

Steven M. Lewis , PhD, is a Director of Development for UnifiedSignal, a provider of telecom solutions.

Wilhelm Fitzpatrick is an independent consultant specializing in Java development for enterprise platforms.

Return to ONJava.com.