问题 Java:静态嵌套类和反射:“$”vs“。”


如果我有课 com.example.test.Enum2.Test 如下面的代码,为什么 getCanonicalName() 返回 com.example.test.Enum2.Test 但 Class.forName() 要求 "com.example.test.Enum2$Test" 作为一个论点?

有没有办法保持一致,以便我可以按名称序列化/反序列化枚举值,而无需检查每个 $ VS . 可能性,当枚举是一个嵌套类?

package com.example.test;

import java.util.Arrays;

public class Enum2 {

    enum Test {
        FOO, BAR, BAZ;
    }

    public static void main(String[] args) {
        for (String className : Arrays.asList(
                "com.example.test.Enum2.Test",
                "com.example.test.Enum2$Test"))
        {
            try {
                Class<?> cl = Class.forName(className);
                System.out.println(className+" found: "+cl.getCanonicalName());
            }
            catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        System.out.println(Test.FOO.getDeclaringClass().getCanonicalName());
    }
}

澄清: 我正在寻找一种在实际应用程序中处理这个问题的好方法(不仅仅是上面提到的测试用例),或者:

一个。序列化/反序列化使用 getCanonicalName()的输出(仅点缀名称),以及 Class.forName() 反过来尝试每种可能性第一 "com.example.test.Enum2.Test", 然后 "com.example.test.Enum2$Test", 然后 "com.example.test$Enum2$Test"

湾使用适当的$表示法,这样 Class.forName() 第一次正常工作。但是这需要我实现getCanonicalName()的替代方法,它产生一个与之一致的字符串 Class.forName()

我倾向于接近(b),部分来自直觉,部分因为方法(a)有歧义,如果有大写字母的包名:com.example.Test.Enum2和com.example.Test $ Enum2都可以有效输入 Class.forName() 如果有一个com / example / Test / Enum2.java,以及一个包含Enum2内部类的com / example / Test.java。

......但我不知道如何实施它。有任何想法吗?


12003
2018-02-09 18:21


起源



答案:


阿格:我应该一直在使用 Class.getName() 代替 Class.getCanonicalName()


9
2018-02-09 19:02





那么,文档 getCanonicalName 州:

返回基础类的规范名称 由Java语言规范定义

(强调我的。)

在Java中 语言,嵌套用点表示。就库和VM而言,嵌套类只是名称中带有$的类。

你还没有说过你正在谈论什么样的序列化 - 只要你对两个方向都一致,那应该没问题。


5
2018-02-09 18:25



无赖。所以语言的名字!= VM​​的名字。 :-(是否有一种更简单的方法将点分表示法转换为正确的$,而不必依次尝试每种可能性?(例如com.example.test.Enum2.Test,com.example.test.Enum2 $ Test,com .example.test $ Enum2 $ Test等) - Jason S
@Jason S:不,不幸的是它含糊不清。 xyz.A.B.C可能意味着 xyz.A.B.C, 要么 xyz.A.B$C, 要么 xyz.A$B$C 要么 xyz$A$B$C。 “美元版本”虽然明确无误。 - Jon Skeet
好的,谢谢,这就是我的想法。 (+1解释) - Jason S
如果你使用推荐的命名模式,你可以做出很好的猜测:以大写字母开头的类,包装全部小写。 - Jorn


答案:


阿格:我应该一直在使用 Class.getName() 代替 Class.getCanonicalName()


9
2018-02-09 19:02





那么,文档 getCanonicalName 州:

返回基础类的规范名称 由Java语言规范定义

(强调我的。)

在Java中 语言,嵌套用点表示。就库和VM而言,嵌套类只是名称中带有$的类。

你还没有说过你正在谈论什么样的序列化 - 只要你对两个方向都一致,那应该没问题。


5
2018-02-09 18:25



无赖。所以语言的名字!= VM​​的名字。 :-(是否有一种更简单的方法将点分表示法转换为正确的$,而不必依次尝试每种可能性?(例如com.example.test.Enum2.Test,com.example.test.Enum2 $ Test,com .example.test $ Enum2 $ Test等) - Jason S
@Jason S:不,不幸的是它含糊不清。 xyz.A.B.C可能意味着 xyz.A.B.C, 要么 xyz.A.B$C, 要么 xyz.A$B$C 要么 xyz$A$B$C。 “美元版本”虽然明确无误。 - Jon Skeet
好的,谢谢,这就是我的想法。 (+1解释) - Jason S
如果你使用推荐的命名模式,你可以做出很好的猜测:以大写字母开头的类,包装全部小写。 - Jorn