添加本地类、lambda 和方法以完成前两个答案。此外,我添加了lambda数组和匿名类数组(尽管这在实践中没有任何意义):toString()
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
- 如果类对象表示基元类型 或 ,则所有四个方法都只返回其名称。
void
现在,该方法的规则:getName()
- 每个非 lambda 和非数组类或接口(即顶级、嵌套、内部、本地和匿名)都有一个名称(由 返回),该名称是包名称,后跟一个点(如果有包),后跟编译器生成的类文件的名称(去掉后缀)。如果没有包,它只是类文件的名称。如果类是内部类、嵌套类、本地类或匿名类,则编译器应在其类文件名中至少生成一个类。请注意,对于匿名类,类名将以美元符号结尾,后跟数字。
getName()
.class
$
- Lambda 类名通常是不可预测的,无论如何您都不应该关心它们。确切地说,它们的名称是封闭类的名称,后跟 ,后跟一个数字,后跟一个斜杠,后跟另一个数字。
$$Lambda$
- 基元的类描述符是 for 、 for 、 for 、 for 、 for 、 for 和 for 。对于非数组类和接口,类描述符后跟给出的内容,后跟 。对于数组类,类描述符后跟组件类型的类描述符(其本身可能是另一个数组类)。
Z
boolean
B
byte
S
short
C
char
I
int
J
long
F
float
D
double
L
getName()
;
[
- 对于数组类,该方法返回其类描述符。此规则似乎仅对组件类型为 lambda 的数组类失败(这可能是一个错误),但希望这无论如何都无关紧要,因为即使组件类型为 lambda 的数组类的存在也没有意义。
getName()
现在,方法:toString()
- 如果类实例表示接口(或注释,它是一种特殊类型的接口),则返回 。如果它是基元,则仅返回 。如果它是其他东西(类类型,即使它是一个非常奇怪的类类型),它将返回 。
toString()
"interface " + getName()
getName()
"class " + getName()
方法:getCanonicalName()
- 对于顶级类和接口,该方法仅返回该方法返回的内容。
getCanonicalName()
getName()
- 该方法返回匿名或本地类以及这些类的数组类。
getCanonicalName()
null
- 对于内部和嵌套类和接口,该方法返回该方法将用点替换编译器引入的美元符号的内容。
getCanonicalName()
getName()
- 对于数组类,如果组件类型的规范名称为 ,则返回该方法。否则,它将返回组件类型的规范名称,后跟 。
getCanonicalName()
null
null
[]
方法:getSimpleName()
- 对于顶级类、嵌套类、内部类和本地类,将返回源文件中写入的类的名称。
getSimpleName()
- 对于匿名类,返回空 .
getSimpleName()
String
- 对于 lambda 类,仅返回在没有包名称的情况下将返回的内容。这对我来说没有多大意义,看起来像一个错误,但是从调用lambda类开始是没有意义的。
getSimpleName()
getName()
getSimpleName()
- 对于数组类,该方法返回组件类的简单名称,后跟 。这有一个有趣/奇怪的副作用,即组件类型为匿名类的数组类就像它们的简单名称一样。
getSimpleName()
[]
[]