COM objects support multiple interfaces. Java supports multiple interfaces on objects. This support is probably the most important reason that Java/COM integration works so well.
The following C++ code uses both types of interfaces. The IRobot interface is used to control what the robot does and IRobotDiagnostics determines the status of the robot. First, the robot is instructed to move forward 10 units, and then turn left 90 degrees using the IRobot interface. QueryInterface is used for IRobotDiagnostics, using it to tell the robot to display a status message.
The IRobot interface example written in C++ is as follows:
// Error handling has been omitted for brevity. IRobot* probbie = NULL; IRobotDiagnostics* probbieDiag = NULL; CoCreateInstance(CLSID_Robot, NULL, CLSCTX_SERVER, IID_IRobot, (void**)&probbie); probbie->GoForward(10); probbie->Turn(-90); probbie->QueryInterface(IID_IRobotDiagnostics, (void**)&probbieDiag); probbie->OutputStatusMessage(); probbieDiag->Release(); probbie->Release();
The same code, written in Java, looks like this:
import robocorp.bots.*; Robot robbie = new Robot(); IRobotDiagnostics robbieDiag = null; robbie.GoForward(10); robbie.Turn(-90); robbieDiag = (IRobotDiagnostics)robbie; robbieDiag.OutputStatusMessage();
Because the Microsoft VM provides the implementation of IUnknown, implementing QueryInterface isn't necessary. The assignment statement does the implicit QueryInterface for IRobotDiagnostics (this is very similar to how QueryInterface is supported in Microsoft® Visual Basic® version 4.0).
COM objects must implement the IUnknown::QueryInterface function to allow clients access to the object's supported interfaces. In Java, the details are handled by the virtual machine. As a result, your source code needs only a typecast.
In C++, you might write code like the following to access the IPrintable interface of the object that pDrawable points to:
// pDrawable points to an object that supports // both IDrawable and IPrintable. IPrintable *pPrintable; pDrawable->QueryInterface( IID_IPrintable, (void **)&pPrintable );
In Java, the equivalent code would look like this:
// drawable refers to an object that supports // both IDrawable and IPrintable. IPrintable printable; printable = (IPrintable)drawable;
Notice that you use the same syntax normally used to cast between Java object types. If the object does not implement the requested interface, a ClassCastException is thrown when you attempt the cast. Alternatively, you can use the instanceof operator to determine whether the object implements the requested interface before the cast is attempted.
An explicit cast to the interface is necessary as it is in normal Java interfaces. If the object does not support the interface you want, an exception is thrown. The standard Java instanceof operator can be used to determine whether a given interface is supported.