|
The Java Specialists' Newsletter
Issue 002 2000-12-07
Category:
Language
Java version: Anonymous Inner Classesby Dr. Heinz M. Kabutz
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?
Thanks for reading this newsletter on our website. We also have a mailing list. That is where the real action takes place (webinars, free reports, etc.). Maybe subscribe today?
Advanced Java Courses on Crete:Java Specialists Master Course 18-21 June 2013 and
Concurrency Specialists Course 6-9 August 2013.
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
Language Articles
Related Java Course
Discuss at The Java Specialist Club
|