Turkeys and Gizzards : Java Inner Classes
Let’s look at a Turkey class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package tg; public class Toikey { private int grit; private int acid; private String name; public Toikey() { this.name = "Tom"; } public void yo() { System.out.println("gobble gobble"); } public String getName() { return this.name; } public void eat(String food) { System.out.println("mmmm " + food); this.digest(); } private void digest() { int bogus = this.grit * this.acid; } } |
And here is a main that will run it
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package tg; public class Thanks { public static void main(String[] args) { Toikey bird = new Toikey(); System.out.println(bird.getName()); System.out.println("sez"); bird.yo(); bird.eat("Corn"); } } |
Nothing remarkable right? It’s a start at implementing some behavior. This execution simply tells the bird to do what its interface says it can do. It doesn’t know much about how the Turkey does what it does; just what it does (not how).
You can imagine that you might want the Turkey to do a bunch of other things depending on your use cases/user stories. Add an instance variable here and a method there and soon you might end up with one big honking Turkey. Or gobbling Turkey.
Perhaps we can factor out (or to be überhip, refactor) some behaviors into another class.
1 2 3 4 5 6 7 8 9 10 11 |
package tg2; public class Gizzard { private int grit; private int acid; public void digest() { int bogus = this.grit * this.acid; } } |
I took the guts of the digesting code out of the Turkey and made a Gizzard class. (OK, so I don’t really know what a gizzard does. Let’s pretend). How does that simplify our Turkey?
Let’s see
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package tg2; public class Toikey { private String name; /* new instance variable we will delegate to */ private Gizzard gizzard; public Toikey() { this.name = "Tom"; /* when you make a turkey you get a gizzard along with it */ this.gizzard = new Gizzard(); } public void yo() { System.out.println("gobble gobble"); } public String getName() { return this.name; } public void eat(String food) { System.out.println("mmmm " + food); /* tell the turkey's gizzard to digest instead of doing it right here */ this.gizzard.digest(); } } |
Now we are delegating the responsibility for digestion to a class that does only that. Our Gizzard just does digestion. It’s cohesive – which is a pretentious way to say it’s not a dessert topping and a floor wax at the same time.
To the Turkey’s clients there is no change. They have no idea that there is now a Gizzard involved. We changed an implementation detail and they didn’t notice. Did you notice that the digest method in the original turkey was private? If it were public the client would have been within its rights to call it. But then you wouldn’t have the freedom to move it to the Gizzard without also changing the client – or a zillion clients. The two would have been a couple instead of two independent individuals. You could say they are coupled. In general you want to minimize coupling. Loose coupling is better than tight coupling. There are many ways to achieve this loose coupling: the liberal use of interfaces and dependency injection q.v. are popular techniques.
There is a small problem though. Let’s look at a two line addition to our client.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package tg2; public class Thanks { public static void main(String[] args) { Toikey bird = new Toikey(); System.out.println(bird.getName()); System.out.println("sez"); bird.yo(); bird.eat("Corn"); /* say what? */ Gizzard g = new Gizzard(); g.digest(); } } |
That’s right. We can make a Gizzard without a Turkey. When was the last time you saw a Gizzard walking down the street? Hey! Might be a great movie! Let’s say we really don’t want Gizzards without Turkeys. We want the Gizzard stuffed inside the Turkey and known just to the Turkey and not the client since it is an implementation detail inside the Turkey.
So, let’s stuff that Turkey!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package tg3; public class Toikey { private String name; private Gizzard gizzard; public Toikey() { this.name = "Tom"; this.gizzard = new Gizzard(); } public void yo() { System.out.println("gobble gobble"); } public String getName() { return this.name; } public void eat(String food) { System.out.println("mmmm " + food); this.gizzard.digest(); } private class Gizzard { private int grit; private int acid; public void digest() { int bogus = this.grit * this.acid; } } } /* end of Toikey class */ |
See where the Gizzard is now? Inside the Turkey class. Not only that, it’s now private so the clients cannot get to it. This is called an inner class because it’s defined inside another class.
How about something geekier like a LinkedList. Remember that it is a collection where insertion is efficient because it is a collection of data containers (variously called nodes or entries) that contain links to the next and previous containers.
So, ignoring Generics for simplicity here let’s look at a bit of java.util.LinkedList (greatly simplified here. For homework look at the real thing. Remember F3 in Eclipse)
1 2 3 4 5 6 7 8 9 10 |
public class LinkedList etc. { private Entry header = new Entry(); private void add(Object data) { Entry newEntry = new Entry(this.header, data); newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } } |
Every time you add data to the list a new Entry is created and the links are set. You don’t want an Entry without a LinkedList so we can make the Entry an inner class.
But wait a minute! We said one Turkey gets one and only one Gizzard. That won’t work for LinkedLists; we want as many Entries as we need.
There is a way to get both.
1 2 3 4 5 6 7 8 9 |
public class LinkedList etc. { // etc. private static class Entry { // etc. } } |
By making the inner class static the LinkedList can have as many Entry objects as it needs.