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

How to Call Overridden Function in Java and .NET

4.47/5 (6 votes)
2 Oct 2017CPOL2 min read 8.8K  
Technique of calling overridden methods from Java and C#

Introduction

Object-oriented programming is a good thing, but sometimes it drives you crazy. For example, you have overridden some method in the class. How can you call the original method? Well, you can use super in Java or base in .NET to access the overridden method from your class. But what if you’d like to access the original method from another class?

In this case, you usually have to provide an additional method to retrieve the original value.

Call Overridden Function

Let’s investigate some important example: the functionObject.hashCode() in Java or Object.GetHashCode() in .NET play twofold role in both platforms: on the one hand, it allows to put effectively any object in some collection, on the other hand, the original value of the object’s hashcode is an identity of the object itself. When we put the object into a collection, we usually override hashCode()/GetHashCode() to represent the internal state of the object. To extract original hashcode Java and .NET provide special functions: System.identityHashCode and RuntimeHelpers.GetHashCode functions respectively.

We will take hashCode()/GetHashCode() method and examine it in more details.

Let’s MyClass overrides Object’s hashcode to be 1:

In Java:

Java
public class MyClass {
  public int hashCode() {
     return 1;
  };
}

In .NET:

C#
public class MyClass{
  public override int GetHashCode() {
     return 1;
  }
}

If we have an instance of the MyObject, how can we get the hashcode for original Object class not using System.identityHashCode in Java or RuntimeHelpers.GetHashCode in .NET.?

For the first try, the problem looks trivial.

Java
Object obj = new MyObject();
int hc = obj.hashCode();

Well, the hc-value is 1 because public methods in Java are virtual (if not final).

Let’s try to get Object’s hash-code using reflection:

Java
MyObject obj = new MyObject();
Method m = Object.class.getMethod("hashCode");
int hc = (int) m.invoke(obj);

Alas, the hc- value is still 1. It means, that although we took the Method from Object.class, it invokes the Method of MyObject class: virtual methods in action!

Here, we used Java code, the .NET code is essentially the same and produces the same results.

For the second try, the problem looks unsolvable: the method was overridden and it seems impossible to obtain its original value (that’s why System.identityHashCode() function exists). And this is true for JDK-5 and 6.

From JDK-7, we have powerful reflection methods which can solve this enigma.

Let’s look at this function:

Java
private static MethodHandle getMethodHandle(Class<?> objClass) throws ReflectiveOperationException {
  Class<?> parentClass = objClass.getSuperclass();
  Lookup lookup = getLookup(objClass);
  return lookup.findSpecial(parentClass, "hashCode", MethodType.methodType(int.class), objClass);
}

Here, we do the following:

  • Create the appropriate object of Lookup class (see the implementation of getLookup(..) function
  • Call findSpecial method of this class

The MethodHandle object for hashCode function is created. After that, we called its invoke() method and viola, the correct result is received.

The .NET implementation is even more direct:

C#
    private delegate int HashCodeDelegate();

...
    MethodInfo handle = objClass.BaseType.GetMethod("GetHashCode");
    IntPtr ptr = handle.MethodHandle.GetFunctionPointer();
    var hashCodeFun = (HashCodeDelegate)Activator.CreateInstance(typeof(HashCodeDelegate), obj, ptr);
    var hashCode = hashCodeFun();

Results

Java:

Hashcode: 1, Object Hashcode:685325104, Identity Hashcode: 685325104

.NET:

Hashcode: 1, Object Hashcode: 46104728, Identity Hashcode: 46104728

In a different environment, one can see different values for Object Hashcode and Identity Hashcode, but always Object Hashcode is the same as Identity Hashcode.

The idea in .NET was provided in [2], I modified the solution a bit to match GetHashCode function.

Acknowledgements

The author is grateful to Ilia Reznik and Alex Rafalovich for useful comments and recommendations.

Reference

  1. Oracle documentation for MethodHandle
  2. Stack overflow: how to call base.base.method()? (for .NET)

License

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