02 從JDK原始碼角度看Boolean
Java的Boolean類主要作用就是對基本型別boolean進行封裝,提供了一些處理boolean型別的方法,比如String型別和boolean型別的轉換。
主要實現原始碼如下圖所示,具體實現程式碼可自行檢視對應的程式碼。
既然是對基本型別boolean的封裝,那必然要有一個變數來儲存,即value,而且它被宣告為final,表明它是不可變的。兩種建構函式可分別傳入boolean和String型別,對於String型別會進行”to boolean”解析,即當傳入的字串忽略大小寫等於”true”時判斷為true,否則為false。
但是我們說一般不推薦直接用建構函式來例項化Boolean物件,這是為什麼?接著往下看,對於布林值也就只有兩種狀態
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
所以推薦的形式是Boolean.TRUE
或Boolean.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>
以下是class.c中Java_java_lang_Class_getPrimitiveClass
的原始碼
JNIEXPORT jclass JNICALL
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();
}
這裡呢類似於下面的程式碼執行。
package test;
public class Demo {
public static void main(String[] args) {
System.out.println(Boolean.TYPE.toString());//boolean
}
}
實際上呼叫的是Class.toString()方法。原始碼如上面的toString()原始碼所示。
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。
/**
* Returns a hash code for a {@code boolean} value; compatible with
* {@code Boolean.hashCode()}.
*
* @param value the value to hash
* @return a hash code value for a {@code boolean} value.
* @since 1.8
*/
public static int hashCode(boolean value) {
return value ? 1231 : 1237;
}
原始碼如上所示。
再繼續往下是equals方法,原始碼如下所示:
/**
* Returns {@code true} if and only if the argument is not
* {@code null} and is a {@code Boolean} object that
* represents the same {@code boolean} value as this object.
*
* @param obj the object to compare with.
* @return {@code true} if the Boolean objects represent the
* same value; {@code false} otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Boolean) {
return value == ((Boolean)obj).booleanValue();
}
return false;
}
equals
方法就是先判斷是不是從Boolean例項化出來的,然後再繼續比較是不是相等。
因為Boolean實現Comparable<Boolean>
介面是為了方便在集合中進行比較,它需要實現的方法為compareTo
。
public int compareTo(Boolean b) {
return compare(this.value, b.value);
}
具體compare原始碼如下:
public static int compare(boolean x, boolean y) {
return (x == y) ? 0 : (x ? 1 : -1);
}
此外,還提供了logicalAnd、logicalOr和logicalXor用於實現三種邏輯運算。具體測試程式碼如下:
System.out.println(Boolean.logicalAnd(true, true));
System.out.println(Boolean.logicalAnd(true, false));
System.out.println(Boolean.logicalAnd(false, true));
System.out.println(Boolean.logicalAnd(false, false));
System.out.println(Boolean.logicalOr(true, true));
System.out.println(Boolean.logicalOr(true, false));
System.out.println(Boolean.logicalOr(false, true));
System.out.println(Boolean.logicalOr(false, false));
System.out.println(Boolean.logicalXor(true, true));
System.out.println(Boolean.logicalXor(true, false));
System.out.println(Boolean.logicalXor(false, true));
System.out.println(Boolean.logicalXor(false, false));
//列印結果如下:
// true
// false
// false
// false
// true
// true
// true
// false
// false
// true
// true
// false
至此,還有兩個方法沒有提到,分別是:parseBoolean和getBoolean
parseBoolean原始碼是
/**
* Parses the string argument as a boolean. The {@code boolean}
* returned represents the value {@code true} if the string argument
* is not {@code null} and is equal, ignoring case, to the string
* {@code "true"}. <p>
* Example: {@code Boolean.parseBoolean("True")} returns {@code true}.<br>
* Example: {@code Boolean.parseBoolean("yes")} returns {@code false}.
*
* @param s the {@code String} containing the boolean
* representation to be parsed
* @return the boolean represented by the string argument
* @since 1.5
*/
public static boolean parseBoolean(String s) {
return ((s != null) && s.equalsIgnoreCase("true"));
}
在上面內容中有提到,如果是一個字串型別,比如構造方法中傳入字串型別,那麼判斷是否為空,並且字串是否和true忽略大小寫equals
測試程式碼如下:
//測試parseBoolean方法
Boolean b1 = new Boolean("true");
String str = null;
Boolean b2 = new Boolean(str);
Boolean b3 = new Boolean("TRUE");
Boolean b4= new Boolean("s");
System.out.println("此處只測試構造方法,因為構造方法中用到了具體的parseBoolean方法");
System.out.println(b1);// true
System.out.println(b2);// false
System.out.println(b3);// true
System.out.println(b4);// false
getBoolean方法原始碼如下:
/**
* Returns {@code true} if and only if the system property
* named by the argument exists and is equal to the string
* {@code "true"}. (Beginning with version 1.0.2 of the
* Java<small><sup>TM</sup></small> platform, the test of
* this string is case insensitive.) A system property is accessible
* through {@code getProperty}, a method defined by the
* {@code System} class.
* <p>
* If there is no property with the specified name, or if the specified
* name is empty or null, then {@code false} is returned.
*
* @param name the system property name.
* @return the {@code boolean} value of the system property.
* @throws SecurityException for the same reasons as
* {@link System#getProperty(String) System.getProperty}
* @see java.lang.System#getProperty(java.lang.String)
* @see java.lang.System#getProperty(java.lang.String, java.lang.String)
*/
public static boolean getBoolean(String name) {
boolean result = false;
try {
result = parseBoolean(System.getProperty(name));
} catch (IllegalArgumentException | NullPointerException e) {
}
return result;
}
當且僅當以引數命名的系統屬性存在,且等於 "true" 字串時,才返回 true。(從 JavaTM 1.0.2 平臺開始,字串的測試不再區分大小寫。)通過 getProperty 方法可訪問系統屬性,此方法由 System 類定義。 如果沒有以指定名稱命名的屬性或者指定名稱為空或 null,則返回 false。
測試程式碼如下:
/*
*當且僅當以引數命名的系統屬性存在,且等於 "true" 字串時,才返回 true
*/
//大寫的true返回為false,必須是小寫的true
String s1 = "true";
String s2 = new String("true");
//這裡將s1存放到Java系統屬性中了.
System.setProperty(s1,"true");
System.setProperty(s2,"true");
//這裡從系統屬性中獲取s1,所以獲取到了。
System.out.println(Boolean.getBoolean(s1));//true
System.out.println(Boolean.getBoolean(s2));//true
String s3 = "true";
//很明顯s3並沒有存放到系統屬性中所以返回false。
System.out.println(Boolean.getBoolean(s3));//false
System.out.println(Boolean.getBoolean("true"));//false
以上是針對Boolean類的所有的測試,如果有不到位的地方,還請各位補充。
下面是完成的測試案例:
package test;
/**
* Boolean類的測試案例
* @Package test
* @Title: BooleanDemo.java
* @Company: $
* @author BurgessLee
* @date 2018年9月29日-上午11:36:39
* @Description: $
*/
public class BooleanDemo {
public static void main(String[] args) {
System.out.println(Boolean.TYPE.toString());
//測試parseBoolean方法
Boolean b1 = new Boolean("true");
String str = null;
Boolean b2 = new Boolean(str);
Boolean b3 = new Boolean("TRUE");
Boolean b4= new Boolean("s");
System.out.println("此處只測試構造方法,因為構造方法中用到了具體的parseBoolean方法");
System.out.println(b1);// true
System.out.println(b2);// false
System.out.println(b3);// true
System.out.println(b4);// false
//測試boolean其他的方法
System.out.println("=================其他方法的測試=========================");
System.out.println(Boolean.logicalAnd(true, true));
System.out.println(Boolean.logicalAnd(true, false));
System.out.println(Boolean.logicalAnd(false, true));
System.out.println(Boolean.logicalAnd(false, false));
System.out.println(Boolean.logicalOr(true, true));
System.out.println(Boolean.logicalOr(true, false));
System.out.println(Boolean.logicalOr(false, true));
System.out.println(Boolean.logicalOr(false, false));
System.out.println(Boolean.logicalXor(true, true));
System.out.println(Boolean.logicalXor(true, false));
System.out.println(Boolean.logicalXor(false, true));
System.out.println(Boolean.logicalXor(false, false));
// true
// false
// false
// false
// true
// true
// true
// false
// false
// true
// true
// false
System.out.println("==================getBoolean方法的測試====================");
/*
*當且僅當以引數命名的系統屬性存在,且等於 "true" 字串時,才返回 true
*/
//大寫的true返回為false,必須是小寫的true
String s1 = "true";
String s2 = new String("true");
//這裡將s1存放到Java系統屬性中了.
System.setProperty(s1,"true");
System.setProperty(s2,"true");
//這裡從系統屬性中獲取s1,所以獲取到了。
System.out.println(Boolean.getBoolean(s1));//true
System.out.println(Boolean.getBoolean(s2));//true
String s3 = "true";
//很明顯s3並沒有存放到系統屬性中所以返回false。
System.out.println(Boolean.getBoolean(s3));//false
System.out.println(Boolean.getBoolean("true"));//false
}
}