Em Java, qual é a diferença entre estes:
Object o1 = ....
o1.getClass().getSimpleName();
o1.getClass().getName();
o1.getClass().getCanonicalName();
Eu verifiquei o Javadoc várias vezes e, no entanto, isso nunca explica muito bem. Também fiz um teste e isso não refletia nenhum significado real por trás da maneira como esses métodos são chamados.
Respostas:
Se você não tiver certeza sobre algo, tente escrever um teste primeiro.
Eu fiz isso:
Impressões:
Há uma entrada vazia no último bloco em que
getSimpleName
retorna uma string vazia.O resultado final é:
Class.forName
com o padrãoClassLoader
. Dentro do escopo de um certoClassLoader
, todas as classes têm nomes exclusivos.toString
ou operações de log. Quando ojavac
compilador tem uma visão completa de um caminho de classe, ele impõe a exclusividade de nomes canônicos dentro dele, colidindo nomes de classes e pacotes totalmente qualificados no momento da compilação. No entanto, as JVMs devem aceitar conflitos de nome e, portanto, nomes canônicos não identificam exclusivamente classes dentro de aClassLoader
. (Em retrospectiva, teria sido um nome melhor para esse gettergetJavaName
; mas esse método data de uma época em que a JVM foi usada apenas para executar programas Java.)toString
ou operações de registro, mas não é garantido que seja exclusivo.fonte
Adicionando classes locais, lambdas e o
toString()
método para concluir as duas respostas anteriores. Além disso, adiciono matrizes de lambdas e matrizes de classes anônimas (que, na prática, não fazem nenhum sentido):Esta é a saída completa:
Então, aqui estão as regras. Primeiro, vamos começar com tipos primitivos e
void
:void
, todos os quatro métodos simplesmente retornam seu nome.Agora as regras para o
getName()
método:getName()
) que é o nome do pacote seguido por um ponto (se houver um pacote ), seguido pelo nome do seu arquivo de classe, conforme gerado pelo compilador (sem o sufixo.class
). Se não houver pacote, é simplesmente o nome do arquivo de classe. Se a classe for uma classe interna, aninhada, local ou anônima, o compilador deve gerar pelo menos um$
em seu nome de arquivo de classe. Observe que, para classes anônimas, o nome da classe terminaria com um cifrão seguido de um número.$$Lambda$
, seguido por um número, seguido por uma barra, seguido por outro número.Z
paraboolean
,B
parabyte
,S
parashort
,C
parachar
,I
paraint
,J
paralong
,F
parafloat
eD
paradouble
. Para classes e interfaces que não são de matriz, o descritor de classe éL
seguido pelo que é fornecido porgetName()
seguido por;
. Para classes de matriz, o descritor de classe é[
seguido pelo descritor de classe do tipo de componente (que pode ser outra classe de matriz).getName()
método retorna seu descritor de classe. Essa regra parece falhar apenas para classes de matriz cujo tipo de componente é um lambda (que possivelmente é um bug), mas espero que isso não importe de qualquer maneira, porque não faz sentido nem mesmo a existência de classes de matriz cujo tipo de componente é um lambda.Agora, o
toString()
método:toString()
retornos"interface " + getName()
. Se é um primitivo, ele retorna simplesmentegetName()
. Se for outra coisa (um tipo de classe, mesmo que seja bem estranho), ele retornará"class " + getName()
.O
getCanonicalName()
método:getCanonicalName()
método retorna exatamente o que ogetName()
método retorna.getCanonicalName()
método retornanull
para classes anônimas ou locais e para classes de matriz dessas.getCanonicalName()
método retorna o que ogetName()
método substituiria os cifrões introduzidos pelo compilador por pontos.getCanonicalName()
método retornanull
se o nome canónica do tipo de componente énull
. Caso contrário, ele retornará o nome canônico do tipo de componente seguido por[]
.O
getSimpleName()
método:getSimpleName()
retorna o nome da classe conforme escrito no arquivo de origem.getSimpleName()
retorno é vazioString
.getSimpleName()
just retorna ogetName()
que retornaria sem o nome do pacote. Isso não faz muito sentido e parece um bug para mim, mas não faz sentido chamargetSimpleName()
uma classe lambda para começar.getSimpleName()
método retorna o nome simples da classe de componente seguido por[]
. Isso tem o efeito colateral engraçado / estranho de que as classes de matriz cujo tipo de componente é uma classe anônima têm apenas[]
seus nomes simples.fonte
… replacing the dollar-signs by dots
: Somente os sinais de dólar introduzidos como delimitadores estão sendo substituídos. Você pode ter dólares como parte de um nome simples, e esses permanecerão no lugar.Além das observações de Nick Holt, executei alguns casos para o
Array
tipo de dados:Impressões acima do snippet de código:
fonte
Também fiquei confuso com a ampla gama de esquemas de nomes diferentes e estava prestes a fazer e responder minha própria pergunta sobre isso quando a encontrei aqui. Acho que minhas descobertas se encaixam bem o suficiente e complementam o que já está aqui. Meu foco é procurar documentação sobre os vários termos e adicionar outros termos relacionados que podem surgir em outros lugares.
Considere o seguinte exemplo:
O nome simples de
D
éD
. Essa é apenas a parte que você escreveu ao declarar a classe. Classes anônimas não têm um nome simples.Class.getSimpleName()
retorna esse nome ou a sequência vazia. É possível que o nome simples contenha a$
se você o escrever assim, pois$
é uma parte válida de um identificador conforme a seção 3.8 do JLS (mesmo que seja um pouco desencorajado).De acordo com a seção 6.7 do JLS , ambos
a.b.C.D
ea.b.C.D.D.D
seriam nomes totalmente qualificados , mas somentea.b.C.D
o nome canônico deD
. Portanto, todo nome canônico é um nome totalmente qualificado, mas o inverso nem sempre é verdadeiro.Class.getCanonicalName()
retornará o nome canônico ounull
.Class.getName()
está documentado para retornar o nome binário , conforme especificado na seção 13.1 do JLS . Nesse caso, ele retornaa.b.C$D
paraD
e[La.b.C$D;
paraD[]
.Esta resposta demonstra que é possível que duas classes carregadas pelo mesmo carregador de classes tenham o mesmo nome canônico, mas nomes binários distintos . Nenhum nome é suficiente para deduzir o outro com segurança: se você possui o nome canônico, não sabe quais partes do nome são pacotes e quais contêm classes. Se você possui o nome binário, não sabe quais
$
foram introduzidos como separadores e quais faziam parte de algum nome simples. (O arquivo de classe armazena o nome binário da própria classe e sua classe anexa , o que permite que o tempo de execução faça essa distinção .)Classes anônimas e classes locais não têm nomes totalmente qualificados, mas ainda têm um nome binário . O mesmo vale para as classes aninhadas dentro dessas classes. Toda classe tem um nome binário.
Correndo
javap -v -private
sobrea/b/C.class
mostra que o código de bytes refere-se ao tipo ded
comoLa/b/C$D;
e que da matrizds
como[La/b/C$D;
. Eles são chamados de descritores e são especificados na seção 4.3 do JVMS .O nome da classe
a/b/C$D
usado em ambos os descritores é o que você obtém substituindo.
por/
no nome binário. A especificação da JVM aparentemente chama isso de forma interna do nome binário . A seção 4.2.1 da JVMS a descreve e afirma que a diferença do nome binário ocorreu por razões históricas.O nome do arquivo de uma classe em um dos carregadores de classes típicos baseados em nome de arquivo é o que você obtém se interpretar o
/
formulário interno do nome binário como um separador de diretório e anexar a extensão do nome do arquivo.class
. É resolvido em relação ao caminho da classe usado pelo carregador de classes em questão.fonte
este é o melhor documento que encontrei descrevendo 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/
fonte
É interessante notar que
getCanonicalName()
egetSimpleName()
pode aumentarInternalError
quando o nome da classe está incorreto. Isso acontece para algumas linguagens JVM não Java, por exemplo, Scala.Considere o seguinte (Scala 2.11 no Java 8):
Isso pode ser um problema para ambientes de linguagem mista ou ambientes que carregam dinamicamente bytecode, por exemplo, servidores de aplicativos e outro software de plataforma.
fonte
getName () - retorna o nome da entidade (classe, interface, classe de matriz, tipo primitivo ou nulo) representada por esse objeto de classe, como uma String.
getCanonicalName () - retorna o nome canônico da classe subjacente, conforme definido pela Java Language Specification.
getSimpleName () - retorna o nome simples da classe subjacente, que é o nome que ele recebeu no código-fonte.
Uma diferença é que, se você usar uma classe anônima, poderá obter um valor nulo ao tentar obter o nome da classe usando o método
getCanonicalName()
Outro fato é que o
getName()
método se comporta de maneira diferente dogetCanonicalName()
método para classes internas .getName()
usa um dólar como separador entre o nome canônico da classe envolvente e o nome simples da classe interna.Para saber mais sobre como recuperar um nome de classe em Java .
fonte
fonte
Class<StringBuffer> clazz = StringBuffer.class