1. ホーム
  2. java

[解決済み] Javaクラスにおけるcanonical name、simple name、class nameの違いは何ですか?

2022-03-19 09:35:16

質問

Javaでは、これらの違いは何ですか。

Object o1 = ....
o1.getClass().getSimpleName();
o1.getClass().getName();
o1.getClass().getCanonicalName();

何度もJavadocを確認したのに、これでは決してうまく説明できない。 また、テストを実行しましたが、これらのメソッドが呼び出される方法の背後にある本当の意味は反映されませんでした。

解決するには?

何かわからないことがあったら、まずテストを書いてみてください。

私はこうしました。

class ClassNameTest {
    public static void main(final String... arguments) {
        printNamesForClass(
            int.class,
            "int.class (primitive)");
        printNamesForClass(
            String.class,
            "String.class (ordinary class)");
        printNamesForClass(
            java.util.HashMap.SimpleEntry.class,
            "java.util.HashMap.SimpleEntry.class (nested class)");
        printNamesForClass(
            new java.io.Serializable(){}.getClass(),
            "new java.io.Serializable(){}.getClass() (anonymous inner class)");
    }

    private static void printNamesForClass(final Class<?> clazz, final String label) {
        System.out.println(label + ":");
        System.out.println("    getName():          " + clazz.getName());
        System.out.println("    getCanonicalName(): " + clazz.getCanonicalName());
        System.out.println("    getSimpleName():    " + clazz.getSimpleName());
        System.out.println("    getTypeName():      " + clazz.getTypeName()); // added in Java 8
        System.out.println();
    }
}

プリントする。

int.class (primitive):
    getName():          int
    getCanonicalName(): int
    getSimpleName():    int
    getTypeName():      int

String.class (ordinary class):
    getName():          java.lang.String
    getCanonicalName(): java.lang.String
    getSimpleName():    String
    getTypeName():      java.lang.String

java.util.HashMap.SimpleEntry.class (nested class):
    getName():          java.util.AbstractMap$SimpleEntry
    getCanonicalName(): java.util.AbstractMap.SimpleEntry
    getSimpleName():    SimpleEntry
    getTypeName():      java.util.AbstractMap$SimpleEntry

new java.io.Serializable(){}.getClass() (anonymous inner class):
    getName():          ClassNameTest$1
    getCanonicalName(): null
    getSimpleName():    
    getTypeName():      ClassNameTest$1

最後のブロックには空のエントリがあり、ここで getSimpleName は空の文字列を返します。

これを見たアップショットは

  • その 名前 は、クラスを動的に読み込むために使用する名前で、例えば、以下のように呼び出します。 Class.forName で、デフォルトの ClassLoader . の範囲内で、ある ClassLoader は、すべてのクラスが一意な名前を持つ。
  • その 正規名 はimport文の中で使われる名前です。これは toString またはロギング操作。このとき javac コンパイラはクラスパスを完全に把握しており、コンパイル時に完全修飾クラス名とパッケージ名を衝突させることで、クラスパス内の標準的な名前の一意性を強制しています。しかし、JVMはこのような名前の衝突を受け入れなければならないため、標準的な名前では、クラスパス内のクラスを一意に識別できません。 ClassLoader . (今にして思えば、このゲッターのより良い名称は getJavaName しかし、このメソッドは、JVMがJavaプログラムを実行するためだけに使用されていた時代から存在しています)。
  • その 単純な名前 はクラスを大まかに識別します。 toString やロギング操作を行うことができますが、一意であることは保証されません。
  • その 型名 は、"この型の名前を表す情報文字列を返します" のようなものです。 toString これは純粋に情報提供であり、契約上の価値を持ちません" 。(sir4ur0nの記述による)

また、この種の技術的なJava APIの詳細については、一般的にJava Language Specificationのドキュメントを参照することができます。

<ブロッククオート

Example 6.7-2.Example 6.7-2. を超える Fully Qualified NamesFully Qualified Names v. Canonical Name それぞれ