我想写一些这样的代码:
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()
:&#34;返回Java语言规范定义的基础类的规范名称。如果基础类没有规范名称(即,如果它是本地或匿名类或其组件类型没有规范名称的数组),则返回null。&#34; getName()
:&#34;返回此Class对象表示的实体名称(类,接口,数组类,基本类型或void),作为String。如果此类对象表示不是数组类型的引用类型,则返回该类的二进制名称,如Java™语言规范所指定。&#34; getTypeName()
:&#34;返回此类型名称的信息字符串。&#34; 很明显,我不想要其中任何一个:
getSimpleName()
:&#34;返回源代码中给出的基础类的简单名称。&#34; toString()
:&#34;字符串表示是字符串&#34; class&#34;或者&#34;接口&#34;,后跟一个空格,然后是getName&#34; 我不希望这适用于原始类型。如果它不能为数组工作,那没关系。我关注的主要问题是嵌套类和Foo.Bar
与Foo$Bar
。
答案 0 :(得分:11)
明确的答案是getName()
。虽然有点隐藏,但这是在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 {}
}
答案 1 :(得分:2)
看起来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
答案 2 :(得分:1)
我总是使用getCanonicalName()内部对象(如你的Foo $ Bar如果静态公共vs内联实现)也可以构造。
此外,你可以使它与原语一起工作..&#39; int.class&#39;例如确实存在。但是,您可能必须检查基元类,并使Object实例(Integer vs int)然后像intValue()一样调用访问器。因此,我使用了很多对象实例和原始对象,但我认为这只是我的偏好。
答案 3 :(得分:-1)
Object oAgain = oClass.newInstance();
[编辑] 无问题哪个方法(getName(),getCanonicalName()等等)不能使用newInstance()方法为非静态内部类创建对象
如果使用newInstance()创建对象,则底层类必须包含no arg构造函数。即使我们显式插入一个无参数构造函数,编译器也会将它转换为带有一些参数的构造函数(仅在非静态内部类的情况下)
[结束编辑]
以下是我找到的简短代码的链接。它演示了上面的解释。