Hinzufügen von lokalen Klassen, Lambdas und dem toString()
Methode, um die beiden vorherigen Antworten zu vervollständigen. Außerdem füge ich Arrays von Lambdas und Arrays von anonymen Klassen hinzu (die in der Praxis allerdings keinen Sinn machen):
package com.example;
public final class TestClassNames {
private static void showClass(Class<?> c) {
System.out.println("getName(): " + c.getName());
System.out.println("getCanonicalName(): " + c.getCanonicalName());
System.out.println("getSimpleName(): " + c.getSimpleName());
System.out.println("toString(): " + c.toString());
System.out.println();
}
private static void x(Runnable r) {
showClass(r.getClass());
showClass(java.lang.reflect.Array.newInstance(r.getClass(), 1).getClass()); // Obtains an array class of a lambda base type.
}
public static class NestedClass {}
public class InnerClass {}
public static void main(String[] args) {
class LocalClass {}
showClass(void.class);
showClass(int.class);
showClass(String.class);
showClass(Runnable.class);
showClass(SomeEnum.class);
showClass(SomeAnnotation.class);
showClass(int[].class);
showClass(String[].class);
showClass(NestedClass.class);
showClass(InnerClass.class);
showClass(LocalClass.class);
showClass(LocalClass[].class);
Object anonymous = new java.io.Serializable() {};
showClass(anonymous.getClass());
showClass(java.lang.reflect.Array.newInstance(anonymous.getClass(), 1).getClass()); // Obtains an array class of an anonymous base type.
x(() -> {});
}
}
enum SomeEnum {
BLUE, YELLOW, RED;
}
@interface SomeAnnotation {}
Dies ist die vollständige Ausgabe:
getName(): void
getCanonicalName(): void
getSimpleName(): void
toString(): void
getName(): int
getCanonicalName(): int
getSimpleName(): int
toString(): int
getName(): java.lang.String
getCanonicalName(): java.lang.String
getSimpleName(): String
toString(): class java.lang.String
getName(): java.lang.Runnable
getCanonicalName(): java.lang.Runnable
getSimpleName(): Runnable
toString(): interface java.lang.Runnable
getName(): com.example.SomeEnum
getCanonicalName(): com.example.SomeEnum
getSimpleName(): SomeEnum
toString(): class com.example.SomeEnum
getName(): com.example.SomeAnnotation
getCanonicalName(): com.example.SomeAnnotation
getSimpleName(): SomeAnnotation
toString(): interface com.example.SomeAnnotation
getName(): [I
getCanonicalName(): int[]
getSimpleName(): int[]
toString(): class [I
getName(): [Ljava.lang.String;
getCanonicalName(): java.lang.String[]
getSimpleName(): String[]
toString(): class [Ljava.lang.String;
getName(): com.example.TestClassNames$NestedClass
getCanonicalName(): com.example.TestClassNames.NestedClass
getSimpleName(): NestedClass
toString(): class com.example.TestClassNames$NestedClass
getName(): com.example.TestClassNames$InnerClass
getCanonicalName(): com.example.TestClassNames.InnerClass
getSimpleName(): InnerClass
toString(): class com.example.TestClassNames$InnerClass
getName(): com.example.TestClassNames$1LocalClass
getCanonicalName(): null
getSimpleName(): LocalClass
toString(): class com.example.TestClassNames$1LocalClass
getName(): [Lcom.example.TestClassNames$1LocalClass;
getCanonicalName(): null
getSimpleName(): LocalClass[]
toString(): class [Lcom.example.TestClassNames$1LocalClass;
getName(): com.example.TestClassNames$1
getCanonicalName(): null
getSimpleName():
toString(): class com.example.TestClassNames$1
getName(): [Lcom.example.TestClassNames$1;
getCanonicalName(): null
getSimpleName(): []
toString(): class [Lcom.example.TestClassNames$1;
getName(): com.example.TestClassNames$$Lambda$1/1175962212
getCanonicalName(): com.example.TestClassNames$$Lambda$1/1175962212
getSimpleName(): TestClassNames$$Lambda$1/1175962212
toString(): class com.example.TestClassNames$$Lambda$1/1175962212
getName(): [Lcom.example.TestClassNames$$Lambda$1;
getCanonicalName(): com.example.TestClassNames$$Lambda$1/1175962212[]
getSimpleName(): TestClassNames$$Lambda$1/1175962212[]
toString(): class [Lcom.example.TestClassNames$$Lambda$1;
Also, hier sind die Regeln. Beginnen wir mit den primitiven Typen und void
:
- Wenn das Klassenobjekt einen primitiven Typ repräsentiert oder
void
geben alle vier Methoden einfach ihren Namen zurück.
Nun die Regeln für die getName()
Methode:
- Jede Nicht-Lambda- und Nicht-Array-Klasse oder -Schnittstelle (d. h. Top-Level, verschachtelt, inner, lokal und anonym) hat einen Namen (der von
getName()
), d.h. der Paketname, gefolgt von einem Punkt (falls es ein Paket gibt), gefolgt von dem Namen der vom Compiler erzeugten Klassendatei (ohne das Suffix .class
). Wenn es kein Paket gibt, ist es einfach der Name der Klassendatei. Wenn die Klasse eine innere, verschachtelte, lokale oder anonyme Klasse ist, sollte der Compiler mindestens eine $
in seinem Klassendateinamen. Beachten Sie, dass bei anonymen Klassen der Klassenname mit einem Dollar-Zeichen, gefolgt von einer Zahl, endet.
- Lambda-Klassennamen sind im Allgemeinen unvorhersehbar und sollten Ihnen ohnehin egal sein. Genau, ihr Name ist der Name der einschließenden Klasse, gefolgt von
$$Lambda$
, gefolgt von einer Zahl, gefolgt von einem Schrägstrich, gefolgt von einer weiteren Zahl.
- Die Klassendeskriptoren der Primitive sind
Z
para boolean
, B
para byte
, S
para short
, C
para char
, I
para int
, J
para long
, F
para float
y D
para double
. Für Nicht-Array-Klassen und -Schnittstellen lautet der Klassendeskriptor L
gefolgt von dem, was gegeben ist durch getName()
gefolgt von ;
. Bei Array-Klassen lautet der Klassen-Deskriptor [
gefolgt von dem Klassendeskriptor des Komponententyps (der selbst eine andere Array-Klasse sein kann).
- Bei Array-Klassen wird die
getName()
Methode gibt ihren Klassendeskriptor zurück. Diese Regel scheint nur bei Array-Klassen zu versagen, deren Komponententyp ein Lambda ist (was möglicherweise ein Fehler ist), aber das sollte hoffentlich ohnehin keine Rolle spielen, da es nicht einmal auf die Existenz von Array-Klassen ankommt, deren Komponententyp ein Lambda ist.
Nun, die toString()
Methode:
- Wenn die Klasseninstanz eine Schnittstelle (oder eine Anmerkung, die eine spezielle Art von Schnittstelle ist) darstellt, wird die
toString()
gibt zurück. "interface " + getName()
. Wenn es sich um ein Primitiv handelt, gibt es einfach getName()
. Wenn es etwas anderes ist (ein Klassentyp, auch wenn es ein ziemlich seltsamer Typ ist), gibt es zurück "class " + getName()
.
En getCanonicalName()
Methode:
- Für Klassen und Schnittstellen der obersten Ebene wird die
getCanonicalName()
Methode gibt genau das zurück, was die getName()
Methode zurück.
- En
getCanonicalName()
Methode gibt zurück null
für anonyme oder lokale Klassen und für Array-Klassen dieser Klassen.
- Für innere und verschachtelte Klassen und Schnittstellen wird die
getCanonicalName()
Methode gibt zurück, was die getName()
Methode würde die vom Compiler eingeführten Dollar-Zeichen durch Punkte ersetzen.
- Bei Array-Klassen wird die
getCanonicalName()
Methode gibt zurück null
wenn der kanonische Name des Komponententyps null
. Andernfalls gibt es den kanonischen Namen des Komponententyps zurück, gefolgt von []
.
En getSimpleName()
Methode:
- Für Top-Level-, verschachtelte, innere und lokale Klassen wird die
getSimpleName()
gibt den Namen der Klasse zurück, wie er in der Quelldatei steht.
- Bei anonymen Klassen wird die
getSimpleName()
gibt eine leere String
.
- Für Lambda-Klassen wird die
getSimpleName()
gibt nur das zurück, was die getName()
würde ohne den Paketnamen zurückgegeben. Das macht nicht viel Sinn und sieht für mich wie ein Fehler aus, aber es macht keinen Sinn, die getSimpleName()
auf eine Lambda-Klasse zu beginnen.
- Bei Array-Klassen wird die
getSimpleName()
Methode gibt den einfachen Namen der Komponentenklasse zurück, gefolgt von []
. Dies hat den lustigen/unheimlichen Nebeneffekt, dass Array-Klassen, deren Komponententyp eine anonyme Klasse ist, nur []
als ihre einfachen Namen.