Google Guava之常见Object方法
文中所述Guava版本基于29.0-jre
,文中涉及到的代码完整示例请移步Github查看。
常见Obejct方法使用
Java中所有的类都有一个隐藏的公共父类,就是Object
类。既然所有的类都继承自Object
类,那所有的类中都包含有Object
类的方法,常见的有。
equals(Object):boolean
hashCode():int
toString():String
notify():void
notifyAll():void
wait():void
wait()long:void
wait(long, int):void
Object
都提供了上述方法的默认实现,但是某些情况下默认的实现不能满足我们的需求,此时就需要一些强大健全的三方实现来满足我们,Guava中提供的一些Object
类常见方法便可以满足我们。
equals
由于所有类都默认继承Object
,同时继承了equals
方法,所以我们在比较对象是否相等的时候可以直接使用
A.equals(B)
来比较(A为null会有异常,B为null可以正常比较结果为false)。由于对null类型使用equals
方式会抛出异常,导致我们在每次使用之前都会进行null判断if (null != A) {}
。使用Guava的Objects.equal(Object, Object):boolean
可以免于我们对对象是否为null的判定,直接使用即可。
Objects.equal(A, A);
Objects.equal(null, A);
Objects.equal(A, null);
Objects.equal(null, null);
/*Output:
true
false
false
true
///:~
注:JDK7引入的Obejcts
类中的Obejcts.equals(Object, Object):boolan
提供同样的功能。
hashCode
计算对象的hash
值是我们在日常编程中经常需要进行的步骤,因为大量使用了对象容器类如Map、Set
等,这些对象容器类判定对象冲突时需要依赖对象的hash
值。而且我们有时还要费心思的设计一个碰撞概率比较小的hash
算法,保证对象hash
值足够分散,同时对拥有相同值的对象计算出相同的hash
值。Guava的Objects.hashCode(Object...):int
提供计算对象hash
值的一般方法,保证在大多数情况下满足我们的需求。
public class Person {
private String name;
private Integer age;
// 省略getter setter和构造函数
@Override
public int hashCode() {
return Objects.hashCode(this.name, this.age);
}
public static void main(String[] args) {
Person alice = new Person("alice", 18);
System.out.println(alice.hashCode());
}
}
/*Output:
-1414972077
///:~
hash方法的实现如下
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
对象是null时hash
值为0,值为null则该值的hash
值为0,其余的值直接调用JDK的native
方法进行hash
值的计算(若是想深入了解可以查询hashCode()
方法在native
的实现)。
注:JDK7引入的Obejcts
类中的Obejcts.hash(Object...):int
提供同样的功能。
toString
toString
方法帮助我们更加详细的打印对象的内部信息,但是默认的实现对于复杂对象直接打印的是对象的内存地址,使用Guava的MoreObjects.toStringHelper
可以轻松编写有用的toString
方法。
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("name", name)
.add("age", age)
.toString();
}
/*Output:
Person{name=alice, age=18}
///:~
对于使用Intellij IDEA
的同学来说,则可以直接借助IDEA提供的快捷功能快速生成toString
方法。
compare/compareTo
Java中对象的比较一般有两种办法,一是继承Comparable
接口并实现compareTo(T o)
方法,另外一种是创建Comparator
类。Guava提供了一种在compareTo(T o)
方法中快速比较对象的功能ComparisonChain
。
public class Person implements Comparable<Person> {
private String name;
private Integer age;
// 省略getter setter和构造函数
@Override
public int compareTo(Person other) {
return ComparisonChain.start()
.compare(this.name, other.name)
.compare(this.age, other.age, Ordering.natural().nullsLast())
.result();
}
}
可以看到,ComparisonChain
以start
方法开启比较,中间是多个compare
方法,最后调用result
返回结果,而且在使用compare
的时候,可以使用Guava提供的Ordering
来实现更多的功能(关于Guava Ordering的介绍请移步Google Guava之Ordering)。
ComparisonChain
执行一种懒比较:它执行比较操作直至发现非零的结果,在那之后的比较输入将被忽略。这句话可能不是那么好理解,我们结合上面的示例来分析这句话。
return ComparisonChain.start() \\ 1
.compare(this.name, other.name) \\ 2
.compare(this.age, other.age, Ordering.natural().nullsLast()) \\ 3
.result(); \\ 4
1处代码开启比较,如果在2处代码比较后结果非零(即this.name小于other.name或this.name大于other.name),3处的代码即忽略执行,直接在4处得到结果。
Guava是如何实现这种懒比较呢?Guava实现此项功能使用了100多行的代码,下面我们来分析这100多行的代码。
public abstract class ComparisonChain {
// 调用start方法返回ACTIVE
private static final ComparisonChain ACTIVE = new ComparisonChain() {
public ComparisonChain compare(Comparable left, Comparable right) {
return this.classify(left.compareTo(right));
}
public <T> ComparisonChain compare(@Nullable T left, @Nullable T right, Comparator<T> comparator) {
return this.classify(comparator.compare(left, right));
}
public ComparisonChain compare(int left, int right) {
return this.classify(Ints.compare(left, right));
}
public ComparisonChain compare(long left, long right) {
return this.classify(Longs.compare(left, right));
}
public ComparisonChain compare(float left, float right) {
return this.classify(Float.compare(left, right));
}
public ComparisonChain compare(double left, double right) {
return this.classify(Double.compare(left, right));
}
public ComparisonChain compareTrueFirst(boolean left, boolean right) {
return this.classify(Booleans.compare(right, left));
}
public ComparisonChain compareFalseFirst(boolean left, boolean right) {
return this.classify(Booleans.compare(left, right));
}
// 所有的compare方法最终都要调用classify方法,classify方法接收的是比较后的值,比较结果为0则返回ComparisonChain.ACTIVE,否则依据结果返回ComparisonChain.LESS或ComparisonChain.GREATER,ComparisonChain.LESS和ComparisonChain.GREATER都是ComparisonChain的子类InactiveComparisonChain实例
ComparisonChain classify(int result) {
return result < 0 ? ComparisonChain.LESS : (result > 0 ? ComparisonChain.GREATER : ComparisonChain.ACTIVE);
}
public int result() {
return 0;
}
};
// LESS使用-1作为构造函数的参数,表示对LESS调用result返回-1
private static final ComparisonChain LESS = new ComparisonChain.InactiveComparisonChain(-1);
// GREATER使用1作为构造函数的参数,表示对GREATER调用result返回1
private static final ComparisonChain GREATER = new ComparisonChain.InactiveComparisonChain(1);
private ComparisonChain() {
}
public static ComparisonChain start() {
return ACTIVE;
}
public abstract ComparisonChain compare(Comparable<?> var1, Comparable<?> var2);
public abstract <T> ComparisonChain compare(@Nullable T var1, @Nullable T var2, Comparator<T> var3);
public abstract ComparisonChain compare(int var1, int var2);
public abstract ComparisonChain compare(long var1, long var3);
public abstract ComparisonChain compare(float var1, float var2);
public abstract ComparisonChain compare(double var1, double var3);
/** @deprecated */
@Deprecated
public final ComparisonChain compare(Boolean left, Boolean right) {
return this.compareFalseFirst(left, right);
}
public abstract ComparisonChain compareTrueFirst(boolean var1, boolean var2);
public abstract ComparisonChain compareFalseFirst(boolean var1, boolean var2);
public abstract int result();
private static final class InactiveComparisonChain extends ComparisonChain {
final int result;
InactiveComparisonChain(int result) {
super(null);
this.result = result;
}
// 一旦内部状态由ACTIVE转为InactiveComparisonChain,后续再调用compare都不再执行真正的比较操作,直接忽略
public ComparisonChain compare(@Nullable Comparable left, @Nullable Comparable right) {
return this;
}
public <T> ComparisonChain compare(@Nullable T left, @Nullable T right, @Nullable Comparator<T> comparator) {
return this;
}
public ComparisonChain compare(int left, int right) {
return this;
}
public ComparisonChain compare(long left, long right) {
return this;
}
public ComparisonChain compare(float left, float right) {
return this;
}
public ComparisonChain compare(double left, double right) {
return this;
}
public ComparisonChain compareTrueFirst(boolean left, boolean right) {
return this;
}
public ComparisonChain compareFalseFirst(boolean left, boolean right) {
return this;
}
public int result() {
return this.result;
}
}
}
ComparisonChain
内部有一个实例ACTIVE
,和一个子类InactiveComparisonChain
,子类InactiveComparisonChain
有两个实例LESS
和GREATER
,比较的过程就是三个实例之间的转变ACTIVE->LESS
或者ACTIVE->GREATER
。
ComparisonChain.start()
调用后返回实例ACTIVE
;- 调用
compare
方法,结果为0则返回新的实例ACTIVE
,结果小于0返回实例LESS
,结果大于0返回实例GREATER
; - 若是步骤2返回的是
ACTIVE
则继续步骤2过程,若返回是LESS
或GREATER
则再调用compare
方法则不进行比较,直接忽略并返回LESS
或GREATER
; - 最后调用
result
返回结果,ACTIVE返回0,LESS返回-1,GREATER返回1
。