從 JDK 原始碼角度看 Boolean

超人汪小建發表於2019-02-20

Java的Boolean類主要作用就是對基本型別boolean進行封裝,提供了一些處理boolean型別的方法,比如String型別和boolean型別的轉換。

主要實現原始碼如下:

public final class Boolean implements java.io.Serializable, Comparable<Boolean> {

  private final boolean value;

  public static final Boolean TRUE = new Boolean(true);

  public static final Boolean FALSE = new Boolean(false);

  public static final Class<Boolean> TYPE = (Class<Boolean>) Class.getPrimitiveClass("boolean");

  public Boolean(boolean value) {
    this.value = value;
  }

  public Boolean(String s) {
    this(parseBoolean(s));
  }

  public static boolean parseBoolean(String s) {
    return ((s != null) && s.equalsIgnoreCase("true"));
  }

  public boolean booleanValue() {
    return value;
  }

  public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
  }

  public static Boolean valueOf(String s) {
    return parseBoolean(s) ? TRUE : FALSE;
  }

  public static String toString(boolean b) {
    return b ? "true" : "false";
  }

  public String toString() {
    return value ? "true" : "false";
  }

  public int hashCode() {
    return Boolean.hashCode(value);
  }

  public static int hashCode(boolean value) {
    return value ? 1231 : 1237;
  }

  public boolean equals(Object obj) {
    if (obj instanceof Boolean) {
      return value == ((Boolean) obj).booleanValue();
    }
    return false;
  }

  public int compareTo(Boolean b) {
    return compare(this.value, b.value);
  }

  public static int compare(boolean x, boolean y) {
    return (x == y) ? 0 : (x ? 1 : -1);
  }

  public static boolean logicalAnd(boolean a, boolean b) {
    return a && b;
  }

  public static boolean logicalOr(boolean a, boolean b) {
    return a || b;
  }

  public static boolean logicalXor(boolean a, boolean b) {
    return a ^ b;
  }
}複製程式碼

既然是對基本型別boolean的封裝,那必然要有一個變數來儲存,即value,而且它被宣告為final,表明它是不可變的。兩種建構函式可分別傳入boolean和String型別,對於String型別會進行”to boolean”解析,即當傳入的字串忽略大小寫等於”true”時判斷為true,否則為false。

但是我們說一般不推薦直接用建構函式來例項化Boolean物件,這是為什麼?接著往下看,對於布林值也就只有兩種狀態,我們其實可以僅僅用兩個物件就表示所有的布林值,也就是說在Java的世界中只要全域性存在兩個Boolean物件即可,例項化出多餘的Boolean物件仍然能正確表示布林值,只是會浪費一些空間和影響時間效能。僅需要的兩個物件為,

  public static final Boolean TRUE = new Boolean(true);
  public static final Boolean FALSE = new Boolean(false);複製程式碼

所以推薦的形式是Boolean.TRUEBoolean.valueOf(true)Boolean.valueOf("true"),避免生成不必要的物件。

接著再看看Boolean的TYPE屬性,它toString的值其實是boolean

public static final Class<Boolean> TYPE = (Class<Boolean>) Class.getPrimitiveClass("boolean");複製程式碼

看看怎麼來的。Class的getPrimitiveClass是一個native方法,在Class.c中有個Java_java_lang_Class_getPrimitiveClass方法與之對應,所以JVM層面會通過JVM_FindPrimitiveClass函式會根據”boolean”字串獲得jclass,最終到Java層則為Class<Boolean>

Java_java_lang_Class_getPrimitiveClass(JNIEnv *env,
                                       jclass cls,
                                       jstring name)
{
    const char *utfName;
    jclass result;

    if (name == NULL) {
        JNU_ThrowNullPointerException(env, 0);
        return NULL;
    }

    utfName = (*env)->GetStringUTFChars(env, name, 0);
    if (utfName == 0)
        return NULL;

    result = JVM_FindPrimitiveClass(env, utfName);

    (*env)->ReleaseStringUTFChars(env, name, utfName);

    return result;
}複製程式碼

TYPE執行toString時,邏輯如下,則其實是getName函式決定其值,getName通過native方法getName0從JVM層獲取名稱,

public String toString() {
        return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
            + getName();
    }複製程式碼

getName0根據一個陣列獲得對應的名稱,JVM根據Java層的Class可得到對應型別的陣列下標,比如這裡下標為4,則名稱為”boolean”。

const char* type2name_tab[T_CONFLICT+1] = {
  NULL, NULL, NULL, NULL,
  "boolean",
  "char",
  "float",
  "double",
  "byte",
  "short",
  "int",
  "long",
  "object",
  "array",
  "void",
  "*address*",
  "*narrowoop*",
  "*conflict*"
};複製程式碼

往下繼續看HashCode,實現邏輯如下,即true返回1231而false返回1237。

public static int hashCode(boolean value) {
    return value ? 1231 : 1237;
}複製程式碼

equals方法就是先判斷是不是從Boolean例項化出來的,然後再繼續比較是不是相等。

實現Comparable<Boolean>介面是為了方便在集合中進行比較,它需要實現的方法為compareTo

此外,還提供了logicalAnd、logicalOr和logicalXor用於實現三種邏輯運算。

以下是廣告相關閱讀

========廣告時間========

鄙人的新書《Tomcat核心設計剖析》已經在京東銷售了,有需要的朋友可以到 item.jd.com/12185360.ht… 進行預定。感謝各位朋友。

=========================

相關閱讀:
談談Java基礎資料型別
從JDK原始碼角度看併發鎖的優化
從JDK原始碼角度看執行緒的阻塞和喚醒
從JDK原始碼角度看併發競爭的超時
從JDK原始碼角度看java併發執行緒的中斷
從JDK原始碼角度看Java併發的公平性
從JDK原始碼角度看java併發的原子性如何保證

相關文章