02 从JDK源码角度看Boolean
Java的Boolean类主要作用就是对基本类型boolean进行封装,提供了一些处理boolean类型的方法,比如String类型和boolean类型的转换。
主要实现源码如下图所示,具体实现代码可自行查看对应的代码。
既然是对基本类型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.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
}
}