Tuesday, 31 December 2013

Java Errors: ClassNotFoundError, NoClassDefFoundError, UnsupportedClassVersionError, LinkageError, ClassFormatError

As per JVM's parent-delegation class loading model a class can be loaded by either a bootstrap class loader or user defined class loader. During class loading the virtual machine can throw following errors and for the given reasons:
  • NoClassDefFoundError
    • If bootstrap class loader is directly invoked by the virtual machine and it is unable to load the binary data for the requested type.
  • ClassNotFoundError
    • If a user-defined class loader delegates to the bootstrap class loader or to a user-defined class loader which is then unable to load the binary data for the requested type, then the ClassNotFoundError is thrown. 

  • ClassFormatError
    •  If the class is located or produced but not in a proper structure
    • If the class does not contain a superclass and is not class Object.
  •  UnsupportedClassVersionError
    • If the binary data is produced but is not part of a recognized version.
  • LinkageError
    • If class name already appears in the current class loader's name space.

Difference between forName() and loadClass() Java API methods

A Java program can be dynamically extended by using following two APIs:

  1. The forName() method of java.lang.Class class, or
  2. The loadClass() method of an instance of a user-defined class loader.

The forName() method has two overloaded signatures:

  1. public static Class<?>  forName(String className) throws ClassNotFoundException
    • Returns the Class object associated with the class or interface with the given string name.
  2. public static Class<?>  forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException
    • Returns the Class object associated with the class or interface with the given string name, using the given class loader. The class will be initialized if the parameter is true, and if it has not been initialized earlier. If loader parameter is passed as null then it means request is to load class from bootstrap class loader.

The loadClass() method has two overloaded signatures:

  1. public Class<?>   loadClass(String name) throws ClassNotFoundException
    • Loads the class with the specified binary name. If the class is already loaded then it returns the Class instance representing that already-loaded type. If not then is loaded via some customized way decided by the user-defined class loader.
  2. protected Class<?>  loadClass(String name, boolean resolve) throws ClassNotFoundException
    • Loads the class with the specified binary name. The resolve parameter indicates whether or not the type should be linked as well loaded. 

Now it should be clear whether you should use forName() or loadClass(); as it depends on your need; if you have no special needs which requires class loader, you should use forName(); also when you want class to be initialized use forName() with right signature. Class loaders can help you have some custom way of loading types, such as by downloading them across a network, retrieve from a DB, from an encrypted file, or even generating them on the fly.

Initialization is the reason, for example, why JDBC drivers generally loaded with a call to forName(). Because the static initializers of driver class register the driver with a DriverManager.

Note: 

Linking process involves three steps: 
  1. verification of the loaded type; 
  2. preparation, which involves allocating more memory for the type; and
  3. optionally, resolution of symbolic references contained into the type.