Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions

  




 

 

Thinking in Java
Prev Contents / Index Next

The Class object

To understand how RTTI works in Java, you must first know how type information is represented at run time. This is accomplished through a special kind of object called the Class object, which contains information about the class. In fact, the Class object is used to create all of the “regular” objects of your class.

There’s a Class object for each class that is part of your program. That is, each time you write and compile a new class, a single Class object is also created (and stored, appropriately enough, in an identically named .class file). At run time, when you want to make an object of that class, the Java Virtual Machine (JVM) that’s executing your program first checks to see if the Class object for that type is loaded. If not, the JVM loads it by finding the .class file with that name. Thus, a Java program isn’t completely loaded before it begins, which is different from many traditional languages.

Once the Class object for that type is in memory, it is used to create all objects of that type. If this seems shadowy or if you don’t really believe it, here’s a demonstration program to prove it:

//: c10:SweetShop.java
// Examination of the way the class loader works.
import com.bruceeckel.simpletest.*;

class Candy {
  static {
    System.out.println("Loading Candy");
  }
}

class Gum {
  static {
    System.out.println("Loading Gum");
  }
}

class Cookie {
  static {
    System.out.println("Loading Cookie");
  }
}

public class SweetShop {
  private static Test monitor = new Test();
  public static void main(String[] args) {
    System.out.println("inside main");
    new Candy();
    System.out.println("After creating Candy");
    try {
      Class.forName("Gum");
    } catch(ClassNotFoundException e) {
      System.out.println("Couldn't find Gum");
    }
    System.out.println("After Class.forName(\"Gum\")");
    new Cookie();
    System.out.println("After creating Cookie");
    monitor.expect(new String[] {
      "inside main",
      "Loading Candy",
      "After creating Candy",
      "Loading Gum",
      "After Class.forName(\"Gum\")",
      "Loading Cookie",
      "After creating Cookie"
    });
  }
} ///:~


Each of the classes Candy, Gum, and Cookie have a static clause that is executed as the class is loaded for the first time. Information will be printed to tell you when loading occurs for that class. In main( ), the object creations are spread out between print statements to help detect the time of loading.

You can see from the output that each Class object is loaded only when it’s needed, and the static initialization is performed upon class loading.

A particularly interesting line is:

Class.forName("Gum");


This method is a static member of Class (to which all Class objects belong). A Class object is like any other object, so you can get and manipulate a reference to it (that’s what the loader does). One of the ways to get a reference to the Class object is forName( ), which takes a String containing the textual name (watch the spelling and capitalization!) of the particular class you want a reference for. It returns a Class reference, which is being ignored here; the call to forName( ) is being made for its side effect, which is to load the class Gum if it isn’t already loaded. In the process of loading, Gum’s static clause is executed.

In the preceding example, if Class.forName( ) fails because it can’t find the class you’re trying to load, it will throw a ClassNotFoundException (ideally, exception names tell you just about everything you need to know about the problem). Here, we simply report the problem and move on, but in more sophisticated programs, you might try to fix the problem inside the exception handler.

Class literals

Java provides a second way to produce the reference to the Class object: the class literal. In the preceding program this would look like:

Gum.class;


which is not only simpler, but also safer since it’s checked at compile time. Because it eliminates the method call, it’s also more efficient.

Class literals work with regular classes as well as interfaces, arrays, and primitive types. In addition, there’s a standard field called TYPE that exists for each of the primitive wrapper classes. The TYPE field produces a reference to the Class object for the associated primitive type, such that:

... is equivalent to ...

boolean.class

Boolean.TYPE

char.class

Character.TYPE

byte.class

Byte.TYPE

short.class

Short.TYPE

int.class

Integer.TYPE

long.class

Long.TYPE

float.class

Float.TYPE

double.class

Double.TYPE

void.class

Void.TYPE

My preference is to use the “.class” versions if you can, since they’re more consistent with regular classes.
Thinking in Java
Prev Contents / Index Next


 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire