Java源码解析(3) —— Class(2)

Class 源码详解续(2)

  续Class,详见:Java源码解析(2) —— Class(1)
  关于嵌套类、内部类、成员类、局部类、匿名类、静态类等知识详见:Java各种称呼类详解

源码

//以下说的类是Class而非class
//如果该Class对象位于一个方法内,返回包含这个类的方法的信息(Method对象)
public Method getEnclosingMethod() {...}
//如果该方法具有(内部)局部类或匿名类,获取其信息,包括Class对象、name以及描述。
private native Object[] getEnclosingMethod0();
//获取包含局部类或匿名类的方法的信息
private EnclosingMethodInfo getEnclosingMethodInfo() {
        Object[] enclosingInfo = getEnclosingMethod0();
        if (enclosingInfo == null)
            return null;
        else {
            return new EnclosingMethodInfo(enclosingInfo);
        }
    }
//包含局部类或匿名类的方法的信息描述类
private final static class EnclosingMethodInfo {...}
//将参数Type对象o转化为Class对象
private static Class<?> toClass(Type o) {
        if (o instanceof GenericArrayType)
            return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
                                     0)
                .getClass();
        return (Class<?>)o;
     }
//类似getEnclosingMethod,只是这是针对构造器
@CallerSensitive
public Constructor<?> getEnclosingConstructor() {
}
//若该类是成员类,返回外部类Class对象,否则返回null
public Class<?> getDeclaringClass() {...}
private native Class<?> getDeclaringClass0();
@CallerSensitive
//类似getEnclosingMethod,只是这是针对类
public Class<?> getEnclosingClass() {}
//如果该类是顶级类,返回null,否则返回该类去除顶级类外后字符串
//非顶级类名称命名:顶级类全限定名+$+[(该种类类的,有的话)顺序]+[类名称(如果有的话)]
//成员类:com.fcc.test.OuterClass$MemberClass,调用该方法后,返回
//$MemberClass
private String getSimpleBinaryName() {
        Class<?> enclosingClass = getEnclosingClass();
        if (enclosingClass == null) //无外部类,即为顶级类
            return null;
        try {
            return getName().substring(enclosingClass.getName().length());
        } catch (IndexOutOfBoundsException ex) {
            throw new InternalError("Malformed class name");
        }
    }
//返回简单类名称(不包含包名)
public String getSimpleName() {
    if (isArray())//首先判断该类是否是数组
            return getComponentType().getSimpleName()+"[]";
//是数组,返回形式:元素类名称[]
        String simpleName = getSimpleBinaryName();
        if (simpleName == null) { //等于null,即该类为顶级类
            simpleName = getName();
            return simpleName.substring(simpleName.lastIndexOf(".")+1); 
        //顶级类的简单名称即去掉包名即可 
        }
        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++;
        // 找到$字符位置
        return simpleName.substring(index);//返回嵌套类名称
}
//判断字符是否是ASCII码
private static boolean isAsciiDigit(char c) {
        return '0' <= c && c <= '9';
}
//除数组外,同getName方法,数组时,getName返回的是[Ljava.lang.String之类的表现
//形式,而getCanonicalName返回的就是跟我们声明类似的形式。
public String getCanonicalName() {}
//判断是否是注释类型
public boolean isAnonymousClass() {
        return "".equals(getSimpleName());
    }
//判断是否是局部类
public boolean isLocalClass() {
        return isLocalOrAnonymousClass() && !isAnonymousClass();
    }
//判断是否是成员类
public boolean isMemberClass() {
        return getSimpleBinaryName() != null && !isLocalOrAnonymousClass();
        //非顶级类,且不是局部类也不是匿名类,即为成员类
    }
//判断是否是局部类或匿名类
private boolean isLocalOrAnonymousClass() {
        return getEnclosingMethodInfo() != null;
    }
//获取该类中所有公有的成员类
//getDeclaredClasses则是获取所有成员类Class对象
    @CallerSensitive
public Class<?>[] getClasses() {}
//获取所有公有字段
@CallerSensitive
    public Field[] getFields() throws SecurityException {...}
//获取所有公有方法
@CallerSensitive
    public Method[] getMethods() throws SecurityException {...}
//获取所有公有构造器
 @CallerSensitive
    public Constructor<?>[] getConstructors() throws SecurityException {...}
//根据名称获取字段(该字段需要为public的否则抛异常)
@CallerSensitive
    public Field getField(String name)
        throws NoSuchFieldException, SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);//公有成员访问限定
        Field field = getField0(name);//本地方法获取字段信息
        if (field == null) {//为null,表示没有,抛不存在该字段异常
            throw new NoSuchFieldException(name);
        }
        return field;
    }
//根据方法名称获取方法信息,后面的变长参数是该方法的每一个参数的对应的Class类型
//同样需要方法是公有的
@CallerSensitive
    public Method getMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {...}
//根据构造器名称获取构造器信息,后面的变长参数是该构造器的每一个参数的对应的Class类型
//同样需要构造器是公有的
@CallerSensitive
    public Constructor<T> getConstructor(Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {...}

概述

上面有很多类似的方法,总结起来需要知道:
1.类里面有这么些东西:类(Class)、字段(Field)、方法(Method)、构造器(Constructor),这样就会有类似的方法,比如:getClass()/getClasses()、getField()/getFields()、getMethod()/getMethods()等,但要注意,Class这一对方法和其他的不同。
2.另外,类似getDeclaredFields(),中间加了Declared的表示获取所有对象,而未加的则表示获取公有的所有对象。
3.enclosingMethod、enclosingConstructor、enclosingClass,enclosing表示该类是被包装起来的,那么就分为三种,分别是被包装在方法、构造器或类中。

源码详解

1.getEnclosingXxx
  这个Xxx表示某种对象,比如Method,表示如果这个类存在于某个方法内,返回这个方法(Method对象),否则返回null。(注意,构造器不是方法)
  类似的还有getEnclosingClass()/getEnclosingConstructor():分别是如果类位于类中、构造器中,返回相应的类、构造器信息。

public class {
    class A;//位于类中,有enclosed class属性
    public Main(){
        class B;//类位于构造器中,有enclosed constructor属性
    }
    public static void main(String[] args) throws Exception
    {
        Class c1 = new InterfaceA(){}.getClass();
        //类位于方法中,有enclosed method属性
    }
}

2.getXxx
  这里的Xxx可以是:Class、Field、Method、Constructor,表示获取该类中的指定的(参数)对应的公有对象(Class不同,表示获取该类的Class对象),也可以是他们的复数,表示获取该类中对应的所有公有对象(getClasses表示获取所有公有成员类)。
3.getDeclaredXxx
  和2类似,只不过这次获取的是该类所有对应的对象,而不是仅仅是公有的。
4.getName、getSimpleName、getCanonicalName
  (1).getName:获取类全限定名,形如:com.fcc.test.ClassName,当这个类是数组的时候,会得到奇怪的结果:[[Ljava.lang.String;这是个二元数组。
  (2).getSimpleName:去掉包名的简单类名称,数组时候返回正常:String[][]。
  (3).getCanonicalName:同getName,但数组的时候返回正常:java.lang.String[][]。

猜你喜欢

转载自blog.csdn.net/a327369238/article/details/52770389