Which java.lang.Class method generates the right input for Class.forName()?

Matt McHenry :

I would like to write some code like this:

Object o = ...;
String oTypeName = o.getClass().getName();

//on the other side of the wire:

Class<?> oClass = Class.forName(oTypeName);
Object oAgain = oClass.newInstance();

However, it's not clear from the javadoc which method I should use to initialize oTypeName, i.e. which method will produce the expected input to Class.forName():

  • getCanonicalName(): "Returns the canonical name of the underlying class as defined by the Java Language Specification. Returns null if the underlying class does not have a canonical name (i.e., if it is a local or anonymous class or an array whose component type does not have a canonical name)."
  • getName(): "Returns the name of the entity (class, interface, array class, primitive type, or void) represented by this Class object, as a String. If this class object represents a reference type that is not an array type then the binary name of the class is returned, as specified by The Java™ Language Specification."
  • getTypeName(): "Return an informative string for the name of this type."

It's fairly obvious that I don't want either of these:

  • getSimpleName(): "Returns the simple name of the underlying class as given in the source code."
  • toString(): "The string representation is the string "class" or "interface", followed by a space, and then by the fully qualified name of the class in the format returned by getName"

I don't expect this to work for primitive types. It's okay if it won't work for arrays. The main thing I'm concerned about is nested classes and Foo.Bar vs. Foo$Bar.

Tunaki :

The definite answer is getName(). Although a bit hidden, this is specified in the Javadoc of the overload of forName(className, initialize, loader):

Given the fully qualified name for a class or interface (in the same format returned by getName) this method attempts to locate, load, and link the class or interface.

And it is also specified that calling forName(className) is equivalent to calling this overload, with default values:

Invoking this method is equivalent to:

Class.forName(className, true, currentLoader) 

where currentLoader denotes the defining class loader of the current class.


Here's a sample code showing that it works for nested classes, local classes, anonymous class, primitive or object arrays. It won't work for primitives because Class.forName doesn't handle primitive classes.

public class Main {
    public static void main(String... args) throws ClassNotFoundException {
        class LocalClass {}

        System.out.println(Class.forName(name(StaticNestedClass.class))); //static nested class
        System.out.println(Class.forName(name(InnerClass.class))); // inner class
        System.out.println(Class.forName(name(Integer[].class))); // object array
        System.out.println(Class.forName(name(int[].class))); // primitive array
        System.out.println(Class.forName(name(List.class))); // interface
        System.out.println(Class.forName(name(LocalClass.class))); // local class
        System.out.println(Class.forName(name(new Object(){}.getClass()))); // anonymous class
    }

    private static String name(Class<?> clazz) {
        return clazz.getName();
    }

    public static class StaticNestedClass {}
    public class InnerClass {}
}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=449955&siteId=1