欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JDK源码解读(第二弹:Boolean)

程序员文章站 2022-07-14 17:27:20
...

我们知道有个基本类型叫boolean,它的值只有两种,true或者false。Boolean类正是对基本类型boolean进行了封装,提供了一些常用的方法。

看源码之前建议先看一下API文档,或者边看源码边看API,这样可以更好的理解。可以直接去看官方的API文档,也可以看我的上一篇文章,是对API文档的翻译,连接如下:https://blog.csdn.net/lianjiww/article/details/82230178

源码很容易获取,大家都知道怎么看,但是考虑到手头不方便打开IDE的同学以及为了方便对照阅读,这里先贴上源码:

package java.lang;

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

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

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

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

    private final boolean value;

    private static final long serialVersionUID = -3665804199014368530L;

    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";
    }

    @Override
    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 static boolean getBoolean(String name) {
        boolean result = false;
        try {
            result = parseBoolean(System.getProperty(name));
        } catch (IllegalArgumentException | NullPointerException e) {
        }
        return result;
    }

    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;
    }
}

以上源码我把注释全都去掉了,因为这些注释就是API文档的内容,对于API,上一篇文章中已经进行过了翻译,所以这里就直接来看源码了。

API中说了,Boolean是对基本类型boolean的封装,那么必然要有一个变量用来保存boolean的值,这个变量就是的value,代码如下:
private final boolean value;
注意它是final的,不可变。

他有两个构造函数:

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

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

可分别传入boolean和String类型。但是要注意,对于String类型,当传入的字符串等于”true”(不分大小写)时判断为true,否则为false。这是通过parseBoolean实现的:

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

但是实际使用的时候,API文档中明确说明并不推荐使用构造函数,而是推荐使用静态工厂valueOf方法。方法源码如下:

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

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

但是这和使用构造函数又有什么区别?

我们知道boolean和其他对象不同,它只有两种值,要么是true,要么是false。那么作为一个boolean的封装对象,Boolean类在全局只需要有两个实例即可,一个代表true,一个代表false。这两个对象就是:

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

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

如果使用构造函数创建出更多的对象,无非还是true或false,只是耗费了更多的空间和性能,没什么大用 。
所以如果需要一个true,一般不用new Boolean(true),而是使用Boolean.valueOf(true)Boolean.valueOf("true"),或者直接使用Boolean.TRUE,这样不会有新的对象产生。

在这里我们先不继续往下看源码,停下来想一想,上面Boolean的这两个静态变量其实体现了一种非常好的设计思想。
如果我们的一个类只允许有少量的几种值,那就可以用几个static final的变量来表示这几个实例,而不用每次都new一个新的对象出来。
比如一周只可能有7天,那如果我们有一个Weekday的类,可以在Weekday里来一个static final的MONDAY属性, 想得到一个周一的实例,只要使用Weekday.MONDAY即可,而不用new一个新的对象出来。
甚至可以取消public的构造方法,只提供静态工厂方法,这样就强制使用静态属性或静态工厂方法,而无法使用构造函数来new一个新的对象。这样还有一个好处就是,因为实例就只有固定的那几个,所以equal方法可以直接用 ==来判断,超级简单。

接着往下看源码,hashcode:

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

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

hashcode值也只有两种,true的时候是1231,false的时候是1237。
之前分析Object源码的时候,我们知道了hashcode是用来干嘛的。简单的说,hashCode是为了提高散列表的性能,它会决定对象在散列表中的存放位置,我们需要每个对象的hashcode尽可能的不重复。
所以true和false的hashcode就需要是两个不能太小也不能太大的质数,太小了容易重复,太大了浪费空间。1231和1237则满足这样的条件。当然了 ,这样的质数还有很多,并不是非要使用这两个质数才行,但为什么Boolean的设计者恰恰就使用了1231和1237这两个质数,估计得去问设计者本人了。

再来看equals的源码:

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

很简单,就是先判断是不是Boolean的实例,然后再判断值相不相等。

再来看一下比较方法:

    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);
    }

Boolean实现Comparable接口是为了方便在集合中进行比较,需要实现的方法就是这个compareTo。

我们注意到Boolean中还有一个静态属性TYPE
public static final Class<Boolean> TYPE = (Class<Boolean>) Class.getPrimitiveClass("boolean");
不多说,看一下以下代码的输出就明白了:

System.out.println(Boolean.class);  -- 输出class java.lang.Boolean
System.out.println(boolean.class);  -- 输出boolean
System.out.println(Boolean.TYPE);   -- 输出boolean

其余的几个方法,toString以及逻辑操作的几个方法都很简单,没什么好看的。