|
The Java Specialists' Newsletter
Issue 127 2006-06-07
Category:
Language
Java version: JDK 1.5, 1.6 Casting like a Tigerby Dr. Heinz M. KabutzAbstract: Java 5 adds a new way of casting that does not show
compiler warnings or errors. Yet another way to shoot
yourself in the foot?
Welcome to the 127th edition of The Java(tm) Specialists' Newsletter. I have just returned
from our first ever set of Java courses in Crete -
they were simply incredible. For example, sitting in a Greek
kafeteria sipping iced coffee and discussing the drawbacks and
benefits of various design patterns! One of my personal
highlights was seeing an octopus whilst snorkelling at the end
of a full day of training. What an unforgetable experience ...
its entire body changed colour as I approached it. These
creatures are beyond weird; you could swear they were dumped in
our seas by some alien teenage prankster.
Upcoming Java Specialist Master Courses:
- please click here to sign up.
As from May 2010, we are also offering this course on the island of Crete. We
only accept 6 students per class in Crete, due to the size of our conference
room. Please book early to avoid disappointment!
San Jose CA, Mar 16-19 2010, $3500 Ottawa, Canada, Mar 22-25 2010, $3500 Oslo, Norway, Apr 13-16 2010, Kr 24500 Montreal, Canada, Apr 20-23 2010, $3500 Toronto, Canada, May 17-20 2010, $3500 Chania, Crete, May 25-28, Jun 29-Jul 2 or Aug 24-27 2010, €2500
In-house courses if these dates or locations do not suit you - click here for more information. Casting like a Tiger
Before we start, have you noticed how Java is striving towards
the C Programming Language? We now have static imports, enums
and varargs. So as a joke, we'll define a Stdio class. This
must be in a package, so that we can statically import the
functions.
package com.cretesoft.c; // must be in a package
public class Stdio {
public static void printf(String format, Object... args) {
System.out.printf(format, args);
}
}
To make the example fun, we make the interface Alien and the
concrete classes Octopus and SeaSlug that implement Alien. The
30cm SeaSlug was another incredibly weird creature, flapping
various appendages whilst creeping over the rocks.
public interface Alien {
void swim();
void glow();
}
import static com.cretesoft.c.Stdio.printf;
public class Octopus implements Alien {
public void swim() {
printf("Squirting water from my head.\n");
}
public void glow() {
printf("I'll be brown, no, yellow, no green.\n");
}
}
import static com.cretesoft.c.Stdio.printf;
public class SeaSlug implements Alien {
public void swim() {
printf("Flap various appendages.\n");
}
public void glow() {
printf("Glow with a yellow hue.\n");
}
}
Class.cast()
In the past, the following cast was illegal and caused
a compilation error:
String s = "42";
Integer i = (Integer)s;
Since Java 5, there is a new way of casting that does not emit a
warning. Each class has a cast() method that does so without
causing compiler errors:
String s = "42";
Integer i = Integer.class.cast(s);
Pre-Java 5, you would have had to first cast the String to an
Object, and then down to an Integer, to get the compiler to shut
up:
String s = "42";
Integer i = (Integer)((Object)s);
Of course, this cast will always fail, and anyone who uses the
Class.cast() method in this way is in need of some R&R in
Crete.
Where is Class.cast() useful?
The Class.cast() method is used in only one place in JDK 1.5,
but in nine places in JDK 1.6. Its popularity is growing! A
place where it makes sense is with filtering of collections.
Let's say we have a collection of objects, and we want to make a
subset of the collection containing only Aliens. Here is a
class that does that for you:
import java.util.*;
public class CollectionFilter {
/**
* Filters the src collection and puts the objects matching the
* clazz into the dest collection.
*/
public static <T> void filter(Class<T> clazz,
Collection<?> src,
Collection<T> dest) {
for (Object o : src) {
if (clazz.isInstance(o)) {
dest.add(clazz.cast(o));
}
}
}
/**
* Filters the src collection and puts all matching objects into
* an ArrayList, which is then returned.
*/
public static <T> Collection<T> filter(Class<T> clazz,
Collection<?> src) {
Collection<T> result = new ArrayList<T>();
filter(clazz, src, result);
return result;
}
}
If instead of the Class.cast() method, we do an explicit cast:
dest.add((T)o) it causes the following warning:
CollectionFilter.java:13: warning: [unchecked] unchecked cast
found : java.lang.Object
required: T
dest.add((T)o);
^
1 warning
Here is an example of how it can be used to filter out the
aliens in the sea:
import java.util.*;
public class StavrosLagoon {
public static void main(String[] args) {
Collection<Object> sea = new ArrayList<Object>();
sea.add("seaweed");
sea.add(new Octopus());
sea.add("rock");
sea.add("fish");
sea.add(new Octopus());
sea.add("sand");
sea.add(new SeaSlug());
sea.add("starfish");
Collection<Alien> aliens =
CollectionFilter.filter(Alien.class, sea);
for (Alien alien : aliens) {
alien.swim();
alien.glow();
}
}
}
There are a few other places where the Class.cast() can be
useful. One of these is in generating dynamic proxy instances
if you want to avoid having to deal with the unchecked cast
warning.
Another interesting new method in Java 5 is the
Class.asSubClass() method. We can use that when we have a class
object that we want to bind to a specific subclass instance,
like this:
public class SeaSlugTest {
public static void main(String[] args) throws Exception {
Class<?> someClass = Class.forName("SeaSlug");
Class<? extends Alien> clz = someClass.asSubclass(Alien.class);
Alien alien = clz.newInstance();
alien.glow();
}
}
It is good to be back in Cape Town. Had to take my Alfa Romeo
for its 100'000km service, which went smoothly. I still think
that the Alfa Romeo is the best value-for-money car that you can
buy, especially if you enjoy driving but have to watch your
budget. Their reliability has improved drastically in the last
few years. Mine has certainly earned her keep. Just a pity
about the speeding fines ...
Kind regards
Heinz
Language Articles
Related Java Course
|