En Java, quelle est la différence entre ceux-ci:
Object o1 = ....
o1.getClass().getSimpleName();
o1.getClass().getName();
o1.getClass().getCanonicalName();
J'ai vérifié le Javadoc plusieurs fois et pourtant cela ne l'explique jamais bien. J'ai également effectué un test et cela ne reflétait aucune signification réelle derrière la façon dont ces méthodes sont appelées.
Réponses:
Si vous n'êtes pas sûr de quelque chose, essayez d'abord d'écrire un test.
J'ai fait ça:
Tirages:
Il y a une entrée vide dans le dernier bloc où
getSimpleName
renvoie une chaîne vide.Le résultat en regardant ceci est:
Class.forName
avec la valeur par défautClassLoader
. Dans le cadre d'un certainClassLoader
, toutes les classes ont des noms uniques.toString
ou lors des opérations de journalisation. Lorsque lejavac
compilateur a une vue complète d'un chemin de classe, il applique l'unicité des noms canoniques en le confrontant aux noms de classe et de package pleinement qualifiés au moment de la compilation. Cependant, les machines virtuelles Java doivent accepter de tels conflits de noms, et donc les noms canoniques n'identifient pas de manière unique les classes dans aClassLoader
. (Rétrospectivement, un meilleur nom pour cet getter aurait étégetJavaName
; mais cette méthode date d'une époque où la JVM n'était utilisée que pour exécuter des programmes Java.)toString
les opérations de journalisation, mais n'est pas garanti d'être unique.la source
Ajout de classes locales, de lambdas et de la
toString()
méthode pour compléter les deux réponses précédentes. De plus, j'ajoute des tableaux de lambdas et des tableaux de classes anonymes (qui n'ont cependant aucun sens dans la pratique):Voici la sortie complète:
Voici donc les règles. Tout d'abord, commençons par les types primitifs et
void
:void
, les quatre méthodes renvoient simplement son nom.Maintenant, les règles de la
getName()
méthode:getName()
) qui est le nom du package suivi d'un point (s'il y a un package ), suivi du nom de son fichier de classe tel que généré par le compilateur (sans le suffixe.class
). S'il n'y a pas de package, c'est simplement le nom du fichier de classe. Si la classe est une classe interne, imbriquée, locale ou anonyme, le compilateur doit en générer au moins une$
dans son nom de fichier de classe. Notez que pour les classes anonymes, le nom de la classe se terminerait par un signe dollar suivi d'un nombre.$$Lambda$
, suivi d'un nombre, suivi d'une barre oblique, suivi d'un autre nombre.Z
pourboolean
,B
pourbyte
,S
pourshort
,C
pourchar
,I
pourint
,J
pourlong
,F
pourfloat
etD
pourdouble
. Pour les classes et interfaces non matricielles, le descripteur de classe estL
suivi de ce qui est donné pargetName()
suivi de;
. Pour les classes de tableau, le descripteur de classe est[
suivi du descripteur de classe du type de composant (qui peut être lui-même une autre classe de tableau).getName()
méthode renvoie son descripteur de classe. Cette règle semble échouer uniquement pour les classes de tableau dont le type de composant est un lambda (ce qui est peut-être un bogue), mais j'espère que cela ne devrait pas avoir d'importance de toute façon car il n'y a aucun point même sur l'existence de classes de tableau dont le type de composant est un lambda.Maintenant, la
toString()
méthode:toString()
retourne"interface " + getName()
. S'il s'agit d'une primitive, elle revient simplementgetName()
. Si c'est autre chose (un type de classe, même s'il est assez bizarre), il revient"class " + getName()
.La
getCanonicalName()
méthode:getCanonicalName()
méthode renvoie exactement ce qu'ellegetName()
renvoie.getCanonicalName()
méthode renvoienull
pour les classes anonymes ou locales et pour les classes de tableau de celles-ci.getCanonicalName()
méthode renvoie ce que lagetName()
méthode remplacerait les signes dollar introduits par le compilateur par des points.getCanonicalName()
méthode renvoienull
si le nom canonique du type de composant estnull
. Sinon, il renvoie le nom canonique du type de composant suivi de[]
.La
getSimpleName()
méthode:getSimpleName()
renvoie le nom de la classe tel qu'il est écrit dans le fichier source.getSimpleName()
renvoie un videString
.getSimpleName()
renvoie simplement ce que legetName()
retournerait sans le nom du package. Cela n'a pas beaucoup de sens et ressemble à un bogue pour moi, mais il est inutile d'appelergetSimpleName()
une classe lambda pour commencer.getSimpleName()
méthode renvoie le nom simple de la classe de composants suivi de[]
. Cela a pour effet secondaire drôle / bizarre que les classes de tableaux dont le type de composant est une classe anonyme ont tout[]
comme leurs noms simples.la source
… replacing the dollar-signs by dots
: Seuls les signes dollar introduits comme délimiteurs sont remplacés. Vous pouvez très bien avoir des dollars dans un nom simple, et ceux-ci resteront en place.En plus des observations de Nick Holt, j'ai exécuté quelques cas pour
Array
le type de données:Copies d'extrait de code ci-dessus:
la source
J'ai également été confondu par le large éventail de schémas de nommage différents, et j'étais sur le point de poser et de répondre à ma propre question à ce sujet lorsque j'ai trouvé cette question ici. Je pense que mes résultats correspondent assez bien et complètent ce qui est déjà là. Je me concentre sur la recherche de documentation sur les différents termes et sur l'ajout d'autres termes connexes qui pourraient apparaître à d'autres endroits.
Prenons l'exemple suivant:
Le nom simple de
D
estD
. C'est juste la partie que vous avez écrite lors de la déclaration de la classe. Les classes anonymes n'ont pas de nom simple.Class.getSimpleName()
renvoie ce nom ou la chaîne vide. Il est possible que le nom simple contienne un$
si vous l'écrivez comme ceci, car il$
s'agit d'une partie valide d'un identifiant selon la section 3.8 de JLS (même s'il est quelque peu déconseillé).Selon la section 6.7 de JLS , les deux
a.b.C.D
eta.b.C.D.D.D
seraient des noms pleinement qualifiés , mais seula.b.C.D
serait le nom canonique deD
. Ainsi, chaque nom canonique est un nom complet, mais l'inverse n'est pas toujours vrai.Class.getCanonicalName()
renverra le nom canonique ounull
.Class.getName()
est documenté pour renvoyer le nom binaire , comme spécifié dans la section 13.1 de JLS . Dans ce cas, il revienta.b.C$D
pourD
et[La.b.C$D;
pourD[]
.Cette réponse montre qu'il est possible que deux classes chargées par le même chargeur de classe aient le même nom canonique mais des noms binaires distincts . Aucun nom n'est suffisant pour déduire de manière fiable l'autre: si vous avez le nom canonique, vous ne savez pas quelles parties du nom sont des packages et lesquelles contiennent des classes. Si vous avez le nom binaire, vous ne savez pas lesquels
$
ont été introduits comme séparateurs et qui faisaient partie d'un nom simple. (Le fichier de classe stocke le nom binaire de la classe elle - même et de sa classe englobante , ce qui permet au runtime de faire cette distinction .)Les classes anonymes et les classes locales n'ont pas de nom complet mais ont toujours un nom binaire . Il en va de même pour les classes imbriquées dans ces classes. Chaque classe a un nom binaire.
Fonctionnement
javap -v -private
sura/b/C.class
montre que le bytecode fait référence au type ded
asLa/b/C$D;
et à celui du tableauds
as[La/b/C$D;
. Ils sont appelés descripteurs et ils sont spécifiés dans la section 4.3 de JVMS .Le nom de classe
a/b/C$D
utilisé dans ces deux descripteurs est ce que vous obtenez en remplaçant.
par/
dans le nom binaire. La spécification JVM appelle apparemment cela la forme interne du nom binaire . La section 4.2.1 de JVMS le décrit et déclare que la différence avec le nom binaire était pour des raisons historiques.Le nom du fichier de d'une classe dans l'un des chargeurs de classe basés sur le nom de fichier typique est ce que vous obtenez si vous interprétez le
/
sous la forme interne du nom binaire comme un séparateur de répertoire et y ajoutez l'extension de nom de fichier.class
. Il est résolu par rapport au chemin de classe utilisé par le chargeur de classe en question.la source
c'est le meilleur document que j'ai trouvé décrivant 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/
la source
Il est intéressant de noter que
getCanonicalName()
etgetSimpleName()
peut augmenterInternalError
lorsque le nom de la classe est mal formé. Cela se produit pour certains langages JVM non Java, par exemple Scala.Tenez compte des éléments suivants (Scala 2.11 sur Java 8):
Cela peut être un problème pour les environnements de langage mixte ou les environnements qui chargent dynamiquement le bytecode, par exemple, les serveurs d'applications et d'autres logiciels de plate-forme.
la source
getName () - renvoie le nom de l'entité (classe, interface, classe de tableau, type primitif ou void) représentée par cet objet Class, sous la forme d'une chaîne.
getCanonicalName () - renvoie le nom canonique de la classe sous-jacente tel que défini par la spécification du langage Java.
getSimpleName () - renvoie le nom simple de la classe sous-jacente, c'est-à-dire le nom qui lui a été donné dans le code source.
Une différence est que si vous utilisez une classe anonyme, vous pouvez obtenir une valeur nulle lorsque vous essayez d'obtenir le nom de la classe à l'aide de la classe
getCanonicalName()
Un autre fait est que la
getName()
méthode se comporte différemment de lagetCanonicalName()
méthode des classes internes .getName()
utilise un dollar comme séparateur entre le nom canonique de la classe englobante et le nom simple de la classe interne.Pour en savoir plus sur la récupération d'un nom de classe en Java .
la source
la source
Class<StringBuffer> clazz = StringBuffer.class