Monday 30 June 2008

Java: class names

In Java, it is possible to get a String representation of a class by calling the Class.getName() method. Since Java 1.5 (AKA Java 5), it has been possible to get the canonical name using Class.getCanonicalName().

javadoc: java.lang.Class

For many classes, these two methods will return identical values. Things get more interesting when it comes to some of the more esoteric types such as arrays and inner classes. The code is provided for completeness, but feel free to skip to the output table.

public class ClassFoo {

  enum FooEnum {
    VAL1,
    VAL2,
  }
  interface InterfaceBar {}
  class InnerClassFoo2 {}
  
  public static Class<?> getAnonymousInnerClass() {
    return new Object(){}.getClass();
  }
  
  public static Class<?> getLocalInnerClass() {
    class extends Object {}
    return X.class;
  }
  
}

Using the example class above, the following code introspects the types:

    Class<?>[] someTypes = {
        String.class,
        String[].class,
        String[][].class,
        Integer.class,
        Integer.TYPE,
        int[].class,
        int[][].class,
        ClassFoo.class,
        ClassFoo.FooEnum.VAL1.getClass(),
        ClassFoo.InnerClassFoo2.class,
        ClassFoo.InterfaceBar.class,
        ClassFoo.getAnonymousInnerClass(),
        ClassFoo.getLocalInnerClass(),
        Void.TYPE,
    };
    
    for(int i=0; i<someTypes.length; i++) {
      Class<?> c = someTypes[i];
      System.out.print(c.getName());
      System.out.print('\t');
      System.out.println(c.getCanonicalName());
    }


The following table lists the output.

Class Instance Class.getName() Class.getCanonicalName() Notes
String.class java.lang.String java.lang.String
String[].class [Ljava.lang.String; java.lang.String[] string array
String[][].class [[Ljava.lang.String; java.lang.String[][] two-dimensional string array
Integer.class java.lang.Integer java.lang.Integer Integer object
Integer.TYPE int int primitive int
int[].class [I int[] int array
int[][].class [[I int[][] two-dimensional int array
ClassFoo.class ClassFoo ClassFoo (default package)
ClassFoo.FooEnum.VAL1.getClass() ClassFoo$FooEnum ClassFoo.FooEnum inner enumeration
ClassFoo.InnerClassFoo2.class ClassFoo$InnerClassFoo2 ClassFoo.InnerClassFoo2 inner class
ClassFoo.InterfaceBar.class ClassFoo$InterfaceBar ClassFoo.InterfaceBar inner interface
ClassFoo.getAnonymousInnerClass() ClassFoo$1 null anonymous inner class
ClassFoo.getLocalInnerClass() ClassFoo$1X null local inner class
Void.TYPE void void void type

Note that in the case of arrays, class names are prefixed by the number of '[' characters equivalent to the number of array dimensions followed by a letter constant. For example, [I is the class name for an int[] object and [L denotes any object array. The remaining primitive types are listed in the javadoc.

Which value to use depends on the application. getCanonicalName() is useful for displaying the type to developers or generating code. getName() provides more useful information on inner types and corresponds more closely to the class names as defined in class repositories (like JAR files). For example, the following is the valid method for loading the type InnerClassFoo2.

ClassLoader.getSystemClassLoader().loadClass("ClassFoo$InnerClassFoo2")

2 comments:

  1. This might just be the perfect blog post. Really concise and helpful. I wouldn't have thought of that last point about use with class loading, which is actually really important for me. Thanks for saving me a lot of time.

    ReplyDelete
  2. Yes, excellent post!
    There's also a Class.getSimpleName() method that might be worth including in this comparison.
    To this end I changed the System.out.print lines in McDowell's code to:
    System.out.print(String.format("%-25s", c.getName()));
    System.out.print(String.format("%-25s", c.getCanonicalName()));
    System.out.println(c.getSimpleName());
    /Mikko Östlund (Stockholm, Sweden)

    ReplyDelete

All comments are moderated