Running on Java 24-ea+24-2960 (Preview)
Home of The JavaSpecialists' Newsletter

002Anonymous Inner Classes

Author: Dr. Heinz M. KabutzDate: 2000-12-07Java Version: 1.1Category: Language
 

Abstract: Anonymous inner classes allow us to call super class methods inside its initializer block. We can use this to add values to a collection at point of creation, for example: new Vector(3) {{ add("Heinz"); add("John"); add("Anton"); }});

 

Welcome to the second The Java(tm) Specialists' Newsletter, a low-volume newsletter that is aimed at in-the-trenches Java programmers and those interested in what the trenches look like nowadays. According to the latest Computing SA, the e-commerce industry in South Africa is struggling to take off because it is almost impossible to find Java programmers with any real experience. Germany seems to be experiencing a similar trend so they want to import 30'000 Indians. Aren't we working in an exciting segment of the IT market? I'm so glad I was too jung to try cash in on Y2K bugs and instead invested my time learning more of Java.

You are either on my mailing list because you begged to be added or because you did not beg to be removed, in either case, I hope you are enjoying reading this information and that it will be of benefit to you. Please let me know if there are topics that you would like discussed or if you would like to share some of your own experiences through this newsletter. This newsletter is distributed free of charge to anyone interested, so please forward it to friends and colleagues who might find the information in this newsletter useful.

In the last newsletter I mentioned in the non-kosher section that Java makes provision for more than one GUI thread to be in the system and that I did not know if/when this feature was used. So far I have not found out what the purpose of this is or if it is still used, although I suspect it's a leftover from the Awful Windows Toolkit. Do we have a Swing expert in the house?

javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.

Anonymous Inner Classes

A feature that we did not have in the early days of Java, when all you needed to run the VM was a 80386 with 4 MB RAM and a correctly set CLASSPATH, was the concept of the inner class, specifically the anonymous inner class (heck, we didn't need that newly-fangled fancy stuff then - we were real programmers ;-). Inner classes have made it possible to code with less lines and in the process to obscure the code to the unenlightened but make it wonderfully elegant to those who understand. A good friend and colleague told me "One good Java programmer is better than ten bad Java programmers" which I wholeheartedly agreed with. He then went on to say "And five bad Java programmers are better than ten bad Java programmers". Inner classes have widened this divide. The typical way of using anonymous inner classes is for writing GUI event handlers, e.g.

button.addActionListener(new ActionListener() {
  // This is how you define an anonymous inner class
  public void actionPerformed(ActionEvent e) {
    System.out.println("The button was pressed!");
  }
});

The amazing thing is that we are actually defining a new class(!) while calling another method. You can virtually make new classes in all sorts of places in Java. All of this is old hat to most of you, but last week I found a new application of anonymous inner classes that I had not thought of before. But first a diversion:

A lot of books seem to suggest that if you want to create a Thread in the middle of your code you do it as shown in this code. The example is typically known as an "idiot counter", patented by Microsoft ;-), in which they make the user dream that progress is happening by changing the screen output in some way..... (I have used this technique quite successfully in the past)

new Thread(new Runnable() {
  public void run() {
    try {
      while (true) {
        sleep(1000); System.out.print(".");
      }
    }
    catch(InterruptedException ex) {}
  }
}).start();

If we look at the definition of Thread we see that it takes a Runnable as a parameter so it sort-of makes sense to create an anonymous inner class from Runnable and stick that into the parameter. However, looking more carefully inside Thread we notice that the run() method defined in Thread calls the run() method defined in Runnable, if a Runnable has been passed into the Thread constructor. Instead, it would be more efficient to do the following, because we would have one less object on the heap and one less method call per Thread creation:

new Thread() {
  public void run() {
    try {
      while (true) {
        sleep(1000); System.out.print(".");
      }
    }
    catch(InterruptedException ex) {}
  }
}).start();

This way Thread itself is made into an anonymous inner class and we override the run() method so instead of Thread.run() having to check that a Runnable exists we can just execute the code in run(). It is a very small difference and I don't know why I have not seen it used before, but I suspect one of the early Java 1.1 lemmings jumped over the cliff holding a placard containing the Runnable as a parameter and all the other lemmings followed the sign ;-) To me the difference is more conceptual than actual and leads me on to the next application of inner classes:

Anyway, I now get to the real reason for another newsletter, which is an application of anonymous inner classes which I find quite useful. In Java 1.0, when we had to pass an array as a parameter to a method we did it as follows:

String[] temp_names = new String[3];
temp_names[0] = "Heinz";
temp_names[1] = "John";
temp_names[2] = "Anton";
universityRegistration.addNames(temp_names);

or, alternatively

String[] temp_names = { "Heinz", "John", "Anton" };
universityRegistration.addNames(temp_names);

In Java 1.1, SUN sneaked in a new construct so we would not need to have a temporary variable, which according to the Refactoring folklore is bad. Since JDK 1.1 we could thus say:

universityRegistration.addNames(
  new String[] { "Heinz", "John", "Anton" });

If you wanted to pass in a Collection instead of an array it would look as follows:

Collection temp_names = new Vector(3);
temp_names.add("Heinz");
temp_names.add("John");
temp_names.add("Anton");
universityRegistration.addNames(temp_names);

The ability to avoid local temporary variables with arrays was always a strong deciding factor in defining interfaces to my classes because I could get away with one line of code instead of five, and the less lines of code the better. I would therefore rather define addNames(String[] names) than addNames(Collection names) even if it meant I would have to convert backwards and forwards between arrays and collections. However, with anonymous inner classes we can get the same effect seen above but with collections:

universityRegistration.addNames(new Vector(3)
  {{ add("Heinz"); add("John"); add("Anton"); }});

How does work? Very simple, say we wanted to extend Vector with our own Vector, called MyVector, that contains the three elements "Heinz", "John", "Anton":

public class MyVector extends Vector {
  public MyVector() {
    super(3); // to initialise it with a size of 3
    add("Heinz"); add("John"); add("Anton");
  }
}

The call to the super constructor always happens first, so we could re-write MyVector as follows without changing the functionality in any way:

public class MyVector extends Vector {
  { // initializer block
    add("Heinz"); add("John"); add("Anton");
  }
  public MyVector() {
    super(3); // to initialise it with a size of 3
  }
}

If we want to make an instance of an anonymous inner class we can pass the parameters directly to the super class via the parameter list of the constructor of the anonymous class. In addition, any init block denoted by {} is done AFTER the call to the super class constructor is completed, so the class MyVector could look like this:

Vector myVector =
  new Vector(3) { // defining anonymous inner class
  {
    add("Heinz"); add("John"); add("Anton");
  }
};

From here the step to addNames(new Vector(3) {{ add("Heinz"); add("John"); add("Anton"); }}); is quite simple, I've just removed the comment and bunched the curly brackets together.

The thing that amazes me most about this "discovery" is that it is such an obvious thing to do if you have to pass a collection into a method and you know the size and elements of the collection, but in 3.5 years of Java I'd never thought of it, and I bet it does not occur anywhere in the 570'000 lines of JDK 1.3 code or the mega-project I worked on in South Africa.

---
Warning Advanced:
When you access private data members of the outer class, the JDK compiler creates package-access member functions in the outer class for the inner class to access the private members. This firstly leaves a security hole, although all data members in Java are public to the initiated ;-), and secondly used to impede performance before hotspot came along. So, if you are writing code that has to run reasonably well on non-hotspot code it would be better for performance reasons to make data members accessed by inner classes package-access.
---

As always, I welcome your comments and thank you for the positive feedback from last week.

With regards

Heinz

 

Comments

We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack '23

Superpack '23 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...