最近在研究学习反射的相关知识,学习到Class类中的 getName()、getCanonicalName()、getSimpleName()、getTypeName() 这四个方法时,感到有些困惑,因此上网查了下相关资料,开个贴记录下自己所了解到的知识
先说说这四个方法各自的作用
- getName()
- 返回该类对象作为字符串表示的实体(类、接口、数组类、基本数据类型或void)的名称
- 可以理解为返回的是 虚拟机中Class对象的表示
- 当我们 动态加载类 的时候,会用到该方法的返回值,如: 使用 Class.forName() 方法
- 如果是 内部类,则使用 $ 符号进行连接
- 如果是 数组,则使用 [ 来表示,数组是几维,[ 就有几个
- 其余情况的表示如下
- 源码如下
// getName()
System.out.println(String[].class.getName()); // [Ljava.lang.String;
Class<?> clazz = Class.forName("[Ljava.lang.String;");
System.out.println(clazz); // class [Ljava.lang.String;
- getCanonicalName()
- 返回Java语言规范定义的底层类的规范名称
- 如果是一个本地类或匿名类或其组件的数组类型没有规范名称的,则返回null
- 可以理解为返回的是 正常的包含路径的类名
- 该方法的返回值可以在 import语句中使用
- 能唯一标识一个类,还可以在toString()或日志操作期间使用
- 源码如下
首先来看下源码中设计到的几个方法- isArray()
判断该Class对象是否为数组,如果是返回true,不是返回false - getComponentType()
返回表示数组类型的类,如果该Class对象不是一个数组,则返回null - isLocalOrAnonymousClass()
该方法是一个私有方法,用来判断该Class对象是否为本地类或匿名类 - getEnclosingClass()
返回该Class对象的封装类,如果是该Class对象是顶级类,则返回null
- isArray()
// isArray()
System.out.println(String[].class.isArray()); // true
System.out.println(String.class.isArray()); // false
// getComponentType()
System.out.println(String[].class.getComponentType()); // class java.lang.String
System.out.println(String.class.getComponentType()); // null
// getEnclosingClass()
public class AAA {
class BBB {
public BBB () {
System.out.println(new Object(){}.getClass().getEnclosingClass());
}
}
public static void main(String[] args) {
System.out.println(AAA.class.getEnclosingClass()); // null
System.out.println(BBB.class.getEnclosingClass()); // class lang.reflect.AAA
new AAA().new BBB(); // class lang.reflect.AAA$BBB
System.out.println(BBB.class.getCanonicalName()); // lang.reflect.AAA.BBB
}
}
弄懂这几个方法后,然后再看源码就很好理解了,用 BBB.class.getCanonicalName() 为例,先判断其是否为数组对象,不是则跳过,再判断其是否为本地类或匿名类,不是则跳过,然后获取其封装类,得到 lang.reflect.AAA,接着会递归调用 getCanonicalName() 方法直至顶级类 (此处AAA即为顶级类),最后用 . 进行拼接,得到 lang.reflect.AAA.BBB
- getSimpleName()
- 返回源代码中给出的基础类的简单名称,如果基础类是匿名的,则返回空字符串
- 可以理解为返回的是仅仅是 类名,不包含路径
- 不能保证能唯一标识一个类,可以在toString()或日志操作期间使用
- 源码如下
首先来看下源码中设计到的几个方法- getSimpleBinaryName()
该方法是一个私有方法,返回该Class对象的的“简单二进制名称”,如果该Class对象是顶级类,则返回null,用 BBB.class.getSimpleName() 为例,该方法会返回 $BBB - isAsciiDigit(char c)
该方法也是一个私有方法,用于判断 getSimpleBinaryName() 返回的值下标为 1 处的字符是否位于 ‘0’ - ‘9’ 之间,如果是返回true且index递增,不是返回false
用 new Object(){}.getClass().getSimpleName() 为例,使用 new Object(){}.getClass() 得到的结果为 class lang.reflect.AAA$1,再调用 getSimpleName(),最终会返回空字符串
- getSimpleBinaryName()
public class AAA {
class BBB {
}
public static void main(String[] args) {
System.out.println(BBB.class.getSimpleName()); // BBB
System.out.println(new Object(){}.getClass().getSimpleName()); // ""
}
}
弄懂这几个方法后,再结合例子,然后再看源码就很好理解了
- getTypeName()
- 返回此类型名称的信息字符串
- 可以理解为返回的是该类类型的名称
- 源码如下
首先先判断其是否为数组则对象,如不是则直接返回 getName() 方法获得的值,如果是则通过循环判断是否为数组对象,最终得到表示数组类型的类,然后追加 “[]”,返回其字符串形式
最后放些例子,可以让大家直观地感受这四个方法之间的差异
public class AAA {
class BBB {
}
public static void main(String[] args) {
// 数组
System.out.println(String[].class.getName()); // [Ljava.lang.String;
System.out.println(String[].class.getCanonicalName()); // java.lang.String[]
System.out.println(String[].class.getSimpleName()); // String[]
System.out.println(String[].class.getTypeName()); // java.lang.String[]
// 成员内部类
System.out.println(BBB.class.getName()); // lang.reflect.AAA$BBB
System.out.println(BBB.class.getCanonicalName()); // lang.reflect.AAA.BBB
System.out.println(BBB.class.getSimpleName()); // BBB
System.out.println(BBB.class.getTypeName()); // lang.reflect.AAA$BBB
// 匿名内部类
System.out.println(new Object(){}.getClass().getName()); // lang.reflect.AAA$1
System.out.println(new Object(){}.getClass().getCanonicalName()); // null
System.out.println(new Object(){}.getClass().getSimpleName()); // ""
System.out.println(new Object(){}.getClass().getTypeName()); // lang.reflect.AAA$4
// 普通类
System.out.println(AAA.class.getName()); // lang.reflect.AAA
System.out.println(AAA.class.getCanonicalName()); // lang.reflect.AAA
System.out.println(AAA.class.getSimpleName()); // AAA
System.out.println(AAA.class.getTypeName()); // lang.reflect.AAA
// 基本数据类型
System.out.println(int.class.getName()); // int
System.out.println(int.class.getCanonicalName()); // int
System.out.println(int.class.getSimpleName()); // int
System.out.println(int.class.getTypeName()); // int
}
}
最后附上StackOverflow上的回答,个人感觉很有帮助
What is the difference between canonical name, simple name and class name in Java Class?