How to Create Inner Classes in Java

By Barry A. Burd

Here’s big news! In Java, you can define a class inside of another class! Here, the GameFrame class contains a class named MyActionListener.

import java.awt.FlowLayout;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.util.Random;

 

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JTextField;

 

class GameFrame extends JFrame {

private static final long serialVersionUID = 1L;

 

int randomNumber = new Random().nextInt(10) + 1;

int numGuesses = 0;

 

JTextField textField = new JTextField(5);

JButton button = new JButton("Guess");

JLabel label = new JLabel(numGuesses + " guesses");

 

public GameFrame() {

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

setLayout(new FlowLayout());

add(textField);

add(button);

add(label);

button.addActionListener(new MyActionListener());

pack();

setVisible(true);

}

class MyActionListener implements ActionListener {

 

@Override

public void actionPerformed(ActionEvent e) {

String textFieldText = textField.getText();

 

if (Integer.parseInt(textFieldText) == randomNumber) {

button.setEnabled(false);

textField.setText(textField.getText() + " Yes!");

textField.setEnabled(false);

} else {

textField.setText("");

textField.requestFocus();

}

numGuesses++;

String guessWord = (numGuesses == 1) ? " guess" : " guesses";

label.setText(numGuesses + guessWord);

}

}

}

The MyActionListener class above is an inner class. An inner class is a lot like any other class. But within an inner class’s code, you can refer to the enclosing class’s fields. For example, several statements inside MyActionListener use the name textField, and textField is defined in the enclosing GameFrame class.

Notice that the code above uses the MyActionListener class only once. (The only use is in a call to button.addActionListener.) So, do you really need a name for something that’s used only once? No, you don’t. You can substitute the entire definition of the inner class inside the call to button.addActionListener. When you do this, you have an anonymous inner class. This is how it works.

import java.awt.FlowLayout;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.util.Random;

 

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JTextField;

 

class GameFrame extends JFrame {

private static final long serialVersionUID = 1L;

 

int randomNumber = new Random().nextInt(10) + 1;

int numGuesses = 0;

 

JTextField textField = new JTextField(5);

JButton button = new JButton("Guess");

JLabel label = new JLabel(numGuesses + " guesses");

 

public GameFrame() {

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

setLayout(new FlowLayout());

add(textField);

add(button);

add(label);

button.addActionListener(new ActionListener() {

 

@Override

public void actionPerformed(ActionEvent e) {

String textFieldText = textField.getText();

 

if (Integer.parseInt(textFieldText) == randomNumber) {

button.setEnabled(false);

textField.setText(textField.getText() + " Yes!");

textField.setEnabled(false);

} else {

textField.setText("");

textField.requestFocus();

}

numGuesses++;

String guessWord = (numGuesses == 1) ? " guess" : " guesses";

label.setText(numGuesses + guessWord);

}

});

pack();

setVisible(true);

}

}

Inner classes are good for things like event handlers, such as the actionPerformed method. The most difficult thing about an anonymous inner class is keeping track of the parentheses, the curly braces, and the indentation Some humble advice: start by writing code without any inner classes. Later, when you become bored with ordinary Java classes, experiment by changing some of your ordinary classes into inner classes.