i'm assuming you all have a good grounding in OOP and understand inheritance and interfaces and so on. in particular, the java object model is a tree, starting with
java.lang.Object
and descending down by way of child classes that extend this base or root class. these sub-classes can only extend one parent class, however they can implement several interfaces. an interface is a statement of an API contract that must be fulfilled by the implementing object. it usually consists of a number of public methods that will be written by the developer as part of the new object. for example, the java.lang.Runnable
interface (for thread creation) requires that the object have a public void run()
method. this means that any object where (o instanceof Runnable)
is true will be able to have o.run()
called on it. similar to interfaces are abstract classes, which are like ordinary objects, but with some methods declared using the abstract
keyword. these methods must then be implemented by any child classes that extend it.since java only allows single-inheritance, interfaces are used to allow a class to extend some parent class and still conform to multiple other method signatures or contracts. however, if you have developed an interface that must be implemented by a large number of your classes, and these classes must also extend some different parent to inherit required functionality, it can be a pain to have to write the same implementation of an interface method many times. what you would like to do is have interfaces that don't just specify method signatures, but actually contain the code for an implementation of those methods that can then be called on any implementing class. sadly this is not possible - an interface cannot contain any Java code.
all is not lost, though, since it is possible to define a nested inner class as part of your interface. an inner class is just like a standard class definition, except it is nested in the code for another class. inner interfaces are also possible, but not discussed here. what i discovered is that it is possible to write a number of method implementations, fields, static initialisers and so on in this inner class, and when compiled, any object that implements the interface will also have access to them, and present them to other classes depending on visibility. here is an example... suppose we have an interface
Kitten
which defines methods public String getText()
and public void doSomething()
. the code looks like this:public interface Kitten {
public String getText();
public void doSomething();
}
but, we also want all
Kitten
objects to have access to some utility methods public void doMore(String s)
and public String findOut()
. These could be added to the interface signature, and implemented by any class that implements Kitten
, but instead we will add an inner class called Helpful
and a reference to it in the outer interface, as follows:public interface Kitten {
public String getText();
public void doSomething();
public Helpful h = new Helpful();
public class Helpful {
private String THING = "java interfaces";
public void doMore(String s) {
System.out.println("doing more with " + s);
}
public String findOut() {
return THING;
}
}
}
so, this interface now has the inner class added. in order to see how it works, we will need to write a test program that implements the interface and then try accessing some of the inner class methods. the implementation is simple, just write the body for the two methods declared by
Kitten
, for instance:public class Potato implements Kitten {
// we could also add "extends Whatever"
public String getText() {
return "this is some text!";
}
public void doSomething() {
for (int i = 0; i < 3; i++)
System.out.println("stage " + i);
}
}
with this class we ought to be able to call both the
Kitten
and the Helpful
methods, so we should write a test class to demonstrate:public class Test {
public static void main(String[] argv) {
Potato p = new Potato();
System.out.println(p.getText()); // Kitten
p.doSomething(); // Kitten
p.h.doMore("string"); // Helpful
System.out.println(p.h.findOut()); // Helpful
}
}
and when compiled, the output from the
Test
class is as follows:$ javac Test.java
$ java Test
this is some text!
stage 0
stage 1
stage 2
doing more with string
java interfaces
this is pretty much as expected. the inner class methods are called on the
Helpful
instance h
that is part of the interface specification. they could also be called directly. for example, if there was a static method in Helpful
named doThis()
, it could be called from anywhere inside a class implementing Kitten
as Helpful.doThis()
or from anywhere else in your code as simply Kitten.Helpful.doThis()
.i think this is probably an abuse of the java object system, and certainly not "best practice" for OOP in any way, but it may be helpful for some situations where you want to avoid repeated boilerplate code and need the benefits of inheritance for utility methods but your objects must descend from a library class, and interfaces are the only extension point available. one thing to bear in mind, however, is that the nested inner class methods are treated by the compiler as
static
and there may be scope issues with access to the parent class. this could be worked around by passing a reference to this
into some of the methods, or similar tactics.happy coding!
No comments:
Post a Comment