ความแตกต่างระหว่างชื่อมาตรฐานชื่อสามัญและชื่อคลาสใน Java Class คืออะไร


973

ใน Java ความแตกต่างระหว่างสิ่งเหล่านี้คืออะไร:

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

ฉันได้ตรวจสอบ Javadoc หลายครั้งและสิ่งนี้ก็ไม่เคยอธิบายได้ดีนัก ฉันทำการทดสอบด้วยและนั่นก็ไม่ได้สะท้อนความหมายที่แท้จริงที่อยู่เบื้องหลังวิธีการที่เรียกว่าวิธีการเหล่านี้



218
ฉันคิดว่านี่เป็นคำถามที่สมเหตุสมผล javadoc ทำงานได้ไม่ดีในการอธิบายความแตกต่างระหว่างทั้งสาม
Graham Borland

1
ดู - docs.oracle.com/javase/6/docs/api/java/lang/Class.htmlหรืออาจจะแค่เขียนแบบทดสอบ
Nick Holt

7
@GrahamBorland javadoc พูดว่า"ตามที่กำหนดโดยข้อกำหนดภาษา Java" - เพื่อให้คุณสามารถค้นหาได้ในเอกสารนั้น เพียงเพราะมันไม่ใช่ลิงก์แบบคลิกได้ผู้คนยังสามารถใช้ความพยายามเพียงเล็กน้อยและคลิกที่ผลลัพธ์การค้นหาครั้งแรก
vbence

66
@vbence: คนส่วนใหญ่ค่อนข้างจะทำสิ่งต่าง ๆ ได้ดีกว่าค้นหา JLS สำหรับสิ่งเล็กน้อยเช่นนี้ ดังนั้นนี่เป็นผลการค้นหาครั้งแรกของ Google :)
pathikrit

คำตอบ:


1130

หากคุณไม่แน่ใจเกี่ยวกับบางสิ่งลองเขียนการทดสอบก่อน

ฉันทำอย่างนี้:

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 (ดั้งเดิม):
    getName (): int
    getCanonicalName (): int
    getSimpleName (): int
    getTypeName (): int

สตริง. คลาส (คลาสปกติ):
    getName (): java.lang.String
    getCanonicalName (): java.lang.String
    getSimpleName (): String
    getTypeName (): java.lang.String

java.util.HashMap.SimpleEntry.class (คลาสที่ซ้อนกัน):
    getName (): java.util.AbstractMap $ SimpleEntry
    getCanonicalName (): java.util.AbstractMap.SimpleEntry
    getSimpleName (): SimpleEntry
    getTypeName (): java.util.AbstractMap $ SimpleEntry

ใหม่ java.io.Serializable () {}. getClass () (คลาสภายในที่ไม่ระบุชื่อ):
    getName (): ClassNameTest $ 1
    getCanonicalName (): null
    getSimpleName ():    
    getTypeName (): ClassNameTest $ 1

มีรายการว่างในบล็อกสุดท้ายที่getSimpleNameส่งคืนสตริงว่าง

ผลที่สุดคือ:

  • ชื่อเป็นชื่อที่คุณต้องการใช้ในการโหลดแบบไดนามิกระดับด้วยตัวอย่างเช่นการเรียกร้องให้มีการเริ่มต้นClass.forName ClassLoaderภายในขอบเขตของClassLoaderคลาสที่แน่นอนทุกชั้นจะมีชื่อเฉพาะ
  • ชื่อบัญญัติเป็นชื่อที่จะใช้ในงบนำเข้า อาจเป็นประโยชน์ในระหว่างtoStringการดำเนินการหรือการบันทึก เมื่อjavacคอมไพเลอร์มีมุมมองที่สมบูรณ์ของ classpath มันจะบังคับให้มีชื่อที่ไม่ซ้ำกันของชื่อแคนนิคัลภายในโดยการปะทะคลาสที่มีคุณสมบัติครบถ้วนและชื่อแพ็คเกจในเวลารวบรวม อย่างไรก็ตาม JVMs ClassLoaderต้องยอมรับการปะทะกันชื่อดังกล่าวและมาตรฐานชื่อจึงไม่ซ้ำกันเรียนระบุภายใน (ใน hindsight, ชื่อที่ดีกว่าสำหรับผู้ทะเยอทะยานนี้จะได้รับgetJavaName; แต่วิธีนี้วันที่จากเวลาที่ JVM ถูกใช้เพียงเพื่อเรียกใช้โปรแกรม Java)
  • ชื่อง่ายหลวมระบุชั้นเรียนอีกครั้งอาจจะมีประโยชน์ในระหว่างการtoStringหรือการดำเนินการเข้าสู่ระบบได้ แต่ไม่รับประกันจะไม่ซ้ำกัน
  • ชื่อประเภทผลตอบแทน "สตริงข้อมูลสำหรับชื่อของประเภทนี้" "มันเหมือน toString (): มันเป็นข้อมูลหมดจดและมีค่าไม่มีสัญญา" (เขียนโดย sir4ur0n)

5
คุณคิดว่าจำเป็นต้องมีอะไรพิเศษ
Nick Holt

2
@AnupamSaini ใช่ การมีชื่อแพ็คเกจดังกล่าวในแอปพลิเคชันจริงจะบ้า
Jayen

3
อย่างไรก็ตามมันเป็นบ้า แต่เป็นข้อสันนิษฐานที่ทำให้นักแสดงที่เป็นอันตรายสามารถทำงานได้ มีคนพูดว่า "โอ้เรารู้ว่าคลาสจะไม่เริ่มต้นด้วยตัวพิมพ์เล็ก / แพ็คเกจจะไม่เริ่มต้นด้วยตัวพิมพ์ใหญ่" ได้รับนักแสดงที่เป็นอันตรายซึ่งสามารถเข้าถึงตัวโหลดคลาสของคุณสามารถทำสิ่งที่น่ากลัวอยู่แล้วดังนั้นจึงอาจไม่ใช่สมมติฐานที่แย่มาก
corsiKa

2
@PieterDeBie เป็นไงบ้าง? สิ่งที่คุณต้องรู้คือชื่อวิธีที่คุณต้องการทดสอบ
fool4jesus

20
Java 8 เพิ่ม getTypeName () และ ... สนใจที่จะอัปเดต
Theodore Murdock

90

การเพิ่มคลาสท้องถิ่น, lambdas และtoString()เมธอดเพื่อทำสองคำตอบก่อนหน้าให้สมบูรณ์ นอกจากนี้ฉันยังเพิ่มอาร์เรย์ของ lambdas และอาร์เรย์ของคลาสที่ไม่ระบุชื่อ (ซึ่งไม่สมเหตุสมผลในทางปฏิบัติแม้ว่า):

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 {}

นี่คือผลลัพธ์เต็มรูปแบบ:

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;

ดังนั้นนี่คือกฎ ก่อนอื่นให้เริ่มด้วยประเภทดั้งเดิมและvoid:

  1. หากคลาสอ็อบเจ็กต์แสดงถึงชนิดดั้งเดิมหรือvoidทั้งสี่เมธอดจะส่งคืนชื่อ

ตอนนี้กฎสำหรับgetName()วิธีการ:

  1. ทุกคลาสที่ไม่ใช่แลมบ์ดาและไม่ใช่อาเรย์หรืออินเทอร์เฟซ (เช่นระดับบนสุดซ้อนกันภายในท้องถิ่นและไม่ระบุชื่อ) มีชื่อ (ซึ่งถูกส่งกลับโดยgetName()) นั่นคือชื่อแพคเกจตามด้วยจุด (ถ้ามีแพคเกจ ) ตามด้วยชื่อของไฟล์คลาสตามที่สร้างโดยคอมไพเลอร์ (โดยไม่มีคำต่อท้าย.class) หากไม่มีแพ็คเกจมันเป็นเพียงชื่อของไฟล์คลาส ถ้าคลาสนั้นเป็นชั้นใน, ซ้อนกัน, ภายในหรือไม่ระบุชื่อคอมไพเลอร์ควรสร้างอย่างน้อยหนึ่ง$ในชื่อไฟล์คลาส โปรดทราบว่าสำหรับคลาสที่ไม่ระบุชื่อชื่อคลาสจะลงท้ายด้วยเครื่องหมายดอลลาร์ตามด้วยตัวเลข
  2. โดยทั่วไปชื่อคลาสแลมบ์ดาไม่สามารถคาดเดาได้และคุณไม่ควรสนใจชื่อเหล่านั้น แน่นอนชื่อของพวกเขาคือชื่อของคลาสที่ปิดล้อมตามด้วย$$Lambda$ตามด้วยหมายเลขตามด้วยเครื่องหมายทับแล้วตามด้วยหมายเลขอื่น
  3. อธิบายระดับของวิทยาการที่มีZสำหรับboolean, Bสำหรับbyte, Sสำหรับshort, Cสำหรับchar, Iสำหรับint, Jสำหรับlong, FสำหรับfloatและสำหรับD doubleสำหรับการเรียนไม่ใช่อาร์เรย์และอินเตอร์เฟซให้คำอธิบายถึงชั้นจะLตามมาด้วยสิ่งที่จะได้รับโดยตามด้วยgetName() ;สำหรับคลาสอาเรย์คลาส descriptor นั้น[ตามมาด้วยคลาส descriptor ของชนิดคอมโพเนนต์ (ซึ่งอาจเป็นคลาสอาเรย์ตัวอื่น)
  4. สำหรับคลาส Array getName()เมธอดจะส่งคืนคลาส descriptor กฎนี้ดูเหมือนว่าจะล้มเหลวเฉพาะสำหรับคลาสอาเรย์ที่มีประเภทองค์ประกอบเป็นแลมบ์ดา (ซึ่งอาจเป็นบั๊ก) แต่หวังว่าสิ่งนี้จะไม่สำคัญต่อไปเพราะไม่มีจุดใดเลยแม้แต่ในการมีอยู่ของคลาสอาเรย์

ตอนนี้toString()วิธีการ:

  1. ถ้าเช่นชั้นหมายถึงอินเตอร์เฟซ (หรือคำอธิบายประกอบซึ่งเป็นชนิดพิเศษของอินเตอร์เฟซ) ซึ่งเป็นผลตอบแทนtoString() ถ้าเป็นแบบดั้งเดิมก็จะส่งกลับเพียง"interface " + getName() getName()ถ้ามันเป็นอย่างอื่น (ประเภทชั้นถึงแม้ว่ามันจะเป็นที่แปลกสวยหนึ่ง) "class " + getName()ก็จะส่งกลับ

getCanonicalName()วิธีการ:

  1. สำหรับคลาสและอินเตอร์เฟสระดับสูงสุดgetCanonicalName()เมธอดจะส่งคืนสิ่งที่getName()เมธอดส่งคืน
  2. getCanonicalName()วิธีการผลตอบแทนที่nullไม่ระบุชื่อหรือเรียนในท้องถิ่นและสำหรับการเรียนอาร์เรย์ของคนเหล่านั้น
  3. สำหรับคลาสและอินเทอร์เฟซภายในและอินเทอร์เฟซgetCanonicalName()วิธีการส่งกลับสิ่งที่getName()วิธีการจะแทนที่สัญญาณดอลลาร์แนะนำคอมไพเลอร์โดยจุด
  4. สำหรับการเรียนอาร์เรย์ที่getCanonicalName()วิธีการส่งกลับถ้าชื่อบัญญัติของชนิดเป็นส่วนประกอบnull มิฉะนั้นก็จะส่งกลับชื่อบัญญัติประเภทองค์ประกอบตามnull[]

getSimpleName()วิธีการ:

  1. สำหรับคลาสระดับบนสุดซ้อนกันภายในและภายในgetSimpleName()จะส่งคืนชื่อของคลาสตามที่เขียนในไฟล์ต้นฉบับ
  2. สำหรับการเรียนที่ไม่ระบุชื่อส่งกลับว่างเปล่าgetSimpleName()String
  3. สำหรับคลาสแลมบ์ดาgetSimpleName()เพียงแค่คืนค่าที่getName()จะให้โดยไม่มีชื่อแพ็กเกจ สิ่งนี้ไม่สมเหตุสมผลและดูเหมือนว่าเป็นข้อบกพร่องสำหรับฉัน แต่ไม่มีจุดเริ่มต้นในการเรียกgetSimpleName()คลาสแลมบ์ดา
  4. สำหรับการเรียนอาร์เรย์วิธีการผลตอบแทนที่เรียบง่ายของชื่อชั้นองค์ประกอบตามมาด้วยgetSimpleName() []สิ่งนี้มีผลข้างเคียงตลก / แปลก ๆ ที่คลาสอาเรย์ที่มีชนิดส่วนประกอบเป็นคลาสแบบไม่ระบุชื่อมี[]ชื่อแบบง่าย ๆ

2
… replacing the dollar-signs by dots: มีเพียงสัญลักษณ์ดอลลาร์ที่ถูกนำมาใช้เป็นตัวคั่นเท่านั้นที่จะถูกแทนที่ คุณสามารถมีดอลลาร์เป็นส่วนหนึ่งของชื่อง่ายๆและพวกเขาจะยังคงอยู่ในสถานที่
MvG

ไม่นะ! เป็นส่วนหนึ่งของชื่อคลาส! ฉันกำลังพัฒนาหม้อแปลงไฟฟ้าสำหรับชั้นเรียนและฉันคิดว่า '/' จะเป็นตัวคั่นที่ปลอดภัยระหว่างชั้นเรียนและชื่อแพ็คเกจ: /
José Roberto AraújoJúnior

81

นอกเหนือจากการสังเกตของ Nick Holt ฉันวิ่งไปสองสามกรณีสำหรับArrayชนิดข้อมูล:

//primitive Array
int demo[] = new int[5];
Class<? extends int[]> clzz = demo.getClass();
System.out.println(clzz.getName());
System.out.println(clzz.getCanonicalName());
System.out.println(clzz.getSimpleName());       

System.out.println();


//Object Array
Integer demo[] = new Integer[5]; 
Class<? extends Integer[]> clzz = demo.getClass();
System.out.println(clzz.getName());
System.out.println(clzz.getCanonicalName());
System.out.println(clzz.getSimpleName());

ตัวอย่างโค้ดข้างต้นจะพิมพ์:

[I
int[]
int[]

[Ljava.lang.Integer;
java.lang.Integer[]
Integer[]

28
ฉันจะไม่ดีไปกว่าการเสนอการแก้ไขคำตอบข้างต้น
LoKi

17

ฉันสับสนกับแผนการตั้งชื่อที่หลากหลายเช่นกันและเพิ่งจะถามและตอบคำถามของฉันเองเมื่อพบคำถามนี้ที่นี่ ฉันคิดว่าสิ่งที่ฉันค้นพบเหมาะสมพอและเสริมสิ่งที่มีอยู่แล้วที่นี่ ฉันมุ่งเน้นที่จะมองหาเอกสารเกี่ยวกับคำศัพท์ต่างๆและเพิ่มคำศัพท์ที่เกี่ยวข้องเพิ่มเติมที่อาจครอบตัดในที่อื่น ๆ

ลองพิจารณาตัวอย่างต่อไปนี้:

package a.b;
class C {
  static class D extends C {
  }
  D d;
  D[] ds;
}
  • ชื่อที่เรียบง่ายของการมีD Dนั่นเป็นเพียงส่วนที่คุณเขียนเมื่อประกาศชั้นเรียน คลาสที่ไม่ระบุชื่อไม่มีชื่อแบบง่าย Class.getSimpleName()ส่งคืนชื่อนี้หรือสตริงว่าง เป็นไปได้สำหรับชื่อแบบง่ายที่จะมี a $ถ้าคุณเขียนมันเช่นนี้เนื่องจาก$เป็นส่วนที่ถูกต้องของตัวระบุตามJLS ส่วน 3.8 (แม้ว่ามันจะค่อนข้างท้อใจก็ตาม)

  • ตามส่วน JLS 6.7ทั้งสองa.b.C.Dและa.b.C.D.D.Dจะเป็นชื่อที่มีคุณสมบัติครบถ้วนแต่a.b.C.Dจะเป็นชื่อที่ยอมรับDของ ดังนั้นชื่อมาตรฐานทุกชื่อจึงเป็นชื่อที่มีคุณสมบัติครบถ้วน แต่การสนทนาไม่เป็นความจริงเสมอไป จะกลับชื่อบัญญัติหรือClass.getCanonicalName()null

  • Class.getName()เป็นเอกสารที่จะกลับมาชื่อไบนารีตามที่ระบุในJLS ส่วน 13.1 ในกรณีนี้ก็จะส่งกลับa.b.C$DสำหรับDและสำหรับ[La.b.C$D;D[]

  • คำตอบนี้แสดงให้เห็นว่ามันเป็นไปได้สำหรับสองชั้นโหลดโดยรถตักดินชั้นเดียวกันจะมีเหมือนกันชื่อบัญญัติแต่แตกต่างชื่อไบนารี ชื่อไม่เพียงพอที่จะอนุมานอีกชื่อที่เชื่อถือได้: ถ้าคุณมีชื่อมาตรฐานคุณไม่ทราบว่าส่วนใดของชื่อที่เป็นแพ็คเกจและบรรจุชั้นเรียน หากคุณมีชื่อไบนารีคุณจะไม่ทราบว่าชื่อใด$ถูกนำมาใช้เป็นตัวคั่นและเป็นส่วนหนึ่งของชื่อง่ายๆ (ไฟล์คลาสเก็บชื่อไบนารีของคลาสเองและคลาสที่ล้อมรอบซึ่งช่วยให้รันไทม์สามารถแยกความแตกต่างนี้ได้)

  • ชั้นเรียนที่ไม่ระบุชื่อและชั้นเรียนในท้องถิ่นไม่มีชื่อที่มีคุณสมบัติครบถ้วนแต่ยังคงมีชื่อไบนารี ที่เก็บเดียวกันสำหรับคลาสที่ซ้อนภายในคลาสดังกล่าว ทุกชั้นมีชื่อไบนารี

  • ทำงานjavap -v -privateเกี่ยวกับการa/b/C.classแสดงให้เห็นว่า bytecode หมายถึงประเภทของdเป็นLa/b/C$D;และที่ของอาร์เรย์เป็นds [La/b/C$D;เหล่านี้เรียกว่าอธิบายและพวกเขาจะระบุไว้ในJVMs ส่วน 4.3

  • ชื่อคลาสที่a/b/C$Dใช้ในตัวให้คำอธิบายทั้งสองนี้คือสิ่งที่คุณได้รับโดยแทนที่.ด้วย/ในชื่อไบนารี ข้อมูลจำเพาะ JVM เห็นได้ชัดว่านี้เรียกว่ารูปแบบภายในของชื่อไบนารี JVMS ส่วน 4.2.1อธิบายและระบุว่าความแตกต่างจากชื่อไบนารีนั้นใช้เพื่อเหตุผลทางประวัติศาสตร์

  • ชื่อไฟล์ของชั้นในหนึ่งในชื่อไฟล์ทั่วไปที่ใช้รถตักชั้นเรียนคือสิ่งที่คุณจะได้รับถ้าคุณตีความ/ในรูปแบบภายในของชื่อไบนารีเป็นตัวคั่นไดเรกทอรีและผนวกนามสกุลของแฟ้ม.classไป มันได้รับการแก้ไขเมื่อเทียบกับเส้นทางคลาสที่ใช้โดยคลาสโหลดเดอร์ที่มีปัญหา


3
นี่ควรเป็นคำตอบที่ได้รับการยอมรับเนื่องจากเป็นคำตอบเดียวที่อ้างอิง JLS และใช้คำศัพท์ที่เหมาะสม
John

10

นี่คือเอกสารที่ดีที่สุดที่ฉันพบอธิบาย 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/

// Primitive type
int.class.getName();          // -> int
int.class.getCanonicalName(); // -> int
int.class.getSimpleName();    // -> int

// Standard class
Integer.class.getName();          // -> java.lang.Integer
Integer.class.getCanonicalName(); // -> java.lang.Integer
Integer.class.getSimpleName();    // -> Integer

// Inner class
Map.Entry.class.getName();          // -> java.util.Map$Entry
Map.Entry.class.getCanonicalName(); // -> java.util.Map.Entry
Map.Entry.class.getSimpleName();    // -> Entry     

// Anonymous inner class
Class<?> anonymousInnerClass = new Cloneable() {}.getClass();
anonymousInnerClass.getName();          // -> somepackage.SomeClass$1
anonymousInnerClass.getCanonicalName(); // -> null
anonymousInnerClass.getSimpleName();    // -> // An empty string

// Array of primitives
Class<?> primitiveArrayClass = new int[0].getClass();
primitiveArrayClass.getName();          // -> [I
primitiveArrayClass.getCanonicalName(); // -> int[]
primitiveArrayClass.getSimpleName();    // -> int[]

// Array of objects
Class<?> objectArrayClass = new Integer[0].getClass();
objectArrayClass.getName();          // -> [Ljava.lang.Integer;
objectArrayClass.getCanonicalName(); // -> java.lang.Integer[]
objectArrayClass.getSimpleName();    // -> Integer[]

3

เป็นที่น่าสนใจที่จะทราบว่าgetCanonicalName()และgetSimpleName()สามารถเพิ่มขึ้นได้InternalErrorเมื่อชื่อคลาสมีรูปแบบไม่ถูกต้อง สิ่งนี้เกิดขึ้นสำหรับภาษาที่ไม่ใช่ Java JVM เช่น Scala

พิจารณาสิ่งต่อไปนี้ (Scala 2.11 บน Java 8):

scala> case class C()
defined class C

scala> val c = C()
c: C = C()

scala> c.getClass.getSimpleName
java.lang.InternalError: Malformed class name
  at java.lang.Class.getSimpleName(Class.java:1330)
  ... 32 elided

scala> c.getClass.getCanonicalName
java.lang.InternalError: Malformed class name
  at java.lang.Class.getSimpleName(Class.java:1330)
  at java.lang.Class.getCanonicalName(Class.java:1399)
  ... 32 elided

scala> c.getClass.getName
res2: String = C

สิ่งนี้อาจเป็นปัญหาสำหรับสภาพแวดล้อมภาษาผสมหรือสภาพแวดล้อมที่โหลดไบต์แบบไดนามิกเช่นแอพเซิร์ฟเวอร์และซอฟต์แวร์แพลตฟอร์มอื่น ๆ


1
    public void printReflectionClassNames(){
    StringBuffer buffer = new StringBuffer();
    Class clazz= buffer.getClass();
    System.out.println("Reflection on String Buffer Class");
    System.out.println("Name: "+clazz.getName());
    System.out.println("Simple Name: "+clazz.getSimpleName());
    System.out.println("Canonical Name: "+clazz.getCanonicalName());
    System.out.println("Type Name: "+clazz.getTypeName());
}

outputs:
Reflection on String Buffer Class
Name: java.lang.StringBuffer
Simple Name: StringBuffer
Canonical Name: java.lang.StringBuffer
Type Name: java.lang.StringBuffer

1
สองบรรทัดแรกในวิธีนี้สามารถลดลงได้Class<StringBuffer> clazz = StringBuffer.class
ThePyroEagle

1

getName () - ส่งคืนชื่อของเอนทิตี (คลาสอินเทอร์เฟซคลาสอาร์เรย์ชนิดดั้งเดิมหรือโมฆะ) ที่แสดงโดยวัตถุคลาสนี้เป็นสตริง

getCanonicalName () - ส่งคืนชื่อมาตรฐานของคลาสพื้นฐานตามที่กำหนดโดย Java Language Specification

getSimpleName () - ส่งคืนชื่อแบบง่ายของคลาสที่อยู่ภายใต้นั่นคือชื่อที่ได้รับในซอร์สโค้ด

package com.practice;

public class ClassName {
public static void main(String[] args) {

  ClassName c = new ClassName();
  Class cls = c.getClass();

  // returns the canonical name of the underlying class if it exists
  System.out.println("Class = " + cls.getCanonicalName());    //Class = com.practice.ClassName
  System.out.println("Class = " + cls.getName());             //Class = com.practice.ClassName
  System.out.println("Class = " + cls.getSimpleName());       //Class = ClassName
  System.out.println("Class = " + Map.Entry.class.getName());             // -> Class = java.util.Map$Entry
  System.out.println("Class = " + Map.Entry.class.getCanonicalName());    // -> Class = java.util.Map.Entry
  System.out.println("Class = " + Map.Entry.class.getSimpleName());       // -> Class = Entry 
  }
}

ข้อแตกต่างอย่างหนึ่งคือถ้าคุณใช้คลาสที่ไม่ระบุชื่อคุณสามารถรับค่า Null เมื่อพยายามรับชื่อของคลาสโดยใช้getCanonicalName()

ความเป็นจริงก็คือว่าgetName()วิธีการทำงานแตกต่างกันกว่าgetCanonicalName()วิธีการเรียนภายใน getName()ใช้ดอลล่าร์เป็นตัวคั่นระหว่างชื่อแคนนิคอลของคลาสที่ปิดล้อมและชื่อแบบง่ายของคลาสภายใน

หากต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับการเรียกชื่อชั้นในชวา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.