When should inner classes be used in Java?
Inner classes were introduced in version 1.1 of Java. Ever since they were introduced they inspired a lot of different opinions among people – but we won’t present any opinions here, just facts. Knowing when to use inner classes is very important, because using inner classes in the wrong situations can lead to code that’s difficult to understand and maintain.
A class can be a member of another class, which is an inner class
Inner classes allow you to define one class inside another class – which is why they are called “inner” classes. A class can have member classes, just like how classes can have member variables and methods. There are many different types of inner classes, but we won’t get into the different types of inner classes since the purpose of this article is just to explain when and why you should use inner classes in Java.
In object oriented programming you are probably aware of the fact that classes need to be specialized because it allows for greater reuse and flexibility. This is because a class only needs code that allows an object of that class to do whatever it needs to do, and no more.
But, there are other situations when you actually need to write some code that seems like it belongs in it’s very own class. But, at the same time, the code that you want to write needs to be intimately tied to some other class’s code. So, the question is what to do in this situation? Well, this is where inner classes are very useful. Don’t worry if you are confused – we have a simple example to help you understand why inner classes are necessary, and how they can help you.
An example of when inner classes are necessary
Suppose you have a Java GUI (Graphical User Interface) class that acts as a chat client like Gchat or Facebook Chat. Think about what methods would need to be present in a class like that which represents a chat client – you will need a method that will read user input from the chat box, methods to actually send the user input to the server and to whoever the user is chatting with, even a method that detects that you are typing so that Gchat can display the “XZY is typing” text to your friends, etc.
But, there is one key thing missing here. How exactly will those methods be called? Well, as an example, think about how Gchat works – you type in some text and when you are ready to send it to whoever you’re chatting with, you press the “Enter” or “Return” key on your keyboard. So, the “Enter” key could be considered one event that triggers a call to one of the methods we mentioned earlier. And, if our chat client class wants to detect if someone is typing in a window, then clearly the event that would trigger the call is someone typing – so we would need some code to detect when someone is actually typing in a window in real time – basically when they are pressing a button inside their chat window.
So, these events – like typing in a window and pressing the “RETURN” key – will also need some methods to detect when they occur, and those event handling methods can then call the appropriate chat client methods. For example, when the event handler method that handles the “RETURN” key button pressed event is called, then that method can call the method to send the user input to the server.
There are two types of methods needed in our example
So, it should be clear that there will need to be two different types of methods that will drive your chat client application: 1. Chat client specific methods like those that will read user input from the chat box and send user input to the server. 2. Event handling methods that will respond to actual events that occur in the chat client window – like hitting the “RETURN” key, detecting consistent typing, etc.
Because it’s clear that there will need to be two different types of methods, then from an Object Oriented Design perspective, it seems like we should have two different classes: one class for the chat client specific methods and one class for the event handling methods. That does follow the normal object oriented design practices – because we are creating classes that specialize in what they do.
The problem with having two separate classes
But, in this particular example, there is a problem with having two separate classes. And that problem is the fact that the event handling code is very much related/tied to the code that belongs to the chat client. This makes sense, as we talked about earlier with our GChat example; as soon as a user in GChat hits “RETURN” or “ENTER” on the keyboard that should trigger an event, which should then grab the text from the chat client window. And, the chat client window would be a particular instance (basically an object) of the chat client class. For example, if you are talking to your friend Bob in GChat, he will have one window in Gmail and you will have one window open in Gmail, and each window is an object of the chat client class. So there will be two separate objects of the chat client class – one for you and one for Bob.
Now, if Bob types something and hits the RETURN key, the event handler code that responds to the RETURN key being pushed will need to be able to communicate with Bob’s chat client class object so that it can grab the text from Bob’s chat client class window, or the text field where that text is actually stored. The key here is thinking in terms of objects – an object of the chat client class is created for each person using GChat, so you will have your own object and Bob will have his own object. This means that the event handling code will need to access an chat client object’s text field – which is a member of the class, and an instance variable. So, it should be clear that the event handling code needs access to the members of a chat client class object in order to be able to effectively help.
Why don’t we just combine the event handling code with the chat client code?
Combining the event handling methods with the chat client specific methods in one big class sounds like a good idea at first, but there is one big problem: If both the event handling code and the chat client code need to inherit some code from different classes then you are in trouble, because Java does not support multiple inheritance – meaning that our one “big class” can not inherit from two different classes.
This means that we want some sort of solution where the event handling code is in it’s very own class – which would allow it to inherit from any class it needs, because it’s not bundled together in one class with the chat client code as well. This is also better object oriented design. But, we also want the event handling class to have easy access to the chat client’s member variables – even the private instance variables. One possible solution is to make everything in the chat client class public so that anyone can access it, including the event handling code. But, making everything public is a bad idea.
Inner classes to the rescue
Now, this is why inner classes were created – for situations exactly like the one we described above. An instance of an inner class can access members of an instance of the outer class, because an inner class is just another member of the outer class. And, inner classes can even access the private members of the outer class – yes you did read that correctly!
Does an inner class violate encapsulation?
No, an inner class does not violate encapsulation because of the fact that an inner class is authored by the same person who created the outer class – so having an inner class was an intentional design decision.
What about nested classes? Are nested classes the same thing as inner classes?
You’ve probably heard the term nested class as well, and may be confused as to what the difference between an inner class and a nested class is – you can read about the difference here: Inner versus nested classes