2011-02-09 27 views
11

Jeśli mam klasę com.example.test.Enum2.Test jak w poniższym kodzie, dlaczego getCanonicalName() zwraca com.example.test.Enum2.Test, ale Class.forName() wymaga "com.example.test.Enum2$Test" jako argumentu?

Czy istnieje sposób, aby być spójne, tak że mogę serializacji/deserializacji wartość enum od jego nazwy, bez konieczności sprawdzenia każdego $ vs . możliwość, gdy enum jest zagnieżdżona klasa?

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

wyjaśnienia: szukam dobry sposób na radzenie sobie z tym problemem w rzeczywistej aplikacji (nie tylko powyższy wymyślony przypadków testowych), albo:

się. serializować/deserializować przy użyciu wyjścia getCanonicalName() (tylko nazwa kropkowana), a dla Class.forName() wypróbować każdą możliwość po kolei, np. najpierw "com.example.test.Enum2.Test", następnie "com.example.test.Enum2$Test", następnie "com.example.test$Enum2$Test", itp.

b. użyj poprawnej notacji $, aby Class.forName() działała poprawnie za pierwszym razem. Wymaga to jednak zastosowania alternatywy dla metody getCanonicalName(), która tworzy ciąg zgodny z Class.forName().

Pochylam się do podejścia (b), częściowo z powodu odczuwania jelit, częściowo dlatego, że podejście (a) ma niejasności, jeśli istnieją nazwy pakietów z wielkimi literami: com.example.Test.Enum2 i com.example.Test $ Enum2 może być zarówno poprawnymi danymi wejściowymi do Class.forName(), jeśli istnieje com/example/Test/Enum2.java, a com/example/Test.java zawierające wewnętrzną klasę Enum2.

... ale nie wiem jak to zrobić. Jakieś pomysły?

Odpowiedz

9

ARGH: Powinienem był po prostu używać Class.getName() zamiast Class.getCanonicalName().

5

Cóż, docs dla getCanonicalName stanie:

Zwraca kanoniczną nazwę podstawowej klasy zdefiniowaną przez Java Specification Language.

(Kopalnia nacisk).

W Java język, zagnieżdżanie jest oznaczona kropką. Jeśli chodzi o biblioteki i VM, klasa zagnieżdżona to tylko klasa z $ w nazwie.

Nie powiedziałeś o jakiej serializacji mówisz - tak długo, jak jesteś konsekwentny w obu kierunkach, powinno być dobrze.

+0

bummer. więc nazwa języka! = nazwa maszyny wirtualnej. :-(Czy istnieje prostszy sposób na konwersję notacji kropkowanej na właściwe $, bez konieczności wypróbowywania każdej kolejnej opcji (np. Com.example.test.Enum2.Test, com.example.test.Enum2 $ Test, com .example.test $ Enum2 $ Test, itp.) –

+0

@Jason S: Nie, niestety jest niejednoznaczna xyz.ABC może oznaczać 'xyz.ABC', lub' xyz.AB $ C' lub 'xyz.A $ B $ C' lub 'xyz $ A $ B $ C'." Wersja dolara "jest jednak jednoznaczna –

+0

OK, dziękuję, to właśnie myślałem. (+1 dla wyjaśnienia) –