Java: статические вложенные классы и рефлексия: "$" против "." - PullRequest
11 голосов
/ 09 февраля 2011

Если у меня есть класс com.example.test.Enum2.Test, как в приведенном ниже коде, почему getCanonicalName() возвращает com.example.test.Enum2.Test, а Class.forName() требует "com.example.test.Enum2$Test" в качестве аргумента?

Есть ли способ бытьнепротиворечиво, так что я могу сериализовать / десериализовать значение перечисления по его имени, не проверяя каждую возможность $ против ., когда перечисление является вложенным классом?

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());
    }
}

уточнение: Я ищу хороший способ решения этой проблемы в реальном приложении (а не только в надуманном тестовом примере), либо:

a.сериализовать / десериализовать, используя вывод 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,и com / example / Test.java, содержащий внутренний класс Enum2.

... но я не знаю, как это реализовать.Есть идеи?

Ответы [ 2 ]

9 голосов
/ 09 февраля 2011

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

5 голосов
/ 09 февраля 2011

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

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

(Акцент мой.)

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

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

...