我想写一些像这样的代码:
Object o = ...;
String oTypeName = o.getClass().getName();
//on the other side of the wire:
Class<?> oClass = Class.forName(oTypeName);
Object oAgain = oClass.newInstance();
但是,从javadoc中我不清楚应该使用哪种方法进行初始化 oTypeName
,即哪种方法将产生预期的输入 Class.forName()
:
getCanonicalName()
:“返回由Java语言规范定义的基础类的规范名称。如果基础类没有规范名称(即,如果它是本地或匿名类或其组件类型不具有的数组,则返回null)一个规范的名字。)“
getName()
:“返回此Class对象表示的实体的名称(类,接口,数组类,基本类型或void),作为String。如果此类对象表示不是数组类型的引用类型,则为二进制名称按照Java语言规范的规定返回类的类。“
getTypeName()
:“返回此类型名称的信息字符串。”
很明显,我不想要其中任何一个:
我不认为这适用于原始类型。如果它不适用于数组也没关系。我关心的主要是嵌套类和 Foo.Bar
与 Foo$Bar
。
确切的答案是 getName()
。虽然有点隐藏,但这是在重载的Javadoc中指定的 forName(className, initialize, loader)
:
给定类或接口的完全限定名称(以相同的格式返回 getName
)此方法尝试定位,加载和链接类或接口。
并且它还指定了调用 forName(className)
相当于使用默认值调用此重载:
调用此方法相当于:
Class.forName(className, true, currentLoader)
其中currentLoader表示当前类的定义类加载器。
这是一个示例代码,显示它适用于嵌套类,本地类,匿名类,基元或对象数组。它不适用于原语,因为 Class.forName
不处理原始类。
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 {}
}
它看起来像是 getName()
要么 getTypeName()
工作,至少在简单的情况下:
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{}
}
产生的输出是:
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
我总是使用getCanonicalName()内部对象(如你的Foo $ Bar如果静态公共vs内联实现)也可以构造。
你也可以用原语来工作。例如'int.class'确实存在。但是,您可能必须检查基元类,然后使Object实例(Integer vs int)然后像intValue()一样调用访问器。因此,我使用了大量的Object实例与原语,但这只是我的偏好。
Object oAgain = oClass.newInstance();
[编辑]
没有问题哪个方法(getName(),getCanonicalName()等...)你 不能 使用newInstance()方法为非静态内部类创建对象
如果使用newInstance()创建对象,则基础类必须包含无arg构造函数。即使我们显式插入一个无参数构造函数,编译器也会将它转换为带有一些参数的构造函数(仅在非静态内部类的情况下)
[结束编辑]
以下是我找到的简短代码的链接。它演示了上面的解释。
http://thecodersbreakfast.net/index.php?post/2011/09/26/Inner-classes-and-the-myth-of-the-default-constructor