: code tutorial (v3)

Lesson 4: Interfaces

Introduction

Interface and abstract class types pose a problem because we might need to instantiate a proxy object for which we have nothing but a proxy interface type. To illustrate that problem, let's look at a generic Java object factory that can return objects of a totally unknown Java type. All we know is that the returned object implements the interface MyIfc.

Given a Java type like

public class MyFactory {
    public MyIfc create( Map inputs ) {
        ...
    };
}

The .NET proxy type for the MyFactory type will look something like this (much code omitted):

public class MyFactory : global::Java.Lang.Object {
    public global::MyIfc Create( global::Java.Util.Map inputs ) {
        ...
    };
}

You see that the .NET type is declared to return a MyIfc instance. But we can't know the exact Java type that is going to be returned and therefore we (probably) don't have the exact .NET proxy type that would match that unknown Java type. Yet we need a .NET type that can be instantiated and that implements the MyIfc interface, otherwise we can't return an object from the Create() method.

Impl Types to the Rescue

We solve this problem with an additional type that we refer to as an "Impl type." Every proxy type for an abstract Java type, interfaces included, has a nested type that has the outer type's name plus "Impl". In our example case, the nested type would be called MyIfcImpl. That type satisfies all contracts of a proxy object while implementing or extending its outer type.

Please note that you do not have to and in fact should never declare a variable of an Impl type. Consider the following snippet that uses our factory class:

// do NOT do this 
MyIfc.MyIfcImpl  impl = (MyIfc.MyIfcImpl)factory.Create( null );

This might work for you in most cases but there's no need to do it and it might actually be harmful. What if you have a proxy type for one of the Java types that are being returned by the factory method? In that case the JMS Courier runtime will return the proper proxy type and not an Impl type and you will get a runtime error. Use the object via its declared interface and treat the Impl type as the implementation detail that it is.

If you are only ever going to use the proxy object via its declared interface API you have absolutely no unexpected behavior. An issue can arise though when you use your expert knowledge about the returned object to cast it to a different interface that the returned Java type also implements. That won't work on the .NET proxy object because it only implements the one interface that was the declared return type. When you face that situation you will have to use the other interface Impl type's From() method to convert the proxy instance to the other type. This is described at much greater detail in the casting lesson.