Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Object-oriented language basics, Part 5

The root of all classes

  • Print
  • Feedback
Object-oriented languages, like C++, do not support the notion of a single class from which all other classes derive and is not necessarily a language detriment. However, the lack of such a class would limit Java, as this article's examples show. Java supports a single root class -- a class known as Object.

If you follow the Java 101 column, you know that currently we are touring Java's object-oriented language basics. So far, this series has covered class declaration, object creation, field/method (including constructor method) declaration and access, object layering, and inheritance topics. In addition, I have introduced the specialized topics of enumerated types and singletons.

Read the whole series on object-oriented language basics, and learn what it means for a Java program to be object-oriented:



The Object layer

All Java objects are layered objects. Each class in an object's class hierarchy represents a layer that adds various capabilities to an object. At the top of the hierarchy, you will always find a class named Object. For example, suppose you declare an ObjectLayerDemo class that doesn't (explicitly) extend any other class. Listing 1's ObjectLayerDemo application presents source code to one representation of that class:

Listing 1. ObjectLayerDemo.java

// ObjectLayerDemo.java
class ObjectLayerDemo
{
   int instanceField = 1;
   public static void main (String [] args)
   {
      ObjectLayerDemo old = new ObjectLayerDemo ();
      System.out.println (old.instanceField);
      System.out.println (old.toString ());
   }
}


At first glance, you see nothing special about ObjectLayerDemo. That class declares an instance field and a main() method that creates an ObjectLayerDemo object and prints the instance field's value. However, upon closer examination, you'll notice something strange: old.toString (). Somehow, main() calls a toString() method, even though ObjectLayerDemo does not declare a method with that name or have an explicitly-specified superclass. However, looks can be deceiving. In reality, ObjectLayerDemo implicitly extends class Object. It's as if I specified class ObjectLayerDemo extends Object, which is legal. Because the toString() method originates in Object, and because ObjectLayerDemo implicitly extends Object, it is perfectly legal to call toString() in ObjectLayerDemo's main() method. To see what the layered ObjectLayerDemo object (referenced by old) looks like, check out Figure 1.

Figure 1. Every object, such as the ObjectLayerDemo object referenced by old, contains an Object layer

At the center of Figure 1's ObjectLayerDemo object, you find a blue Object layer. That layer presents some methods that you will examine in this article. The outer green layer -- ObjectLayerDemo -- inherits those methods. That outer layer also presents an instanceField field variable and a main() method.

In general terms, if you have a class A that extends a class B, class B directly extends Object, and class A indirectly extends Object. As a result, class B receives first crack at overriding (some of) Object's methods. What are those methods? Let's find out!

Class information

The first Object method that you will explore is getClass(). When called, getClass() returns a reference to a Class object and has the following signature:

public final Class getClass ()


Because getClass() is a final method, as shown above, you cannot override getClass() in a subclass. The Class object, whose reference returns from getClass(), contains several methods that return various kinds of information about a class, such as constructor, field, and method information. Before looking at those methods, let's find out why we need getClass() and learn how to use it.

Every Java object is associated with a behind-the-scenes Class object, which is the object locked by static synchronized methods -- a topic I will explore in a future article. Also, Class objects are part of Java's Reflection API -- an API that developers use to dynamically determine the names of a class's methods and fields, method parameters and return types, and so on. (I will explore the Reflection API in a future article.) Because the getClass() method offers a convenient way of retrieving the associated class object, getClass() is part of Object. To see getClass() in action, examine Listing 2's source code:

Listing 2. ClassInfoDemo1.java

// ClassInfoDemo1.java
class Employee
{
   private String name;
   Employee (String name)
   {
      this.name = name;
   }
   String getName ()
   {
      return name;
   }
}
class ClassInfoDemo1
{
   public static void main (String [] args)
   {
      ClassInfoDemo1 cid = new ClassInfoDemo1 ();
      Class c = cid.getClass ();
      System.out.println (c.getName ());
      Employee e = new Employee ("John Doe");
      c = e.getClass ();
      System.out.println (c.getName ());
   }
}


ClassInfoDemo1 declares a pair of classes: Employee and ClassInfoDemo1. For each class, ClassInfoDemo1's main() method creates an object from that class and calls getClass() to return the associated Class object. A reference to the Class object assigns to variable c, and calls to Class's getName() method (via object reference variable c) print the appropriate class name (ClassInfoDemo1 followed by Employee).

You cannot call getClass() for every type. For example, it is illegal to call getClass() on a primitive type -- such as char. Also, it might be inconvenient to create an object before you can call getClass(). For those reasons, Java allows you to alternatively attach .class to the end of a type name, as Listing 3 demonstrates:

Listing 3. ClassInfoDemo2.java

// ClassInfoDemo2.java
class Employee
{
   private String name;
   Employee (String name)
   {
      this.name = name;
   }
   String getName ()
   {
      return name;
   }
}
class ClassInfoDemo2
{
   public static void main (String [] args)
   {
      Class c = ClassInfoDemo2.class;
      System.out.println (c.getName ());
      c = Employee.class;
      System.out.println (c.getName ());
      c = char.class;
      System.out.println (c.getName ());
      // The following commented-out line results in a "class expected"
      // compiler error message.
//      c = char.getClass ();
//      System.out.println (c.getName ());
      c = char [].class;
      System.out.println (c.getName ());
   }
}


Instead of specifying ClassInfoDemo2 cid = new ClassInfoDemo2 (); Class c = cid.getClass ();, you can specify Class c = ClassInfoDemo2.class;. (Generally, you can retrieve a Class object for any type x by specifying x.class.) If you run ClassInfoDemo2, you will receive the following output:

  • Print
  • Feedback

Resources