В Java, в чем разница между ними:
Object o1 = ....
o1.getClass().getSimpleName();
o1.getClass().getName();
o1.getClass().getCanonicalName();
Я проверял Javadoc несколько раз, но это никогда не объясняет это хорошо. Я также провел тест, и это не отражало никакого реального смысла в том, как эти методы вызываются.
Ответы:
Если вы не уверены в чем-то, попробуйте сначала написать тест.
Я сделал это:
Печать:
В последнем блоке есть пустая запись, которая
getSimpleName
возвращает пустую строку.Результат, глядя на это:
Class.forName
с по умолчаниюClassLoader
. В рамках определенногоClassLoader
, все классы имеют уникальные имена.toString
или при ведении журнала. Когдаjavac
компилятор имеет полное представление о пути к классам, он обеспечивает уникальность канонических имен в нем, конфликтуя полностью определенные имена классов и пакетов во время компиляции. Однако JVM должны принимать такие конфликты имен, и, таким образом, канонические имена не уникально идентифицируют классы вClassLoader
. (Оглядываясь назад, можно было бы назвать это имя лучше,getJavaName
но этот метод датируется тем временем, когда JVM использовалась исключительно для запуска программ на Java.)toString
или лесозаготовительных операций , но не гарантировано быть уникальным.источник
Добавление локальных классов, лямбд и
toString()
метода для завершения двух предыдущих ответов. Кроме того, я добавляю массивы лямбд и массивы анонимных классов (которые на практике не имеют никакого смысла):Это полный вывод:
Итак, вот правила. Во-первых, давайте начнем с примитивных типов и
void
:void
, все четыре метода просто возвращают его имя.Теперь правила для
getName()
метода:getName()
), которое является именем пакета, за которым следует точка (если есть пакет) ), за которым следует имя его файла классов, сгенерированного компилятором (без суффикса.class
). Если пакета нет, это просто имя файла класса. Если класс является внутренним, вложенным, локальным или анонимным классом, компилятор должен сгенерировать хотя бы один$
в своем имени файла класса. Обратите внимание, что для анонимных классов имя класса заканчивается знаком доллара, за которым следует число.$$Lambda$
следует число, за которым следует косая черта, а затем еще одно число.Z
дляboolean
,B
дляbyte
,S
дляshort
,C
дляchar
,I
дляint
,J
дляlong
,F
дляfloat
иD
дляdouble
. Для классов и интерфейсов, не являющихся массивами, за дескриптором классаL
следует то, что дано,getName()
а затем;
. Для классов массива за дескриптором класса следует дескриптор[
класса типа компонента (который сам может быть другим классом массива).getName()
метод возвращает свой дескриптор класса. Это правило не работает только для классов массива, чей тип компонента является лямбда-выражением (что, возможно, является ошибкой), но, надеюсь, это не должно иметь значения в любом случае, потому что нет никакого смысла даже в существовании классов-массивов, чей тип компонента является лямбда-выражением.Теперь
toString()
метод:toString()
возвращается"interface " + getName()
. Если это примитив, он просто возвращаетсяgetName()
. Если это что-то еще (тип класса, даже если он довольно странный), он возвращается"class " + getName()
.getCanonicalName()
Метод:getCanonicalName()
метод возвращает только то, чтоgetName()
возвращает метод.getCanonicalName()
методе возвращаетnull
для анонимных или локальных классов и для классов массива из них.getCanonicalName()
метод возвращает то, чтоgetName()
метод заменял бы введенные компилятором знаки доллара точками.getCanonicalName()
метод возвращает,null
если каноническое имя типа компонента равноnull
. В противном случае он возвращает каноническое имя типа компонента, за которым следует[]
.getSimpleName()
Метод:getSimpleName()
возвращает имя класса, записанное в исходном файле.getSimpleName()
возвращается пустойString
.getSimpleName()
просто возвращает то,getName()
что возвращает без имени пакета. Это не имеет особого смысла и выглядит для меня как ошибка, но нет смысла вызыватьgetSimpleName()
лямбда-класс для начала.getSimpleName()
метод возвращает простое имя класса компонента, за которым следует[]
. У этого есть забавный / странный побочный эффект, что классы массива, тип компонента которых является анонимным классом, имеют так же,[]
как их простые имена.источник
… replacing the dollar-signs by dots
: Заменяются только знаки доллара, которые были введены в качестве разделителей. Вы можете иметь доллары как часть простого имени, и они останутся на месте.В дополнение к наблюдениям Ника Холта, я провел несколько случаев для
Array
типа данных:Вышеупомянутые фрагменты кода:
источник
Я также был озадачен широким спектром различных схем именования и собирался задать свой вопрос и ответить на него, когда нашел этот вопрос здесь. Я думаю, что мои выводы соответствуют этому достаточно хорошо, и дополняют то, что уже здесь. Я сосредоточен на поиске документации по различным терминам и добавлении некоторых связанных терминов, которые могут возникнуть в других местах.
Рассмотрим следующий пример:
Простое имя в
D
этоD
. Это та часть, которую вы написали, когда объявляли класс. У анонимных классов нет простого имени.Class.getSimpleName()
возвращает это имя или пустую строку. Простое имя может содержать a,$
если вы напишите его так, поскольку$
оно является допустимой частью идентификатора согласно разделу 3.8 JLS (даже если оно несколько не рекомендуется).Согласно разделу JLS 6.7 , как
a.b.C.D
иa.b.C.D.D.D
было бы полностью квалифицированные имена , но толькоa.b.C.D
бы быть каноническим именем изD
. Таким образом, каждое каноническое имя является полностью определенным именем, но обратное не всегда верно.Class.getCanonicalName()
вернет каноническое имя илиnull
.Class.getName()
задокументировано возвращение двоичного имени , как указано в разделе 13.1 JLS . В этом случае он возвращаетсяa.b.C$D
дляD
и[La.b.C$D;
дляD[]
.Этот ответ демонстрирует, что два класса, загруженные одним и тем же загрузчиком классов, могут иметь одинаковое каноническое имя, но разные двоичные имена . Ни одно из имен не достаточно для надежного вывода другого: если у вас есть каноническое имя, вы не знаете, какие части имени являются пакетами, а какие содержат классы. Если у вас есть двоичное имя, вы не знаете, какие
$
были введены как разделители, а какие были частью какого-то простого имени. (Файл класса хранит двоичное имя самого класса и включающего его класса , что позволяет среде выполнения сделать это различие .)Анонимные классы и локальные классы не имеют полностью определенных имен, но все еще имеют двоичное имя . То же самое относится к классам, вложенным в такие классы. Каждый класс имеет двоичное имя.
Запуск
javap -v -private
наa/b/C.class
показывает, что байт-код ссылается на типd
asLa/b/C$D;
и тип массиваds
as[La/b/C$D;
. Это так называемые дескрипторы , и они указаны в разделе 4.3 JVMS .Имя класса
a/b/C$D
используется в обоих этих дескрипторов, что вы получите, заменив.
на/
в двоичном имени. Спецификация JVM, очевидно, называет это внутренней формой двоичного имени . Раздел 4.2.1 JVMS описывает это и утверждает, что отличие от двоичного имени было по историческим причинам.Имя файла класса в одном из типичных загрузчиков классов на основе имени файла - это то, что вы получаете, если вы интерпретируете
/
внутреннюю форму двоичного имени как разделитель каталогов и добавляете.class
к нему расширение имени файла . Это решено относительно пути к классу, используемого рассматриваемым загрузчиком классов.источник
это лучший документ, который я нашел, описывающий 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/
источник
Интересно отметить, что
getCanonicalName()
иgetSimpleName()
может повышаться,InternalError
когда имя класса искажено. Это происходит для некоторых не Java-языков JVM, например, Scala.Рассмотрим следующее (Scala 2.11 на Java 8):
Это может быть проблемой для смешанных языковых сред или сред, которые динамически загружают байт-код, например, для серверов приложений и другого программного обеспечения платформы.
источник
getName () - возвращает имя объекта (класс, интерфейс, класс массива, тип примитива или void), представленного этим объектом класса, в виде строки.
getCanonicalName () - возвращает каноническое имя базового класса, как определено в Спецификации языка Java.
getSimpleName () - возвращает простое имя базового класса, то есть имя, которое было дано в исходном коде.
Одно из отличий состоит в том, что если вы используете анонимный класс, вы можете получить нулевое значение при попытке получить имя класса, используя
getCanonicalName()
Другой факт заключается в том, что
getName()
метод ведет себя иначе, чемgetCanonicalName()
метод для внутренних классов .getName()
использует доллар в качестве разделителя между каноническим именем включающего класса и простым именем внутреннего класса.Чтобы узнать больше о получении имени класса в Java .
источник
источник
Class<StringBuffer> clazz = StringBuffer.class