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


我想写一些像这样的代码:

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():“返回此类型名称的信息字符串。”

很明显,我不想要其中任何一个:

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

我不认为这适用于原始类型。如果它不适用于数组也没关系。我关心的主要是嵌套类和 Foo.Bar 与 Foo$Bar


11309
2017-07-29 20:46


起源

我的意思是嵌套;问题已更新 - Matt McHenry


答案:


确切的答案是 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 {}
}

9
2017-07-29 21:13



相反,两者都没有 getTypeName 也不 getCanonicalName 例如,将用于原始数组。都 Class.forName(int[].class.getTypeName()) 和 Class.forName(int[].class.getCanonicalName()) 会扔 ClassNotFoundException但是 Class.forName(int[].class.getName()) 将不会。 - palimpsestor
感谢您找到埋藏的javadoc引用 - 这是我正在寻找并找不到的官方单词! - Matt McHenry


它看起来像是 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
2017-07-29 21:03



这正是我到达的地方。哇,你认为你知道的事情(我是 当然 它是 Foo.Bar)然后你去测试它,好吧.... - T.J. Crowder


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

你也可以用原语来工作。例如'int.class'确实存在。但是,您可能必须检查基元类,然后使Object实例(Integer vs int)然后像intValue()一样调用访问器。因此,我使用了大量的Object实例与原语,但这只是我的偏好。


1
2017-07-29 21:08





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


-1
2017-07-29 21:22



实际上,no-arg构造函数不一定是默认构造函数。 - Lew Bloch
编辑答案,我的意思是newInstance()方法期望在您的类中存在无参数构造函数。 - Karthik Cherala