Sự khác biệt giữa tên chính tắc, tên đơn giản và tên lớp trong Lớp Java là gì?


973

Trong Java, sự khác biệt giữa những điều này là gì:

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

Tôi đã kiểm tra Javadoc nhiều lần và điều này không bao giờ giải thích rõ về nó. Tôi cũng đã chạy thử nghiệm và điều đó không phản ánh bất kỳ ý nghĩa thực sự nào đằng sau cách các phương thức này được gọi.



218
Tôi nghĩ rằng đây là một câu hỏi hợp lý. Các javadoc không làm tốt công việc giải thích sự khác biệt giữa ba.
Graham Borland

1
Xem - docs.oracle.com/javase/6/docs/api/java/lang/Class.html hoặc có thể chỉ cần viết một bài kiểm tra.
Nick Holt

7
@GrahamBorland javadoc nói "như được định nghĩa bởi Đặc tả ngôn ngữ Java" - vì vậy bạn có thể tra cứu nó trong tài liệu đó. Chỉ vì nó không phải là một liên kết có thể nhấp, mọi người vẫn có thể thực hiện một nỗ lực tối thiểu và nhấp vào kết quả của công cụ tìm kiếm đầu tiên.
vbence

66
@vbence: Hầu hết mọi người thà hoàn thành công việc hơn là tìm kiếm JLS cho những thứ tầm thường như thế này. Do đó, đây là kết quả đầu tiên của Google :)
pathikrit

Câu trả lời:


1130

Nếu bạn không chắc chắn về điều gì đó, hãy thử viết một bài kiểm tra trước.

Tôi đã làm điều này:

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();
    }
}

Bản in:

int. class (nguyên thủy):
    getName (): int
    getCanonicalName (): int
    getSimpleName (): int
    getTypeName (): int

String. Class (lớp thường):
    getName (): java.lang.String
    getCanonicalName (): java.lang.String
    getSimpleName (): Chuỗi
    getTypeName (): java.lang.String

java.util.HashMap.SimpleEntry. class (lớp lồng nhau):
    getName (): java.util.Ab tríchMap $ SimpleEntry
    getCanonicalName (): java.util.Ab tríchMap.SimpleEntry
    getSimpleName (): SimpleEntry
    getTypeName (): java.util.Ab tríchMap $ SimpleEntry

new java.io.Serializable () {}. getClass () (lớp bên trong ẩn danh):
    getName (): ClassNameTest $ 1
    getCanonicalName (): null
    getSimpleName ():    
    getTypeName (): ClassNameTest $ 1

Có một mục trống trong khối cuối cùng getSimpleNametrả về một chuỗi trống.

Kết quả cuối cùng nhìn vào đây là:

  • các tên là tên mà bạn muốn sử dụng để tự động tải các lớp với, ví dụ, một cuộc gọi đến Class.forNamevới mặc định ClassLoader. Trong phạm vi nhất định ClassLoader, tất cả các lớp có tên duy nhất.
  • các tên kinh điển là tên mà sẽ được sử dụng trong một tuyên bố nhập khẩu. Nó có thể hữu ích trong quá trình toStringhoặc đăng nhập hoạt động. Khi javactrình biên dịch có chế độ xem hoàn chỉnh của một đường dẫn lớp, nó sẽ thực thi tính duy nhất của các tên chính tắc trong nó bằng cách trộn các tên lớp và gói đủ điều kiện tại thời điểm biên dịch. Tuy nhiên, các JVM phải chấp nhận các xung đột tên như vậy và do đó các tên chính tắc không xác định duy nhất các lớp trong a ClassLoader. (Nhìn chung, một tên tốt hơn cho getter này sẽ là getJavaName; nhưng phương thức này có từ thời JVM chỉ được sử dụng để chạy các chương trình Java.)
  • các tên đơn giản lỏng lẻo xác định các lớp, một lần nữa có thể có ích trong quá trình toStringhoặc các hoạt động khai thác gỗ nhưng không đảm bảo là duy nhất.
  • các tên kiểu trả về "một chuỗi thông tin cho tên thuộc loại này", "Nó giống như toString (): nó hoàn toàn là thông tin và không có giá trị hợp đồng" (như được viết bởi sir4ur0n)

5
Bạn nghĩ thêm gì là cần thiết?
Nick Holt

2
@AnupamSaini có. Có một tên gói như vậy trong một ứng dụng thực sự sẽ là điên rồ.
Jayen

3
CNTT sẽ là điên rồ, tuy nhiên, đó là loại giả định cho phép một diễn viên độc hại làm việc. Có người nói "ồ, chúng tôi biết các lớp sẽ không bao giờ bắt đầu bằng chữ thường / gói sẽ không bao giờ bắt đầu bằng chữ hoa". Cấp, một diễn viên độc hại có quyền truy cập vào trình tải lớp của bạn có thể đã làm những điều khủng khiếp, vì vậy nó có thể không phải là một giả định hoàn toàn khủng khiếp.
corsiKa

2
@PieterDeBie Làm sao vậy? Tất cả những gì bạn cần biết là tên phương thức bạn muốn kiểm tra.
lừa4jesus

20
Java 8 đã thêm getTypeName () cũng ... quan tâm cập nhật cho điều đó?
Theodore Murdock

90

Thêm các lớp địa phương, lambdas và toString()phương pháp để hoàn thành hai câu trả lời trước. Hơn nữa, tôi thêm các mảng lambdas và mảng các lớp ẩn danh (mặc dù không có ý nghĩa gì trong thực tế):

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

Đây là đầu ra đầy đủ:

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;

Vì vậy, đây là các quy tắc. Đầu tiên, hãy bắt đầu với các kiểu nguyên thủy và void:

  1. Nếu đối tượng lớp đại diện cho một kiểu nguyên thủy hoặc void, tất cả bốn phương thức chỉ đơn giản trả về tên của nó.

Bây giờ các quy tắc cho getName() phương thức:

  1. Mỗi lớp hoặc giao diện không phải là lambda và không phải mảng (nghĩa là cấp cao nhất, lồng nhau, bên trong, cục bộ và ẩn danh) có một tên (được trả về bởi getName() ) đó là tên gói theo sau là dấu chấm (nếu có gói ), theo sau là tên của tệp lớp của nó được tạo bởi trình biên dịch (không có hậu tố .class). Nếu không có gói, nó chỉ đơn giản là tên của tệp lớp. Nếu lớp là một lớp bên trong, lồng nhau, cục bộ hoặc ẩn danh, trình biên dịch sẽ tạo ra ít nhất một $trong tên tệp lớp của nó. Lưu ý rằng đối với các lớp ẩn danh, tên lớp sẽ kết thúc bằng ký hiệu đô la theo sau là một số.
  2. Tên lớp Lambda thường không thể đoán trước và dù sao bạn cũng không nên quan tâm đến chúng. Chính xác, tên của họ là tên của lớp kèm theo, theo sau là$$Lambda$ , theo sau là một số, theo sau là dấu gạch chéo, theo sau là một số khác.
  3. Các mô tả lớp của nguyên thủy là Zcho boolean, Bcho byte, Scho short, Ccho char, Icho int, Jcho long, Fcho floatDcho double. Đối với các lớp và giao diện không phải là mảng, bộ mô tả lớp được Ltheo sau bởi những gì được cho bởi getName()theo sau bởi; . Đối với các lớp mảng, bộ mô tả lớp được [theo sau bởi bộ mô tả lớp của loại thành phần (có thể chính nó là một lớp mảng khác).
  4. Đối với các lớp mảng, getName() phương thức trả về mô tả lớp của nó. Quy tắc này dường như chỉ thất bại đối với các lớp mảng có loại thành phần là lambda (có thể là lỗi), nhưng hy vọng điều này không thành vấn đề vì dù sao cũng không có sự tồn tại của các lớp mảng có loại thành phần là lambda.

Bây giờ, toString()phương thức:

  1. Nếu cá thể lớp đại diện cho một giao diện (hoặc một chú thích, là một loại giao diện đặc biệt), thì toString()trả về "interface " + getName(). Nếu nó là một nguyên thủy, nó trở lại đơn giản getName(). Nếu nó là một cái gì đó khác (một loại lớp, ngay cả khi nó là một loại khá kỳ lạ), nó sẽ trả về "class " + getName().

Các getCanonicalName()phương pháp:

  1. Đối với các lớp và giao diện cấp cao nhất, getCanonicalName()phương thức trả về đúng những gì getName()phương thức trả về.
  2. Các getCanonicalName() trở về phương pháp nullcho vô danh hoặc các lớp học tại địa phương và cho các lớp mảng của những người.
  3. Đối với các lớp và giao diện bên trong và lồng nhau, getCanonicalName()phương thức trả về những gìgetName() phương thức sẽ thay thế các ký hiệu đô la do trình biên dịch giới thiệu bằng dấu chấm.
  4. Đối với các lớp mảng, getCanonicalName()phương thức trả về nullnếu tên chính tắc của kiểu thành phần là null. Mặt khác, nó trả về tên chính tắc của loại thành phần theo sau [].

Các getSimpleName()phương pháp:

  1. Đối với các lớp cấp cao nhất, lồng nhau, bên trong và cục bộ, getSimpleName() trả về tên của lớp như được ghi trong tệp nguồn.
  2. Đối với các lớp ẩn danh, getSimpleName()trả về một khoảng trốngString .
  3. Đối với các lớp lambda, getSimpleName()chỉ trả về những gì getName()sẽ trả về mà không có tên gói. Điều này không có nhiều ý nghĩa và có vẻ như là một lỗi đối với tôi, nhưng không có lý do gì để gọigetSimpleName() một lớp lambda để bắt đầu.
  4. Đối với các lớp mảng, getSimpleName()phương thức trả về tên đơn giản của lớp thành phần theo sau []. Điều này có tác dụng phụ buồn cười / kỳ lạ là các lớp mảng có loại thành phần là một lớp ẩn danh có []tên đơn giản như chúng.

2
… replacing the dollar-signs by dots: Chỉ các ký hiệu đô la được giới thiệu là dấu phân cách đang được thay thế. Bạn cũng có thể có đô la như một phần của một cái tên đơn giản, và những thứ đó sẽ được giữ nguyên.
MvG

Ôi không! Là một phần của tên lớp! Tôi đang phát triển một biến áp lớp và tôi nghĩ rằng '/' sẽ là một dấu phân cách an toàn giữa lớp và tên gói: /
José Roberto Araújo Júnior

81

Ngoài các quan sát của Nick Holt, tôi đã chạy một vài trường hợp cho Arraykiểu dữ liệu:

//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());

Đoạn mã trên in:

[I
int[]
int[]

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

28
Tôi sẽ tốt hơn nhiều khi đề xuất một chỉnh sửa cho câu trả lời ở trên.
LoKi

17

Tôi đã bị nhầm lẫn bởi một loạt các kế hoạch đặt tên khác nhau, và chỉ cần hỏi và trả lời câu hỏi của riêng tôi về điều này khi tôi tìm thấy câu hỏi này ở đây. Tôi nghĩ rằng những phát hiện của tôi phù hợp với nó đủ tốt, và bổ sung cho những gì đã có ở đây. Trọng tâm của tôi là tìm kiếm tài liệu về các điều khoản khác nhau và thêm một số thuật ngữ liên quan khác có thể mọc lên ở những nơi khác.

Hãy xem xét ví dụ sau:

package a.b;
class C {
  static class D extends C {
  }
  D d;
  D[] ds;
}
  • Các tên đơn giản của DD. Đó chỉ là phần bạn đã viết khi khai báo lớp. Các lớp ẩn danh không có tên đơn giản. Class.getSimpleName()trả về tên này hoặc chuỗi rỗng Tên đơn giản có thể chứa một $nếu bạn viết nó như thế này, vì đây $là một phần hợp lệ của mã định danh theo phần JLS 3.8 (ngay cả khi nó hơi nản lòng).

  • Theo mục JLS 6.7 , cả hai a.b.C.Da.b.C.D.D.Dsẽ là tên đủ điều kiện , nhưng chỉ a.b.C.Dtên chính tắc của D. Vì vậy, mỗi tên chính tắc là một tên đủ điều kiện, nhưng điều ngược lại không phải lúc nào cũng đúng. Class.getCanonicalName()sẽ trả lại tên chính tắc hoặc null.

  • Class.getName()được ghi lại để trả về tên nhị phân , như được chỉ định trong phần JLS 13.1 . Trong trường hợp này nó sẽ trả về a.b.C$Dcho D[La.b.C$D;cho D[].

  • Câu trả lời này chứng minh rằng có thể hai lớp được tải bởi cùng một trình nạp lớp có cùng tên chính tắc nhưng tên nhị phân riêng biệt . Cả hai tên đều không đủ để suy luận một cách đáng tin cậy: nếu bạn có tên chính tắc, bạn không biết phần nào của tên là gói và phần nào chứa các lớp. Nếu bạn có tên nhị phân, bạn không biết cái nào $được giới thiệu là dấu phân cách và là một phần của một số tên đơn giản. (Tệp lớp lưu trữ tên nhị phân của chính lớp đólớp kèm theo của nó , cho phép bộ thực thi tạo sự khác biệt này .)

  • Các lớp ẩn danhcác lớp cục bộ không có tên đủ điều kiện nhưng vẫn có tên nhị phân . Điều tương tự giữ cho các lớp được lồng trong các lớp như vậy. Mỗi lớp có một tên nhị phân.

  • Chạy javap -v -privatetrên a/b/C.classcho thấy rằng mã byte liên quan đến loại das La/b/C$D;và của mảng ds[La/b/C$D;. Chúng được gọi là mô tả và chúng được chỉ định trong phần 4.3 của JVMS .

  • Tên lớp a/b/C$Dđược sử dụng trong cả hai mô tả này là những gì bạn nhận được bằng cách thay thế .bằng /tên nhị phân. Đặc tả JVM rõ ràng gọi đây là dạng bên trong của tên nhị phân . Phần 4.2.1 của JVMS mô tả nó và nói rằng sự khác biệt so với tên nhị phân là vì lý do lịch sử.

  • Tên tệp của một lớp trong một trong các trình nạp lớp dựa trên tên tệp điển hình là những gì bạn nhận được nếu bạn diễn giải /ở dạng bên trong của tên nhị phân như một dấu tách thư mục và nối thêm phần mở rộng tên tệp .classvào nó. Nó được giải quyết liên quan đến đường dẫn lớp được sử dụng bởi trình nạp lớp trong câu hỏi.


3
Đây phải là câu trả lời được chấp nhận vì đây là câu trả lời duy nhất tham chiếu đến JLS và sử dụng các thuật ngữ thích hợp.
Giăng

10

đây là tài liệu tốt nhất tôi tìm thấy mô tả getName (), getSimpleName (), getCanonicalName ()

https://javahowtodoit.wordpress.com/2014/09/09/java-lang- class-what-is-the-default-b between

// 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

Thật thú vị khi lưu ý rằng getCanonicalName()getSimpleName()có thể nâng caoInternalError khi tên lớp không đúng. Điều này xảy ra đối với một số ngôn ngữ JVM không phải Java, ví dụ: Scala.

Hãy xem xét những điều sau đây (Scala 2.11 trên 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

Đây có thể là một vấn đề đối với các môi trường ngôn ngữ hỗn hợp hoặc môi trường tải động mã byte, ví dụ: máy chủ ứng dụng và phần mềm nền tảng khác.


2

getName () - trả về tên của thực thể (lớp, giao diện, lớp mảng, kiểu nguyên thủy hoặc void) được đại diện bởi đối tượng Class này, dưới dạng Chuỗi.

getCanonicalName () - trả về tên chính tắc của lớp bên dưới như được định nghĩa bởi Đặc tả ngôn ngữ Java.

getSimpleName () - trả về tên đơn giản của lớp bên dưới, đó là tên mà nó đã được đặt trong mã nguồn.

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

Một sự khác biệt là nếu bạn sử dụng một lớp ẩn danh, bạn có thể nhận được một giá trị null khi cố gắng lấy tên của lớp bằng cách sử dụnggetCanonicalName()

Một thực tế khác là getName()phương thức hành xử khác với getCanonicalName()phương thức cho các lớp bên trong . getName()sử dụng một đô la làm dấu phân cách giữa tên chính tắc của lớp kèm theo và tên đơn giản của lớp bên trong.

Để biết thêm về việc lấy một tên lớp trong Java .


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
Hai dòng đầu tiên bên trong phương thức có thể được rút gọn thànhClass<StringBuffer> clazz = StringBuffer.class
ThePyroEagle
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.