Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java / JavaSE

Delegates, Events and Pass by ref in Java using bytecode Manipulation

4.85/5 (4 votes)
15 May 2012CPOL2 min read 22.3K   204  
Support for Delegates, Events and Pass by ref in Java using bytecode manipulation

Introduction

C# language has come up with some very beautiful features where Java is lacking. People are still able to manage but having those in Java would make life of the developers much easier. Recently, I found Javassist library which is able to manipulate bytecode and compile classes at runtime. Using that, I was able to implement some of the features.

Delegate

A delegate is a type that references a method.

C# declaration:

C#
public delegate int PerformCalculation(int x, int y);

Equivalent Java declaration:

Java
public abstract class PerformCalculation extends csharp.Delegate {
    public abstract int invoke(int x, int y);
}

C# instantiation:

C#
PerformCalculation performCalculation = new PerformCalculation(this.myMethod);   //instance 
C#
PerformCalculation performCalculation = new PerformCalculation(AClass.myMethod); //static  

Equivalent Java instantiation

Java
PerformCalculation performCalculation = Delegate.<PerformCalculation> 
       getInstance(PerformCalculation.class, this, "myMethod"); //instance  
Java
PerformCalculation performCalculation = Delegate.<PerformCalculation> 
       getInstance(PerformCalculation.class, AClass.class, "myMethod"); //static 

You can just call invoke of the performCalculation object. A new delegate class is created on runtime for each AClass type used (but only once throughout the life of the application).

Requirements

  1. The declared 'Delegate' class and 'invoke' method should be 'public abstract'.
  2. Signature of the 'invoke' method should match to that of 'myMethod' function.
  3. Only one 'invoke' method should be present.
  4. It would be better if 'myMethod' function is public or protected else reflection is used which may have performance issues.

Event

An event in C# is a way for a class to provide notifications to clients of that class when some interesting thing happens to an object. This is actually list of delegates.

C# declaration/instantiation:

C#
public event PerformCalculation myEvent; 

Equivalent Java declaration:

Java
public abstract class MyEvent<D extends PerformCalculation> extends csharp.Event<D> {
    public abstract int invoke(int x, int y);
}

Equivalent Java instantiation:

Java
MyEvent<PerformCalculation> performEvent = 
  Event.<MyEvent<PerformCalculation>> getInstance(MyEvent.class, PerformCalculation.class); 

You can now add PerformCalculation delegates to performEvent object by calling its 'add' method. Calling invoke of the performEvent object which will call invoke of all the delegates added.

Requirements

  1. The declared 'Event' class and 'invoke' method should be 'public abstract'.
  2. Signature of the 'invoke' method should match that of delegates to be added.
  3. Only one 'invoke' method should be present.

Pass by ref

The ref keyword in C# causes an argument to be passed by reference. This feature is not available in Java. It means if this is available in future, primitive types will be passed by reference and objects will be passed by reference of a reference (by default, reference of object is passed).

So, following would not change the original variable.

Java
list = new ArrayList(); 

But the 'list' variable will point to a new memory location. For this, I have included few wrapper classes (one of each primitive type and one with generics for objects) in my code that can be used to pass reference and get it back. This is nothing new but included them in the code just in case somebody wants to use this feature.

Notes

If you are a hardcore Java developer, please read about events and delegates. You may not appreciate these features till you have actually used them in your code.

Update

  1. Use of class.getCanonicalName instead of class.getName. The latter had issues in case of inner classes.
  2. There is no need of writing dynamically compiled classes to filesystem.

History

  • 15th May, 2012: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)