哪个java.lang.Class方法为Class.forName()生成正确的输入?

哪个java.lang.Class方法为Class.forName()生成正确的输入?,java,reflection,Java,Reflection,我想写一些这样的代码: Object o = ...; String oTypeName = o.getClass().getName(); //on the other side of the wire: Class<?> oClass = Class.forName(oTypeName); Object oAgain = oClass.newInstance(); 对象o=。。。; 字符串oTypeName=o.getClass().getName(); //在导线的另一侧

我想写一些这样的代码:

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

//on the other side of the wire:

Class<?> oClass = Class.forName(oTypeName);
Object oAgain = oClass.newInstance();
对象o=。。。; 字符串oTypeName=o.getClass().getName(); //在导线的另一侧: Class-oClass=Class.forName(oTypeName); 对象oAgain=oClass.newInstance(); 但是,javadoc不清楚我应该使用哪种方法初始化
oTypeName
,即哪种方法将产生预期的输入:

  • :“返回Java语言规范定义的基础类的规范名称。如果基础类没有规范名称(即,如果它是本地或匿名类,或者组件类型没有规范名称的数组),则返回null。”
  • :“以字符串形式返回由该类对象表示的实体(类、接口、数组类、基元类型或void)的名称。如果该类对象表示的引用类型不是数组类型,则返回该类的二进制名称,如Java™ 语言规范。”
  • :“返回此类型名称的信息字符串。”
很明显,我不想要这些:

  • :“返回源代码中给定的基础类的简单名称。”
  • :“字符串表示法是字符串“class”或“interface”,后跟空格,然后是类的完全限定名,格式为getName返回”

我不认为这适用于基本类型。如果它对数组不起作用,也没关系。我关心的主要问题是嵌套类和
Foo.Bar
Foo$Bar

看起来
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{}
}

我总是使用getCanonicalName()也可以构造内部对象(如静态公共与内联实现中的Foo$Bar)

您还可以使用原语使其工作。'例如,int.class确实存在。但是,您可能需要检查基本类,并生成对象实例(Integer vs int),然后调用类似intValue()的访问器。正因为如此,我使用了很多对象实例与基本体,但我想这只是我的偏好。

确切的答案是。虽然有点隐藏,但在重载的Javadoc中指定了:

给定类或接口的完全限定名(,格式与
getName
返回的格式相同),此方法尝试定位、加载和链接类或接口

并且还指定调用相当于调用此重载,默认值为:

调用此方法相当于:

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 {}
}
公共类主{
公共静态void main(字符串…参数)引发ClassNotFoundException{
类LocalClass{}
System.out.println(Class.forName(name(StaticNestedClass.Class));//静态嵌套类
System.out.println(Class.forName(name(InnerClass.Class));//内部类
System.out.println(Class.forName(name(Integer[].Class));//对象数组
System.out.println(Class.forName(name(int[].Class));//基元数组
System.out.println(Class.forName(name(List.Class));//接口
System.out.println(Class.forName(name(LocalClass.Class));//本地类
System.out.println(Class.forName(name(new Object(){}.getClass()));//匿名类
}
私有静态字符串名称(类clazz){
返回clazz.getName();
}
公共静态类StaticNestedClass{}
公共类内部类{}
}
[编辑] 无论使用哪种方法(getName()、getCanonicalName()等),都不能使用newInstance()方法为非静态内部类创建对象

如果使用newInstance()创建对象,则底层类必须包含无参数构造函数。即使我们显式地插入一个无参数构造函数,编译器也会将其转换为带有一些参数的构造函数(仅在非静态内部类的情况下)

[结束编辑]

下面是我找到的简短代码的链接。它演示了上面的解释


我的意思是嵌套的;问题更新了这也是我要说的。哇,你认为你知道一些东西(我确信它是
Foo.Bar
),然后你去测试它,嗯……相反地,
getTypeName
getCanonicalName
都不适用于,例如,基元数组。
Class.forName(int[].Class.getTypeName())
Class.forName(int[].Class.getCanonicalName())
都会抛出
ClassNotFoundException
,但
Class.forName(int[].Class.getName())
不会。感谢您找到隐藏的javadoc引用——这是我一直在寻找的官方单词,但找不到!实际上,无参数构造函数不一定是默认构造函数。编辑答案,我的意思是newInstance()方法要求类中存在无参数构造函数。
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 {}
}
Object oAgain = oClass.newInstance();