Guava源码分析——Objects
Objects工具类,可以分为两部分来分析。一部分是equals()和hashcode()方法的支持。另一部分是toString()和compareTo()的链式调用的支持。
对于equals()方法,Guava的Objects类提供了如下支持:
public static boolean equal(@Nullable Object a, @Nullable Object b){ return a == b || (a != null && a.equals(b)); }
对于hashcode()方法,Guava的Objects类提供了如下支持:
public static int hashCode(@Nullable Object... objects) { return Arrays.hashCode(objects); }
equal()方法的实现,比较简单,采用Objects.equal(a,b),很巧妙的避免了a.equals(b)时,NullPointerException的出现。
hashcode()方法的实现,也是比较简单。
一般情况下,重写hashcode()和equals()方法的时候都会使用IDE直接生成,如下所示:
public class Person { private int id; private String name; private int age; @Override public int hashCode() { int result = id; result = 31 * result + (name != null ? name.hashCode() : 0); result = 31 * result + age; return result; } }
可以看出重写后的方法会让使用者很困惑,究竟哪些字段参与了比较。而Objects中的hashcode()方法可以很好的解决这个问题。如下代码所示:
public class Person { private int id; private String name; private int age; @Override public int hashCode() { return Objects.hashCode(id, name, age); } }
需要注意的是。在Java7后,Guava让我们使用java.util.Objects,替代Guava的Objects,API参数是一样的。
Objects另一个需要阐述的地方,是对toString()和compare()方法的支持。
对于toString()方法的链式调用的支持。如下代码所示:
public class Person { private int id; private String name; private int age; @Override public String toString() { return MoreObjects.toStringHelper(this).add("id", id).add("name", name).add("age", age).toString(); } }
下面,我们分析一下MoreObjects.toStringHelper的实现
public static ToStringHelper toStringHelper(Object self) { return new ToStringHelper(simpleName(self.getClass())); }
静态方法直接返回ToStringHelper对象,接下来链式调用add(name,value)方法,而ToStringHelper内部维护一个ValueHolder(name, value,next结构)链表,记录add(name,value)的所有内容
public static final class ToStringHelper { private final String className; private ValueHolder holderHead = new ValueHolder(); private ValueHolder holderTail = holderHead; private boolean omitNullValues = false; }
private ToStringHelper addHolder(String name, @Nullable Object value) { ValueHolder valueHolder = addHolder(); valueHolder.value = value; valueHolder.name = checkNotNull(name); return this; }
还有一个方法。简单说明一下,代码如下:
public ToStringHelper omitNullValues() { omitNullValues = true; return this; }
这里omitNullValues是一个开关,控制是否在ToStringHelper.toString()的时候输出null值。
另一个就是对于compare的重写,这个实现的很是巧妙
@Override public int compareTo(Person o) { return ComparisonChain.start().compare(id, o.id).compare(name, o.name).compare(age, o.age).result(); }
在ComparisonChain中,有三个内部常量
private static final ComparisonChain ACTIVE = new ComparisonChain(); private static final ComparisonChain LESS = new InactiveComparisonChain(-1); private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
在ACTIVE实现中,才真正实现了compare的比较逻辑是就是classify()方法
ComparisonChain classify(int result) { return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE; }
LESS和GREATER的区别仅仅在于,构造参数中传入的int(result)值不同,而在InactiveComparisonChain内部实现中,compare方法仅仅返回this,而不去真正执行比较逻辑,因为此阶段的比较结果如果是LESS或是GREATER,最终ComparisonChain的结果也就决定了。而后续的比较没有意义。
private static final class InactiveComparisonChain extends ComparisonChain { final int result; InactiveComparisonChain(int result) { this.result = result; } @Override public ComparisonChain compare( @Nullable Comparable left, @Nullable Comparable right) { return this; } @Override public <T> ComparisonChain compare(@Nullable T left, @Nullable T right, @Nullable Comparator<T> comparator) { return this; } @Override public ComparisonChain compare(int left, int right) { return this; } @Override public ComparisonChain compare(long left, long right) { return this; } @Override public ComparisonChain compare(float left, float right) { return this; } @Override public ComparisonChain compare(double left, double right) { return this; } @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) { return this; } @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) { return this; } @Override public int result() { return result; } }