2011-02-09 5 views
11

Если у меня есть класс 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()); 
    } 
} 

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

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

b. используйте правильную $ notation, так что 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.

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

ответ

9

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

5

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

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

(выделено мной.)

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

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

+0

bummer. поэтому имя языка! = имя виртуальной машины. :-(Есть ли более простой способ преобразовать пунктирную нотацию в правильный $, без необходимости попробовать каждую возможность по очереди? (Например, com.example.test.Enum2.Test, com.example.test.Enum2 $ Test, com .example.test $ Enum2 $ Test и т. д.) –

+0

@Jason S: Нет, к сожалению, это неоднозначно. xyz.ABC может означать 'xyz.ABC', или' xyz.AB $ C', или 'xyz.A $ B $ C' или 'xyz $ A $ B $ C'. Однако« долларовая версия »однозначна. –

+0

ОК, спасибо, вот что я подумал. (+1 для объяснения) –

Смежные вопросы