探索JDK源碼-每行代碼堪稱教科書級別(1)Modifier.java

前言

身爲一個Java開發者,你可能還在初級階段,或者正在往更高的階段努力着。不管你的編碼能力如何,閱讀源碼的能力是你最基本的技能也是最容易潛移默化的提升各方面能力的一部分。爲什麼這麼說呢?Java從1995年問世直到今天,它積累了太多前人的智慧結晶,每一行代碼都是教科書級別的詮釋。閱讀它並在項目中學着應用其精華,想必對你的成長速度是最快的。從這篇文章開始,我將寫下閱讀JDK源碼後的過程、困難和心得,讓我們一起學習進步吧。

首先需要大概講一下如何查看JDK的源碼。如果你使用的是IDEA工具,那麼當你雙擊Shift鍵後輸入一個類名進入後,可以點擊Download Source進行源碼的下載。如果你還在用Eclipse工具,那麼很不幸,你需要將JDK安裝目錄下的src.zip文件加壓後才能得到JDK源碼。所以這裏建議決定走Java開發的用IDEA來開發更符合時代的潮流(因爲真的方便很多)。

今天要講的是Java反射包中的Modifier.java

放心即使你目前沒學過反射也不影響對這份代碼的理解,因爲我們還沒有要真正進入反射機制的探索。

Modifier.java是一個修飾符類,提供許多用於標識類、方法和變量訪問修飾符的常量。

標識類和變量訪問修飾符的常量(十六進制)

public static final int PUBLIC         = 0x00000001; // public
public static final int PRIVATE        = 0x00000002; // private
public static final int PROTECTED      = 0x00000004; // protected
public static final int ABSTRACT       = 0x00000400; // abstract
public static final int STATIC         = 0x00000008; // static
public static final int FINAL          = 0x00000010; // final
public static final int SYNCHRONIZED   = 0x00000020; // synchronized(修飾方法的同步鎖)
public static final int VOLATILE       = 0x00000040; // volatile(修飾變量的同步鎖)
public static final int TRANSIENT      = 0x00000080; // transient(修飾不參與序列化的變量)
public static final int NATIVE         = 0x00000100; // native(修飾本地方法)
public static final int STRICT         = 0x00000800; // strictfp(修飾類、接口、方法,使其所有的float、double類型都以精確浮點IEEE-754規範進行計算)
public static final int INTERFACE      = 0x00000200; // interface

從上面可以看到用整型數定義了訪問一個類、方法和變量的所有修飾符標識,仔細觀察就可以發現他們有一個共同的特點:整數標識轉化成二進制後,進制位爲1的位置都是不一樣的。

public static final int PUBLIC         = 0x00000001; // 000000000001
public static final int PRIVATE        = 0x00000002; // 000000000010
public static final int PROTECTED      = 0x00000004; // 000000000100
public static final int STATIC         = 0x00000008; // 000000001000
public static final int FINAL          = 0x00000010; // 000000010000
public static final int SYNCHRONIZED   = 0x00000020; // 00‭0000100000‬
public static final int VOLATILE       = 0x00000040; // ‭000001000000‬
public static final int TRANSIENT      = 0x00000080; // 000010000000
public static final int NATIVE         = 0x00000100; // 000100000000‬
public static final int INTERFACE      = 0x00000200; // 001000000000
public static final int ABSTRACT       = 0x00000400; // 010000000000
public static final int STRICT         = 0x00000800; // 100000000000

這樣的設計是相當巧妙的,因爲接下來就可以通過這個特點來做運算得到一些信息了。

判斷一個類、方法或變量是否具有某屬性

public static boolean isPublic(int mod) { /* mod就是當前類、方法或屬性具有的所有屬性值的和 */
	return (mod & PUBLIC) != 0;
}

(mod & PUBLIC) != 0這裏巧妙的使用了二進制的’與運算’來達到識別一個數是否是構成一個十六進制數的必要條件。

  1. 假設當前屬性值的和mod = PUBLIC + STATIC,則有以下運算:
mod = 0x00000001 + 0x00000008 = 0x00000009 = 000000001001
mod & PUBLIC = 000000001001 & 000000000001 = 000000000001 = 1 // 說明具有PUBLIC屬性	
  1. 假設當前屬性值的和mod = PRIVATE+ STATIC,則有以下運算:
mod = 0x00000002 + 0x00000008 = 0x00000010 = 000000010000
mod & PUBLIC = 000000010000 & 000000000001 = 000000000000 = 0 // 說明沒有有PUBLIC屬性	
  1. 當然JDK還提供了許多這樣的方法:
public static boolean isPublic(int mod) {
	return (mod & PUBLIC) != 0;
}
public static boolean isPrivate(int mod) {
	return (mod & PRIVATE) != 0;
}
public static boolean isProtected(int mod) {
	return (mod & PROTECTED) != 0;
}
public static boolean isStatic(int mod) {
	return (mod & STATIC) != 0;
}
public static boolean isFinal(int mod) {
	return (mod & FINAL) != 0;
}
public static boolean isSynchronized(int mod) {
	return (mod & SYNCHRONIZED) != 0;
}
public static boolean isVolatile(int mod) {
	return (mod & VOLATILE) != 0;
}
public static boolean isTransient(int mod) {
	return (mod & TRANSIENT) != 0;
}
public static boolean isNative(int mod) {
	return (mod & NATIVE) != 0;
}
public static boolean isInterface(int mod) {
	return (mod & INTERFACE) != 0;
}
public static boolean isAbstract(int mod) {
	return (mod & ABSTRACT) != 0;
}
public static boolean isStrict(int mod) {
	return (mod & STRICT) != 0;
}

獲取一個類、方法或變量的所有屬性

public static String toString(int mod) { /* mod就是說有屬性對應整型標誌相加後的結果 */
    StringBuilder sb = new StringBuilder();
    int len;

    if ((mod & PUBLIC) != 0)        sb.append("public ");
    if ((mod & PROTECTED) != 0)     sb.append("protected ");
    if ((mod & PRIVATE) != 0)       sb.append("private ");
    if ((mod & ABSTRACT) != 0)      sb.append("abstract ");
    if ((mod & STATIC) != 0)        sb.append("static ");
    if ((mod & FINAL) != 0)         sb.append("final ");
    if ((mod & TRANSIENT) != 0)     sb.append("transient ");
    if ((mod & VOLATILE) != 0)      sb.append("volatile ");
    if ((mod & SYNCHRONIZED) != 0)  sb.append("synchronized ");
    if ((mod & NATIVE) != 0)        sb.append("native ");
    if ((mod & STRICT) != 0)        sb.append("strictfp ");
    if ((mod & INTERFACE) != 0)     sb.append("interface ");

    if ((len = sb.length()) > 0)    /* 去除最後一個空格 */
        return sb.toString().substring(0, len-1);
    return "";
}

(mod & PUBLIC) != 0這裏巧妙的使用了二進制的’與運算’來達到識別一個數是否是構成一個十六進制數(mod)的必要條件,這裏我們可以來模擬一下就清楚爲什麼了:

public static final String TAG = "";

根據上面的修飾符對應的十六進制做以下計算得到mod:

int mod = Modifier.PUBLIC + Modifier.STATIC + Modifier.FINAL;
// mod = 0x00000001 + 0x00000008 + 0x00000010 = 0x00000019 = 000000011001‬

通過計算得到mod十進制爲19,二進制爲000000011001。通過與運算:

mod & PUBLIC		mod & STATIC		mod & FINAL
= 000000011001= 000000011001= 000000011001& 000000000001		& 000000001000		& 000000010000
= 000000000001		= 000000001000		= 000000010000
= 1					= 8					= 16

通過打印可以看到 : public static final

綜合以上的知識應用到自己的項目中

比如你要做一個鏈接地址分類功能,那麼你可以定義一個類LinkType.java

public class LinkType {
    // 科技
    public static final int SCIENCE          = 0x00000001;
	// 計算機
    public static final int COMPUTER         = 0x00000002;
	// 藝術
    public static final int ART              = 0x00000004;
	// 新聞
    public static final int NEW              = 0x00000008;
    
    public static String toString(int type) { /* type:鏈接屬於的所有類型值得和 */
        StringBuilder sb = new StringBuilder();

        if ((type & SCIENCE) != 0)      sb.append("科技 ");
        if ((type & COMPUTER) != 0)     sb.append("計算機 ");
        if ((type & ART) != 0)          sb.append("藝術 ");
        if ((type & NEW) != 0)        	sb.append("新聞 ");

        int len = sb.length();
        if (len > 0)    /* 去掉最後一個空格 */
            return sb.toString().substring(0, len-1);
        return "";
    }
}

相信通過這個講解已經對Modifer.java源碼得思想有了一定得思考。其實這種採用二進制的方式來判斷一個十六進制得數由哪些數(標誌)構成在真實項目中經常會被用到,而且套路上都是一樣的。

如果不是通過閱讀源碼,我想就算看再多的書籍都不可能學習到這樣一種編碼方式,而且是最爲科學的了。所以說只要敢於挑戰源碼,那麼就一定會有所收穫!

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