Class类 getName()、getCanonicalName()、getSimpleName()、getTypeName() 方法的异同

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Goodbye_Youth/article/details/83536840

最近在研究学习反射的相关知识,学习到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()
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(),最终会返回空字符串
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?

猜你喜欢

转载自blog.csdn.net/Goodbye_Youth/article/details/83536840
今日推荐