There are times when the system throws a ClassCastException if you are casting an object of type A to type A (where A can be any class within your system). Doesn't make any sense, does it? Well, there is a good explanation to this problem that keeps confusing people working with Java environments especially with JSP:s and servlets.

Reason and technical background#

The understanding of this strange phenomenon goes down to the very basics of the Java virtual machine and its data structures. The cause of ClassCastException is technically a difference between two pointers (or references to be more exact) pointing to instances of java.lang.Class. For each object instance in Java we also need an instance of that java.lang.Class representing its bytecode and static allocations. Typically this instance of Class is shared among all objects of same type, which means that a.getClass() == b.getClass() if objects a and b are type MyClass.

The construction of Class objects is usually hidden from application developers and takes place when the JVM meets new object types (classes) for the first time. For example when the code says "new MyClass();" the system notices that there is no code for MyClass and the class loader gets activated. The loader loads the bytecode, allocates static fields and executes the static initializer. The next step after the class construction is to allocate an actual instance of the class. The JVM now calls the new java.lang.Class instance representing MyClass for a new instance, which allocates some memory for instance variables (non-static fields). One important part of this new allocation is a reference back to the actual class object that defines the object type. You can get this reference with getClass() method of the object to see its content.

In some special cases it is possible that there are two or more Class instances representing the same class (either with the same or different bytecode) with their own static areas. It is a common and incorrect belief that static fields are unique within the same virtual machine. Static areas are part of the class instance and since there can be several instances for the same class they all have their own copies of those fields (this is a fact that can be used to detect this problem). So, if we have an A and a B of types MyClass but their instances of MyClass code are different it means that a.getClass() != b.getClass() and we will get a ClassCastException if the code says:

 MyClass A = (MyClass)vector.elementAt(0); 
where the element is B. Confusing? Ok, let's take a closer look to the code. What is really happening is that "(MyClass)" expects that the parameter object has a reference to the class instance (or its class instance has recursively a base class reference to support inheritance) that would be exactly the same as the one given my the local class loader (this.getClass().getClassLoader()). This is important because although we might have the same class name we would still have wrong static allocations and perhaps even wrong bytecode if the instance would not be the same.

When does this happen?#

  • If there are several ClassLoaders and they do not share all their classes. Classes loaded with separate loaders cannot see Class objects from each other and reload binaries. This is usally the case when you are using applications servers and you have several applications that interact together.
  • If you are loading classes explicitly using Class.forName() or by passing their codes directly to the class loader. Explicit class construction can even be used to reconstruct the situation in question.
  • If you are using a system that automatically reloads classes that have been modified. This is usually the case with JSPs. The Servlet engine re-compiles JSPs and loads them although old instances still remain somewhere in memory. You might also meet this problem with some IDEs for the same reason.

Some possible ways to fix the problem#

You can try to specify the problematic classes in the beginning of the CLASSPATH of the default ClassLoader. This usually prevents custom loaders from creating their local copies because default classes are usually visible for all of them.

In case of the rare JSP problems it might be enough if you just restart the servlet engine after page modifications to dispose old classes.

Use explicit ClassLoader definitions in your code to makes sure that you are using the correct ClassLoader for all classes.

If you are getting this problem because you have written your own ClassLoader it usually means that you are not accessing the base loader properly. By default you should always ask if the default ClassLoader already has an instance for the requested class type.

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-29) was last changed on 17-Apr-2012 14:31 by 70.141.116.250