Class对象的getXXXClass和getXXXName

本文详细介绍了Java中Class对象的getXXXClass和getXXXName相关方法,包括getEnclosingClass、getDeclaringClass、getSimpleName、getName和getCanonicalName等,分析了它们的区别和使用场景,以及在Spring框架中classMetadata的相关应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. getXXXClass方法获取class对象

在讲解具体的方法之前,我们先介绍一下java类(接口)的划分方法。
java的class对象分为5种,这一点在getEnclosingClass方法的注释中有写明,分别是:
a. Top类
b. Nested类:嵌套类,即静态成员类
c. Inner类:内部类,即普通成员类
d. Local类:局部类,在方法中定义的类
e. Anonymous:匿名类

Class对象有3个和name相关的方法,分别是getClass, getDeclaringClass和getEnclosingClass,下面我们仔细看一下这3个方法有什么区别。

  • getClass方法
    getClass方法是从Object类继承而来的方法,返回的是该对象所对应的运行时类。
    class.getClass()返回的自然是java.lang.Class.

  • getDeclaringClass方法
    从注释可以看出,class.getDeclaringClass()方法返回了声明class对象的类,只有当class对象的类A是另一个类B的成员类,该方法才能返回值,返回该成员类所在的类(即类B),否则返回null值。
    如果class对象是local class,是在类B的方法里定义的,同样返回null值,而不会返回类B。

 /**
 * If the class or interface represented by this {@code Class} object
 * is a member of another class, returns the {@code Class} object
 * representing the class in which it was declared.  This method returns
 * null if this class or interface is not a member of any other class.  If
 * this {@code Class} object represents an array class, a primitive
 * type, or void,then this method returns null.
 *  * @return the declaring class for this class
 * @throws SecurityException
 *         If a security manager, <i>s</i>, is present and the caller's
 *         class loader is not the same as or an ancestor of the class
 *         loader for the declaring class and invocation of {@link
 *         SecurityManager#checkPackageAccess s.checkPackageAccess()}
 *         denies access to the package of the declaring class
 * @since JDK1.1
   */
  @CallerSensitive
  public Class<?> getDeclaringClass() throws SecurityException {
      final Class<?> candidate = getDeclaringClass0();

      if (candidate != null)
          candidate.checkPackageAccess(
                  ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
      return candidate;
  }
  • getEnclosingClass方法

返回该class对象的立即封闭类,即该类实在哪个类里定义的,与getDeclaringClass不同,getEnclosingClass并不要求一定是成员类。

@CallerSensitive
public Class<?> getEnclosingClass() throws SecurityException {
    EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo();
    Class<?> enclosingCandidate;

    if (enclosingInfo == null) {
        // This is a top level or a nested class or an inner class (a, b, or c)
        enclosingCandidate = getDeclaringClass();
    } else {
        Class<?> enclosingClass = enclosingInfo.getEnclosingClass();
        // This is a local class or an anonymous class (d or e)
        if (enclosingClass == this || enclosingClass == null)
            throw new InternalError("Malformed enclosing method information");
        else
            enclosingCandidate = enclosingClass;
    }

    if (enclosingCandidate != null)
        enclosingCandidate.checkPackageAccess(
                ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
    return enclosingCandidate;
}

总结一下:
**class对象getXXXClass方法对比表**

  1. getXXXName方法返回名称

在讲具体的区别之前,先明确对象的描述符概念。
在class文件里,字段表集合里存储了类的属性和方法,并且通过描述符来区分不同的对象类型。对于基本数据结构,描述符用一个大写字母表示;对于对象,描述符用L+类的全限定名表示,并以分号结束。
描述符在class类中getName方法的注释中也有描述。
**描述符**

Class对象有3个和name相关的方法,分别是getSimpleName, getName和getCanonicalName,下面我们仔细看一下这3个方法有什么区别。

  • getName
    在class类里,getName方法通过调用native方法getName0获得,返回class对象在虚拟机里面的表示。
    1 .对于top class,getName为:类的全限定名,如:test.Test。
    2 .对于nested class和inner class,getName为:getEnclosingClass的getName + $ + 类名,如test.Test$Inner。
    3 . 对于anonymous class,getName为:getEnclosingClass的getName + $ + 虚拟机分配的类名(虚拟机对于每一个类中的匿名类会按顺序分配给1,2之类的类名,如test.Test$1。
    对于local class,getName为:getEnclosingClass的getName + $ + 虚拟机分配的前缀+类名(由于local class是属于方法的,一个类中的不同方法下的local class类名是有可能相同的,所以虚拟机会在类名前面自动加上按方法加上1,2之类的排序),如test.Test$2LocalClass。
    4 .对于基本数据结构的class对象,getName为:基本数据结构的名称,如boolean。
    5 .对于数组的class对象,getName为:[ + 元素类型的描述符,如[Ljava.lang.String;(带分号),[Z。如果是多维数组,则带有多个[。

  • getSimpleName方法

    从代码可以看出
    1 .对于数组的class对象,返回元素类型的getSimpleName+[]。
    2 .对于非top class的对象,获取getEnclosingClass,从getName中截去getEnclosingClass的getName,截去$符号,然后截去字符串前面的所有数字。
    3 .对于top class的对象,返回类名。

public String getSimpleName() {
   if (isArray())
        return getComponentType().getSimpleName()+"[]";

    String simpleName = getSimpleBinaryName();
    if (simpleName == null) { // top level class
        simpleName = getName();
        return simpleName.substring(simpleName.lastIndexOf(".")+1); // strip the package name
    }
    int length = simpleName.length();
   if (length < 1 || simpleName.charAt(0) != '$')
       throw new InternalError("Malformed class name");
   int index = 1;
   while (index < length && isAsciiDigit(simpleName.charAt(index)))
       index++;
   // Eventually, this is the empty string iff this is an anonymous class
   return simpleName.substring(index);
}
private String getSimpleBinaryName() {
   Class<?> enclosingClass = getEnclosingClass();
    if (enclosingClass == null) // top level class
        return null;
    // Otherwise, strip the enclosing class' name
    try {
        return getName().substring(enclosingClass.getName().length());
    } catch (IndexOutOfBoundsException ex) {
        throw new InternalError("Malformed class name", ex);
    }
}
  • getCanonicalName方法
    1 .对于数组的class对象,检查元素类型的getCanonicalName,如果是null,则返回null;否则元素类型的getCanonicalName + []。
    2 .对于local class和anonymous class,返回null。
    3.对于top class,返回getName。
    4.获取getEnclosingClass的getCanonicalName作为canonicalName,为null则返回null;否则getCanonicalName + . + getSimpleName。
public String getCanonicalName() {
  if (isArray()) {
      String canonicalName = getComponentType().getCanonicalName();
      if (canonicalName != null)
          return canonicalName + "[]";
      else
          return null;
  }
  if (isLocalOrAnonymousClass())
      return null;
  Class<?> enclosingClass = getEnclosingClass();
  if (enclosingClass == null) { // top level class
      return getName();
  } else {
      String enclosingName = enclosingClass.getCanonicalName();
      if (enclosingName == null)
          return null;
      return enclosingName + "." + getSimpleName();
  }
}

总结一下:
**class对象getXXXName方法对比表**

  1. spring包里的classMetadata
    在spring的org.springframework.core.type包下的classMetadata接口里有一些与我们上述内容相关的方法,这些方法在spring的源码中经常会遇到,我们通过其实现类StandardClassMetadata一并解释一下:
  • isIndependent
    从方法名称上可以看出,判断对应的类是否是独立的,不需要依赖其它类。
    如果是top class或nested class,视为Independent,返回true;否则返回false。
@Override
public boolean isIndependent() {
	return (!hasEnclosingClass() ||
			(this.introspectedClass.getDeclaringClass() != null &&
			Modifier.isStatic(this.introspectedClass.getModifiers())));
}
  • hasEnclosingClass
    从方法名称上可以看出,判断getEnclosingClass是否存在。
    如果是top class返回false,否则返回true。
@Override
public boolean hasEnclosingClass() {
	return (this.introspectedClass.getEnclosingClass() != null);
}
  • getEnclosingClassName
    从方法名称上可以看出,获取getEnclosingClass的getName。
    如果是top class返回null,否则返回getEnclosingClass的getName。
@Override
@Nullable
public String getEnclosingClassName() {
	Class<?> enclosingClass = this.introspectedClass.getEnclosingClass();
	return (enclosingClass != null ? enclosingClass.getName() : null);
}
  • getClassName
    从方法名称上可以看出对于class对象的getName。
@Override
public String getClassName() {
	return this.introspectedClass.getName();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值