Java: статические вложенные классы и отражение: "$" против ".

Если у меня есть класс com.example.test.Enum2.Test, как в приведенном ниже коде, почему getCanonicalName() return 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().

Я склоняюсь к подходу (б), частично от чувства кишки, и частично потому, что подход (а) имеет двусмысленности, если есть имена пакетов с прописными буквами: com.example.Test.Enum2 и com.example.Test $Enum2 оба могут быть действительными входами в Class.forName(), если есть com/example/Test/Enum2.java и com/example/Test.java, содержащий внутренний класс Enum2.

... но я не знаю, как его реализовать. Любые идеи?

Ответ 1

ARGH: Я должен был просто использовать Class.getName() вместо Class.getCanonicalName().

Ответ 2

Ну, документы для getCanonicalName state:

Возвращает каноническое имя базового класса, как определено спецификацией языка Java.

(Подчеркните мой.)

В Java язык, вложенность указывается точкой. Что касается библиотек и виртуальной машины, вложенный класс - это просто класс с именем $в имени.

Вы не сказали, о какой сериализации вы говорите - пока вы согласны в обоих направлениях, это должно быть хорошо.