Sometimes it works anyway
It turns out that in some cases things seem to work correctly without casting back to your original type. One case is quite special: The String class has some extra help from the compiler to make it work smoothly. Whenever the compiler expects a String object and it hasn’t got one, it will automatically call the toString( ) method that’s defined in Object and can be overridden by any Java class. This method produces the desired String object, which is then used wherever it is wanted.
Thus, all you need to do to make objects of your class print is to override the toString( ) method, as shown in the following example:
//: c11:Mouse.java
// Overriding toString().
public class Mouse {
private int mouseNumber;
public Mouse(int i) { mouseNumber = i; }
// Override Object.toString():
public String toString() {
return "This is Mouse #" + mouseNumber;
}
public int getNumber() { return mouseNumber; }
} ///:~
//: c11:MouseTrap.java
public class MouseTrap {
static void caughtYa(Object m) {
Mouse mouse = (Mouse)m; // Cast from Object
System.out.println("Mouse: " + mouse.getNumber());
}
} ///:~
//: c11:WorksAnyway.java
// In special cases, things just seem to work correctly.
import com.bruceeckel.simpletest.*;
import java.util.*;
public class WorksAnyway {
private static Test monitor = new Test();
public static void main(String[] args) {
List mice = new ArrayList();
for(int i = 0; i < 3; i++)
mice.add(new Mouse(i));
for(int i = 0; i < mice.size(); i++) {
// No cast necessary, automatic
// call to Object.toString():
System.out.println("Free mouse: " + mice.get(i));
MouseTrap.caughtYa(mice.get(i));
}
monitor.expect(new String[] {
"Free mouse: This is Mouse #0",
"Mouse: 0",
"Free mouse: This is Mouse #1",
"Mouse: 1",
"Free mouse: This is Mouse #2",
"Mouse: 2"
});
}
} ///:~
You can see toString( ) overridden in Mouse. In the second for loop in main( ) you find the statement:
System.out.println("Free mouse: " + mice.get(i));
After the ‘+’ sign the compiler expects to see a String object. get( ) produces an Object, so to get the desired String, the compiler implicitly calls toString( ). Unfortunately, you can work this kind of magic only with String; it isn’t available for any other type.
A second approach to hiding the cast has been placed inside MouseTrap. The caughtYa( ) method accepts not a Mouse, but an Object, which it then casts to a Mouse. This is quite presumptuous, of course, since by accepting an Object, anything could be passed to the method. However, if the cast is incorrect—if you passed the wrong type—you’ll get an exception at run time. This is not as good as compile-time checking, but it’s still robust. Note that in the use of this method:
MouseTrap.caughtYa(mice.get(i));
no cast is necessary.