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.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>

以下是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
	}

}

猜你喜欢

转载自blog.csdn.net/Burgess_Lee/article/details/82894441
02
今日推荐