Sometimes you know more about an object than the JVM can prove. For example, suppose you have a Library class that has a hash table to map a person's name (as a String) to the Address where they live:
.class Library ; This field maps a String to an Address .field static addressMap Ljava/util/Hashtable;
The get method of Hashtable takes an Object and returns an Object. Here's how to get the address of a person, assuming that the name is in local variable 1:
; Take the person's name and use it to get their Address from ; the addressMap getstatic Library/addressMap Ljava/util/Hashtable; aload_1 ; Push the name from variable 1 invokevirtual java/util/Hashtable/get (Ljava/lang/Object;)Ljava/lang/Object;
Since a String is an Object, it's perfectly legal to call the method like this. Now the top of the stack contains an Address, but the JVM doesn't know that. It knows only that the top of the stack contains an Object, since that is what the get method says it returns. If the next thing you try is to send an overdue notice to that address, something bad happens:
invokestatic Library/sendOverdueNotice (LAddress;)V ; ILLEGAL!
The problem is that the JVM can't prove that the Object returned by get is really an Address. You know it, since your program uses the addressMap so that it only has Strings as the keys and Addresses as the values. The JVM sees this as an attempt by the program to use an object in an illegal way that could potentially cause the machine to do something destructive, and it will refuse to load the class.
To get around this, the checkcast instruction checks to see if the object really has the type you expect it to have:
checkcast Address ; Now you know that the top of the stack is an Address invokestatic Library/sendOverdueNotice(LAddress;)V ; OK
Unlike most instructions, checkcast doesn't pop its operand off the stack; it just checks it. If the test succeeds, then it is as though nothing at all has happened. The class of the object has not changed. However, the verification algorithm will no longer complain that you're trying to send an incorrect argument to the method.
The checkcast instruction does not do anything to the reference on top of the stack. Both the object and the reference to it are unchanged. All that has changed is the JVM's perception of the class of the object that the reference refers to. If this perception turns out to be wrong at runtime, the JVM will throw an exception.
Suppose, however, that you accidentally did put something into the addressMap that wasn't an Address. The Hashtable class has no way to check this, since it is designed to handle any Object. In this case, the checkcast instruction will cause a ClassCastException to be thrown when the program reaches the checkcast instruction. For more about exceptions, see section 5.6.
The program cannot reach the invokestatic with an object of the wrong type. If a checkcast fails, then the flow of execution goes to an error handler instead of to the invokestatic instruction. If the checkcast is not present, then the JVM proves that the object on top of the stack must have the appropriate class; other wise, it rejects the class. Under no circumstances does the JVM invoke a method with an argument of the wrong type.