W Javie jaka jest różnica między nimi:
Object o1 = ....
o1.getClass().getSimpleName();
o1.getClass().getName();
o1.getClass().getCanonicalName();
Sprawdziłem Javadoc wiele razy, ale to nigdy nie wyjaśnia tego dobrze. Przeprowadziłem również test, który nie odzwierciedlał żadnego rzeczywistego znaczenia w sposobie wywoływania tych metod.
Odpowiedzi:
Jeśli nie masz pewności, spróbuj najpierw napisać test.
Ja to zrobiłem:
Wydruki:
W ostatnim bloku jest pusty wpis, w którym
getSimpleName
zwraca pusty ciąg.Efektem tego jest:
Class.forName
z domyślnymClassLoader
. W ramach pewnegoClassLoader
, wszystkie klasy mają unikalne nazwy.toString
operacji lub logowania. Gdyjavac
kompilator ma pełny widok ścieżki klasy, wymusza unikatowość nazw kanonicznych w nim, zderzając w pełni kwalifikowane nazwy klas i pakietów w czasie kompilacji. Jednak maszyny JVM muszą zaakceptować takie konflikty nazw, a zatem nazwy kanoniczne nie jednoznacznie identyfikują klasy w obrębieClassLoader
. (Z perspektywy czasu lepsza nazwa tego programu pobierającego byłabygetJavaName
; ale ta metoda pochodzi z czasów, gdy JVM był używany wyłącznie do uruchamiania programów Java).toString
lub operacji rejestrowania ale nie są gwarantowane być unikalne.źródło
Dodanie klas lokalnych, lambdów i
toString()
metody uzupełniania dwóch poprzednich odpowiedzi. Ponadto dodaję tablice lambdas i tablice anonimowych klas (które nie mają jednak żadnego sensu w praktyce):To jest pełny wynik:
Oto zasady. Najpierw zacznijmy od typów pierwotnych i
void
:void
, wszystkie cztery metody po prostu zwracają jego nazwę.Teraz zasady dla
getName()
metody:getName()
), która jest nazwą pakietu, po której następuje kropka (jeśli istnieje pakiet ), a po nim nazwa pliku klasy wygenerowanego przez kompilator (bez sufiksu.class
). Jeśli nie ma pakietu, jest to po prostu nazwa pliku klasy. Jeśli klasa jest klasą wewnętrzną, zagnieżdżoną, lokalną lub anonimową, kompilator powinien wygenerować co najmniej jedną$
w swojej nazwie pliku klasy. Pamiętaj, że w przypadku klas anonimowych nazwa klasy kończy się znakiem dolara, po którym następuje cyfra.$$Lambda$
następuje liczba, po której następuje ukośnik, a następnie kolejny numer.Z
zaboolean
,B
zabyte
,S
zashort
,C
zachar
,I
zaint
,J
zalong
,F
zafloat
iD
dladouble
. W przypadku klas i interfejsów niebędących tablicami po deskryptorze klasyL
następuje, po czymgetName()
następuje;
. W przypadku klas tablic po deskryptorze klasy[
następuje deskryptor klasy typu komponentu (który może być inną klasą tablicy).getName()
metoda zwraca deskryptor klasy. Ta reguła wydaje się zawodzić tylko w przypadku klas tablic, których typem komponentu jest lambda (co prawdopodobnie jest błędem), ale mam nadzieję, że to i tak nie powinno mieć znaczenia, ponieważ nie ma sensu nawet istnienie klas tablic, których typem komponentu jest lambda.Teraz
toString()
metoda:toString()
zwraca"interface " + getName()
. Jeśli jest prymitywny, zwraca po prostugetName()
. Jeśli jest to coś innego (typ klasy, nawet jeśli jest dość dziwny), zwraca"class " + getName()
.getCanonicalName()
Metoda:getCanonicalName()
metoda zwraca tylko to, cogetName()
zwraca metoda.getCanonicalName()
metoda powracanull
do anonimowego lub lokalnych klas i dla klas tablicy z nich.getCanonicalName()
metoda zwraca to, cogetName()
metoda zastąpiłaby znaki dolara wprowadzone przez kompilator kropkami.getCanonicalName()
metoda zwraca,null
jeśli nazwa kanoniczna typu komponentu tonull
. W przeciwnym razie zwraca kanoniczną nazwę typu komponentu, po której następuje[]
.getSimpleName()
Metoda:getSimpleName()
zwraca nazwę klasy zapisaną w pliku źródłowym.getSimpleName()
zwraca pustyString
.getSimpleName()
prostu zwraca to, cogetName()
zwróci bez nazwy pakietu. To nie ma większego sensu i wygląda na błąd, ale nie ma sensu wzywaćgetSimpleName()
klasy lambda na początek.getSimpleName()
metoda zwraca prostą nazwę klasy komponentu, po której następuje[]
. Ma to zabawny / dziwny efekt uboczny, jaki mają takie[]
proste nazwy klas tablic, których typem składowym jest klasa anonimowa .źródło
… replacing the dollar-signs by dots
: Zastępowane są tylko znaki dolara wprowadzone jako ograniczniki. Możesz mieć dolary jako część prostej nazwy, a te pozostaną na swoim miejscu.Oprócz obserwacji Nicka Holta, prowadziłem kilka spraw dotyczących
Array
typu danych:Wydruki kodu powyżej:
źródło
Byłem zdezorientowany szeroką gamą różnych schematów nazewnictwa i właśnie miałem zadać i odpowiedzieć na moje własne pytanie na ten temat, kiedy znalazłem to pytanie tutaj. Myślę, że moje ustalenia pasują wystarczająco dobrze i uzupełniają to, co już jest. Skupiam się na dokumentacji różnych terminów i dodaniu kolejnych powiązanych terminów, które mogą pojawić się w innych miejscach.
Rozważ następujący przykład:
Prosta nazwa z
D
toD
. To tylko część, którą napisałeś, deklarując klasę. Anonimowe klasy nie mają prostej nazwy.Class.getSimpleName()
zwraca tę nazwę lub pusty ciąg. Prosta nazwa może zawierać a,$
jeśli napiszesz ją w ten sposób, ponieważ$
jest to poprawna część identyfikatora zgodnie z sekcją 3.8 JLS (nawet jeśli jest to nieco odradzane).Według sekcji JLS 6.7 , zarówno
a.b.C.D
ia.b.C.D.D.D
będzie w pełni kwalifikowane nazwy , ale tylkoa.b.C.D
byłby kanoniczna nazwa odD
. Każda nazwa kanoniczna jest więc nazwą w pełni kwalifikowaną, ale odwrotność nie zawsze jest prawdziwa.Class.getCanonicalName()
zwróci nazwę kanoniczną lubnull
.Class.getName()
jest udokumentowany, aby zwrócić nazwę binarną , jak określono w sekcji 13.1 JLS . W tym przypadku zwracaa.b.C$D
zaD
i[La.b.C$D;
zaD[]
.Ta odpowiedź pokazuje, że dwie klasy ładowane przez ten sam moduł ładujący klasy mogą mieć tę samą nazwę kanoniczną, ale różne nazwy binarne . Żadna z tych nazw nie jest wystarczająca do wiarygodnego wywnioskowania drugiej: jeśli masz kanoniczną nazwę, nie wiesz, które części nazwy są paczkami, a które zawierają klasy. Jeśli masz nazwę binarną, nie wiesz, które
$
zostały wprowadzone jako separatory, a które były częścią jakiejś prostej nazwy. (Plik klasy przechowuje binarne nazwa z samej klasy i jej klasy załączając , który pozwala wykonawcze do dokonać tego rozróżnienia ).Klasy anonimowe i klasy lokalne nie mają w pełni kwalifikowanych nazw, ale nadal mają nazwy binarne . To samo dotyczy klas zagnieżdżonych w takich klasach. Każda klasa ma nazwę binarną.
Działa
javap -v -private
naa/b/C.class
pokazuje, że bajtowy odnosi się do typud
, jakLa/b/C$D;
i matrycyds
, jak[La/b/C$D;
. Są to tak zwane deskryptory i są określone w sekcji 4.3 JVMS .Nazwa klasy
a/b/C$D
używana w obu tych deskryptorach jest otrzymywana przez zastąpienie.
przez/
w nazwie binarnej. Specyfikacja JVM najwyraźniej nazywa to wewnętrzną formą nazwy binarnej . JVMS sekcja 4.2.1 opisuje to i stwierdza, że różnica od nazwy binarnej wynikała z przyczyn historycznych.Nazwa pliku klasy w jednej z typowych ładowarki filename class oparte na to co masz, jeśli interpretować
/
w wewnętrznej formie binarnej nazwy jako separator katalogów i dołączyć rozszerzenie nazwy pliku.class
do niego. Jest rozwiązany względem ścieżki klasy używanej przez moduł ładujący, o którym mowa.źródło
to najlepszy dokument, który znalazłem opisujący getName (), getSimpleName (), getCanonicalName ()
https://javahowtodoit.wordpress.com/2014/09/09/java-lang-class-what-is-the-difference-between-class-getname-class-getcanonicalname-and-class-getsimplename/
źródło
Interesujące jest to, aby pamiętać, że
getCanonicalName()
igetSimpleName()
może podnieśćInternalError
gdy nazwa klasy jest niepoprawny. Dzieje się tak w przypadku niektórych języków JVM innych niż Java, np. Scala.Rozważ następujące kwestie (Scala 2.11 w Javie 8):
Może to stanowić problem w środowiskach mieszanych lub środowiskach, które dynamicznie ładują kod bajtowy, np. Serwery aplikacji i inne oprogramowanie platformy.
źródło
źródło
Class<StringBuffer> clazz = StringBuffer.class
getName () - zwraca nazwę bytu (klasa, interfejs, klasa tablicowa, typ pierwotny lub void) reprezentowana przez ten obiekt klasy jako ciąg.
getCanonicalName () - zwraca kanoniczną nazwę klasy bazowej zdefiniowanej w specyfikacji języka Java.
getSimpleName () - zwraca prostą nazwę klasy bazowej, to jest nazwę, którą podano w kodzie źródłowym.
Jedną różnicą jest to, że jeśli używasz anonimowej klasy , możesz uzyskać wartość zerową podczas próby uzyskania nazwy klasy za pomocą
getCanonicalName()
Innym faktem jest to, że
getName()
metoda zachowuje się inaczej niżgetCanonicalName()
metoda klas wewnętrznych .getName()
używa dolara jako separatora między kanoniczną nazwą klasy zamykającej a prostą nazwą klasy wewnętrznej.Aby dowiedzieć się więcej na temat pobierania nazwy klasy w Javie .
źródło