代码改变世界

Guava学习笔记(3)--覆写Object的常用方法[翻译+学习笔记]

2012-06-30 17:43  会被淹死的鱼  阅读(1123)  评论(1编辑  收藏  举报

Java的Object是所有类的父类, 也有几个常用的需要覆写的方法, 比如equals, hashCode和toString.

每次写这几个方法都要做很多重复性的判断, 很多类库提供了覆写这几个方法的工具类, 比如apache commons lang.

Guava也提供了类似的方式, 在JDK7也提供了和Guava类似的方法.

equals

equals是一个经常需要覆写的方法, 可以查看Object的equals方法注释, 对equals有几个性质的要求: 自反性reflexive, 对称性symmetric, 传递性transitive, 一致性consistent. 还有一个要求: 对于所有非null的值x, x.equals(null)都要返回false. (如果你要用null.equals(x)也可以, 会报NullPointerException)

当我们要覆写的类中某些值可能为null的时候, 就需要对null做很多判断和分支处理. 使用Guava的Objects.equal方法可以避免这个问题, 使得equals的方法的覆写变得更加容易, 而且可读性强, 简洁.

Objects.equal("a", "a"); // returns true
Objects.equal(null, "a"); // returns false
Objects.equal("a", null); // returns false
Objects.equal(null, null); // returns true

 JDK7新引入了Objects类, 其中有类似的方法equals.

hashCode

要求equals返回true的值, hashCode也返回相同的值. 所以覆写equals方法, 一般都要覆写hashCode方法.

写一个hashCode本来也不是很难, 但是Guava提供给我们了一个更加简单的方法--Objects.hashCode(Object ...), 这是个可变参数的方法, 参数列表可以是任意数量, 所以可以像这样使用Objects.hashCode(field1, field2, ..., fieldn).非常方便和简洁.

JDK7新引入了Objects类, 其中有类似的方法hash.

toString

这个方法是用得最多的, 覆写得最多, 一个好的toString方法对于调试来说是非常重要的, 但是写起来确实很不爽. 幸好我们可以用eclipse的自动生成代码的功能, 也可以使用apache commons lang来自动生成(使用反射), 当然Guava也提供了方法.

   // Returns "ClassName{x=1}"
   Objects.toStringHelper(this)
       .add("x", 1)
       .toString();

   // Returns "MyObject{x=1}"
   Objects.toStringHelper("MyObject")
       .add("x", 1)
       .toString();

 commons lang的生成方式使用了反射, 效率可能会低一点, 但是有个好处, 修改了类中的成员变量, 不需要修改toString方法, 因为是用的反射. 这个还是很方便的.

compare/compareTo

实现Comparator或Comparable接口, 可以实现比较功能, 但是这个方法却并不好重写, 写过的人都知道. 为了简化, Guava提供了ComparisonChain.

ComparisonChain是一个lazy的比较过程, 当比较结果为0的时候, 即相等的时候, 会继续比较下去, 出现非0的情况, 就会忽略后面的比较.

   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(this.aString, that.aString)
         .compare(this.anInt, that.anInt)
         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
         .result();
   }

 下面是一个完整的示例, 展示了这几个方法的使用

import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering;

public class Person implements Comparable<Person> {
	public String name;
	public String nickname;
	public Gender gender;
	
	public Person(String name, String nickname, Gender gender) {
		super();
		this.name = name;
		this.nickname = nickname;
		this.gender = gender;
	}
	
	@Override
	public int hashCode() {
		return Objects.hashCode(name, nickname);
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Person) {
			Person that = (Person) obj;
			return Objects.equal(name, that.name)
					&& Objects.equal(nickname, that.nickname)
					&& Objects.equal(gender, that.gender);
		}
		return false;
	}
//	@Override
//	public String toString() {
//		return Objects.toStringHelper(this)
//				.add("name", name)
//				.add("nickname", nickname)
//				.add("gender", gender)
//				.toString();
//	}
	@Override
	public String toString() {
		return Objects.toStringHelper(this)
				.addValue(name)
				.addValue(nickname)
				.toString();
	}
	
	public String preferredName() {
		return Objects.firstNonNull(nickname, name);
	}
	
	@Override
	public int compareTo(Person that) {
		return ComparisonChain.start()
		         .compare(this.name, that.name)
		         .compare(this.nickname, that.nickname)
		         .compare(this.gender, that.gender, Ordering.natural().nullsLast())
		         .result();
	}
	
	public static void main(String[] args) {
		Person person = new Person("Jack", "Jackson", Gender.MALE);
		System.out.println(person);
		Person person2 = new Person("Jack", "Jackson", Gender.FEMALE);
		System.out.println(person2.compareTo(person));
		System.out.println(person2.equals(person));
	}
}

 因本人水平有限, 欢迎拍砖!

 

参考资料:

  1. 官方wiki: http://code.google.com/p/guava-libraries/wiki/GuavaExplained
  2. Object common methods: http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained