Java gets a lot of blame for not allowing straight multiple inheritance and for not implementing closures. But according to Bruce Eckel, you can do a multiple inheritance in Java, you can do closures – sort of. You can accomplish that with inner classes!
In this final Part 4 entry, I will concentrate on these two advanced topics.
One way that you can do multiple inheritance is just by implementing two or more interfaces. Easy and already possible in Java. But what if you did not have an interface, but rather abstract or concrete class. You can no longer just extend two of them — Java limitation. Inner classes provide different options.
First, let’s take a look at two different ways you can implement multiple interfaces.
// Two ways that a class can implement multiple interfaces. // Thinking in Java example interface A {} interface B {} class X implements A, B {} class Y implements A { B makeB() { // Anonymous inner class: return new B() {}; } } public class MultiInterfaces { static void takesA(A a) { } static void takesB(B b) { } public static void main(String[] args) { X x = new X(); Y y = new Y(); takesA(x); takesA(y); takesB(x); takesB(y.makeB()); } } // /:~
Note how class Y implements multiple interfaces. I admit that I have never used it like that. But it does implement two interfaces.
What if you had an abstract or concrete class. You can’t extend two classes easily. Not without the use of inner classes! Here’s how inner classes allow you to do that.
// With concrete or abstract classes, innerÄ… // classes are the only way to produce the effect // of "multiple implementation inheritance." // Thinking in Java example class D {} abstract class E {} class Z extends D { E makeE() { return new E() {}; } } public class MultiImplementation { static void takesD(D d) {} static void takesE(E e) {} public static void main(String[] args) { Z z = new Z(); takesD(z); takesE(z.makeE()); } } // /:~
Possible? Yes. Clean? Not really. But you can!
Eckel says that with inner classes you have these additional features:
1. The inner class can have multiple instances, each with its own state information that is independent of the information in the outer-class object.
2. In a single outer class you can have several inner classes, each of which implements the same interface or inherits from the same class in a different way.
3. The point of creation of the inner-class object is not tied to the creation of the outer-class object.
4. There is no potentially confusing “is-a” relationship with the inner class; it’s a separate entity.
What is a closure? “A closure is a callable object that retains information from the scope in which it was created,” says Eckel. If you’ve been reading this series, you know that an inner class maintains a link to the outer class — that’s in fact a closure.
The following example illustrates a closure. It’s long, but it’s worth getting comfortable with. (Plus, it’s the final example in the series!)
// Using inner classes for callbacks interface Incrementable { void increment(); } // Very simple to just implement the interface: class Callee1 implements Incrementable { private int i = 0; public void increment() { i++; System.out.println(i); } } class MyIncrement { public void increment() { System.out.println("Other operation"); } static void f(MyIncrement mi) { mi.increment(); } } // If your class must implement increment() in// some other way, you must use an inner class: class Callee2 extends MyIncrement { private int i = 0; public void increment() { super.increment(); i++; System.out.println(i); } private class Closure implements Incrementable { public void increment() { // Specify outer-class method, otherwise // you'd get an infinite recursion: Callee2.this.increment(); } Incrementable getCallbackReference() { return new Closure(); } } class Caller { private Incrementable callbackReference; Caller(Incrementable cbh) { callbackReference = cbh; } void go() { callbackReference.increment(); } } public class Callbacks { public static void main(String[] args) { Callee1 c1 = new Callee1(); Callee2 c2 = new Callee2(); MyIncrement.f(c2); Caller caller1 = new Caller(c1); Caller caller2 = new Caller(c2.getCallbackReference()); caller1.go(); caller1.go(); caller2.go(); caller2.go(); } } /* Output:Other operation11 2 Other operation 2 Other operation 3 *///:~ }
This has been a long series — a first for me. I have learned a great deal about inner classes. I hope you find these helpful as well.
Inner classes have their uses. They can help you implement an elegant solution. They can help you accomplish things not easily doable using alternative ways. They can also complicate your code a great deal. They can make your code unreadable. Use it with care.
Reference
Thinking in Java (4th), Bruce Eckel
Java Inner Classes – Part 1 – Intro
Java Inner Classes – Part 2 – Anonymous
Java Inner Classes – Part 3 – Nested Classes
In Part 1, I’ve covered the basics, in part 2, anonymous inner classes. Is there anything left about inner classes? Yes, there is. I warned you that inner classes are a beast.
In this part, I’ll cover nested classes.
When you create an inner class, there is a connection between the enclosed class and the inner class. Because of that, the inner class can access and manipulate the enclosed class.
Take that connection away and you have a nested class. A nested class is a static inner class. With a nested class, 1) you don’t need an outer class to create the instance and 2) you can’t access non-static outer-class object from the nested instance. Below is an example.
public class StaticInner { String s = "test"; public static class Inner { private int counter = 1; public int increment() { return counter++; } public void printS() { // StaticInner.this.s; // ERROR: No enclosing instance of the type StaticInner is // accessible in scope } } public static class Inner2 { private static int counter = 1; public static int increment() { return counter++; } } public static class Inner3 { public static class Inner3Inner { public void sayHi() { System.out.println("Hi"); } } } public static void main(String[] args) { System.out.println("Inner"); Inner inner = new Inner(); System.out.println(inner.increment()); // "1" System.out.println(inner.increment()); "2" Inner inner2 = new Inner(); System.out.println(inner2.increment()); // "1" // Inner2 has a static method System.out.println("Inner2"); System.out.println(Inner2.increment()); // "1" System.out.println(Inner2.increment()); // "2" // Inner3 has an inner class System.out.println("Inner3Inner"); Inner3Inner subInner = new Inner3Inner(); subInner.sayHi(); // "Hi" } }
In the main method, you can see that you can just instantiate Inner with new Inner(). Also in Inner, printS method tries to access StaticInner variable but it’s not allowed to. There is no connection between the two classes.
Initially, I thought a “static class” can have only one instance. That’s not true. Inner can have multiple instances, inner2 is a seperate instance and has its own object.
Inner2 is an example of a static instance. You can refer to in directly by Inner2.increment().
Inner2 shows that static inners can have more than one layer, Inner3Inner is defined inside Inner3.
Yes, you read that correctly. You can have an inner class within an interface! I did not know this was possible. Not that I would want to use it, but still… Take a look at the following example.
// Thinking in Java example public interface ClassInInterface { void howdy(); class Test implements ClassInInterface { public void howdy() { System.out.println("Howdy!"); } } } // Usage ClassInInterface test = new Test(); test.howdy(); /* Output: Howdy!*/// :~
It’s completely valid! Why would you want to do it that way? One valid reason is that if you wanted to have a common implementation of the interface. The downside is that the interface is “heavier” to carry around, but that’s probably very minor.
Back to the basic inner classes. Does a 2nd or 3rd level inner class have access to the layers above? Yes, it does, it has access to all layers. Thinking in Java has a great example, see below.
// Nested classes can access all members of all // levels of the classes they are nested within. class MNA { private void f() { } class A { private void g() { } public class B { void h() { g(); f(); } } } } public class MultiNestingAccess { public static void main(String[] args) { MNA mna = new MNA(); MNA.A mnaa = mna.new A(); MNA.A.B mnaab = mnaa.new B(); mnaab.h(); } } // /:~
I don’t like long tutorials nor long chapters. That’s why I’m breaking these into parts. When will it end? I have done 3 parts already and I’m not done! In Part 4, I’ll try to cover another advanced topic, Multiple Inheritance. Bruce Eckel has an interesting example.
Reference
Thinking in Java (4th), Bruce Eckel
Java Inner Classes – Part 1 – Intro
Java Inner Classes – Part 2 – Anonymous
In Part 1, Java Inner Classes – Intro, I covered most of the basics of inner classes. But there is much more. Some of it might get complex and confusing. But with all of that, I am beginning to understand and value what Bruce Eckel tries to say when he introduces inner classes.
At first, inner classes look like a simple code-hiding mechanism: You place classes inside other classes. You’ll learn, however, that the inner class does more than that–it knows about and can communicate with the surrounding class–and the kind of code you can write with inner classes is more elegant and clear, although there’s certainly no guarantee of this.
Initially, inner classes may seem odd, and it will take some time to become comfortable using them in your designs. The need for inner classes isn’t always obvious, but after the basic syntax and semantics of inner classes have been described, the section “Why inner classes?” should begin to make clear the benefits of inner classes.
In part 2, I am going to cover even more obscure, but more advanced topics. I like to learn by example, this part is heavy on examples.
Did you know you can define a class within a method? Yes, you can. It’s called a local inner class. Example below.
// Nesting a class within a method. // Example from Thinking in Java public class Parcel5 { public Destination destination(String s) { class PDestination implements Destination { private String label; private PDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } return new PDestination(s); } public static void main(String[] args) { Parcel5 p = new Parcel5(); Destination d = p.destination("Tasmania"); } } // /:~
How about a class within an “if” statement. Yes, you can do that as well. It’s called a class within arbitrary scope, see below.
// Nesting a class within a scope. // Thinking in Java example public class Parcel6 { private void internalTracking(boolean b) { if (b) { class TrackingSlip { private String id; TrackingSlip(String s) { id = s; } String getSlip() { return id; } } TrackingSlip ts = new TrackingSlip("slip"); String s = ts.getSlip(); } // Can't use it here! Out of scope: // ! TrackingSlip ts = new TrackingSlip("x"); } public void track() { internalTracking(true); } public static void main(String[] args) { Parcel6 p = new Parcel6(); p.track(); } } // /:~
One other interesting part about the example above is that the class TrackingSlip will get compiled and a class file created. However, this class will only be accessible from within the scope it got created in.
Did you know you can return a class from inside the method body? A class that is not accessible from anywhere else. A class that has no name. Yes, that’s why it’s called anonymous. See example below.
// Returning an instance of an anonymous inner class. // Thinking in Java example public class Parcel7 { public Contents contents() { return new Contents() { // Insert a class definition private int i = 11; public int value() { return i; } }; Semicolon required in this case } public static void main(String[] args) { Parcel7 p = new Parcel7(); Contents c = p.contents(); } } // /:~
Observe the syntax. The first statement in the method body is a return statement. It looks like you are returning a new instance of a class or interface. But that’s not it. You are actually creating/implementing the class, so you open a curly brackets { and close with }; and put the class definition inside. Very tricky and hard to get used to, I think.
Passing Arguments / Anonymous ConstructorWhat if you need to pass an argument and do some constructor initialization. It turns out you can.
// Creating a constructor for an anonymous inner class. // Thinking in Java example abstract class Base { public Base(int i) { print("Base constructor, i = " + i); } public abstract void f(); } public class AnonymousConstructor { public static Base getBase(int i) { return new Base(i) {{ print("Inside instance initializer"); } public void f() { print("In anonymous f()"); }}; } public static void main(String[] args) { Base base = getBase(47); base.f(); } } /** Output: Base constructor, i = 47 Inside instance initializer In anonymous f() */// :~
One note about arguments. If you’re using them inside the inner class, they have to be passed as final. In the above case, it’s not used directly so a non-final argument is fine.
More: You can even define an instance variable in an inner class!
Here’s a snippet from Thinking in Java that illustrates that:
public Destination destination(final String dest, final float price) { return new Destination() { private int cost; // Instance initialization for each object: {cost = Math.round(price); if(cost > 100) System.out.println("Over budget!"); } private String label = dest; public String readLabel() { return label; }}; }
Note that in the above example, because price was used in the inner class, it had to be defined as final.
Here’s a final note from Bruce about anonymous inner classes.
Anonymous inner classes are somewhat limited compared to regular inheritance, because they can either extend a class or implement an interface, but not both. And if you do implement an interface, you can only implement one.
More fun with inner classes to come! In Part 3, I’ll cover nested classes.
Reference
Thinking in Java (4th), Bruce Eckel
Java Inner Classes – Part 1 – Intro, The Pragmatic Craftsman
I believe in writing self-documented, easy to read code. I believe in mantra that simple is beautiful Inner classes are not good tools for that task. I think they make the task of writing good code much harder: weird syntax, different rules, etc. Mostly for that reason, I have not really learned inner classes. I rarely use them. But whether you like inner classes or not, they are a fundamental feature of Java. You can find examples of inner classes in the Java collections. Map.Entry is one example.
Where am I going with this? I think inner classes come useful in some circumstances. You can develop some really complex features with them. And as a Java developer, you should know what’s in your toolbox. Sooner or later you will come across them. You might have to read code that uses them. Or you might utilize them to make your task easier.
Either way, it’s time to learn inner classes.
My goal here is to create a series of articles/tutorials on inner classes with a goal of learning them on a more deeper level. I came across some very good references on inner classes in Thinking Java book by Bruce Eckel. I’ll mostly use that book, plus some other references for this series.
What’s an inner class? It’s a class defined within another class.
public class Outer { public class Inner { // inner fields, methods, etc } }
Simple, right? That’s basically where it ends. Inner classes have more privileges than regular classes. There are different types of inner classes. Like I said, it’s a beast.
One nice thing about inner classes is that they allow you to group related classes together. Comes in handy at times.
Take a look at the example above one more time. How would you create an instance of Inner?
Inner inner = new Inner(); // not going to work // how about -- seems like this should work Inner = new Outer.Inner(); // getting closer, but still not there // let's try to first create an instance of outer // and then use that to create an instance of inner Outer outer = new Outer(); Outer.Inner inner = outer.new Inner();
Yes! That will work. But look at the syntax! Looks really weird to me. outer.new Inner() — but yes, that’s how you create an instance of inner.
One way to get around this weird syntax that Bruce Eckel uses is to create a method in outer that creates an instance of inner.
public class Outer { public class Inner { // inner fields, methods, etc } public Inner innerInstance() { return new Inner(); } } // now you can use Outer outer = new Outer(); Outer.Inner inner = outer.innerInstance();
I like that approach. Makes it much more readable.
So far, you’ve only seen how you would create an inner class. But what’s really different about an inner class?
Here’s a good example from Thinking in Java:
// Holds a sequence of Objects. interface Selector { boolean end(); Object current(); void next(); } public class Sequence { private Object[] items; private int next = 0; public Sequence(int size) { items = new Object[size]; } public void add(Object x) { if (next < items.length) items[next++] = x; } private class SequenceSelector implements Selector { private int i = 0; public boolean end() { return i == items.length; } public Object current() { return items[i]; } public void next() { if (i < items.length) i++; } } public Selector selector() { return new SequenceSelector(); } public static void main(String[] args) { Sequence sequence = new Sequence(10); for (int i = 0; i < 10; i++) sequence.add(Integer.toString(i)); Selector selector = sequence.selector(); while (!selector.end()) { System.out.print(selector.current() + " "); selector.next(); } } } /** Output: 0 1 2 3 4 5 6 7 8 9*/
Note that SequenceSelector is a private class, and how end(), current(), and next() access fields in the enclosed class. Pretty neat, actually.
How would you access the outer object from within the inner? Guess what, another “tricky” syntax: Outer.this
public class SimpleOuter { private String name; private String getName() { return this.name; } private void setName(String name) { this.name = name; } public class Inner { public void accessOuter() { // note the SYNTAX SimpleOuter.this.setName("Test"); System.out.println("Outer name: " + SimpleOuter.this.getName()); } } public Inner inner() { return new Inner(); } public static void main(String[] args) { SimpleOuter outer = new SimpleOuter(); SimpleOuter.Inner inner = outer.inner(); inner.accessOuter(); } } /* Output:Outer name: Test*/
You can’t create an instance of an inner class without creating an outer instance first and using that instance to create the inner. Well, there is, if the inner is static (called nested class). More to come in Part 2…