Reputation: 20909
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
.
Upvotes: 19
Views: 1874
Reputation: 322
Object oAgain = oClass.newInstance();
[EDIT] No Matter which method(getName(), getCanonicalName(), etc..) you cannot use newInstance() method to create an object for a non static inner class
If you are creating an object using newInstance(), then it is mandatory that the underlying class contains a no arg constructor. Even if we explicitly insert one no argument constructor, the compiler will convert it to a constructor with some arguments(Only in case of a non static inner class)
[END EDIT]
Below is the link for brief code that i found. It demonstrates the explanation above.
Upvotes: -1
Reputation: 137064
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 {}
}
Upvotes: 15
Reputation: 300
I always use getCanonicalName() Internal objects (like your Foo$Bar If static public vs inline implementation) will be able to be constructed as well.
Also you can make it work w/ primitives .. 'int.class' for example does exist. However you'll probably have to do a check on the primitives classes, and make the Object instance (Integer vs int) then call the accessor like intValue(). Because of this i use a lot of Object instances vs primitive, but that's just my preference I guess.
Upvotes: 1
Reputation: 20909
It looks like either getName()
or getTypeName()
works, at least in the simple case:
public final class ForNameTest{
public static void main(String[] args) throws Exception{
Object o = new Foo();
System.out.println("class is: " + o.getClass());
for(String getterMethodName : Arrays.asList("getName", "getTypeName", "getCanonicalName")){
Method m = Class.class.getMethod(getterMethodName);
String oTypeName = m.invoke(o.getClass()).toString();
System.out.println(getterMethodName + " yields " + oTypeName);
try{
Class<?> oType = Class.forName(oTypeName);
Object oAgain = oType.newInstance();
System.out.println(" ... and it works: " + oAgain);
} catch (Exception e){
System.err.println(" ... and it fails: " + e);
}
}
}
public static class Foo{}
}
The output produced is:
class is: class ForNameTest$Foo
getName yields ForNameTest$Foo
... and it works: ForNameTest$Foo@4554617c
getTypeName yields ForNameTest$Foo
... and it works: ForNameTest$Foo@74a14482
getCanonicalName yields ForNameTest.Foo
... and it fails: java.lang.ClassNotFoundException: ForNameTest.Foo
Upvotes: 2