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[][]。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章