在Java中Object类是所有类的父类,其中有几个需要override的方法比如equals,hashCode和toString等方法。每次写这几个方法都要做很多重复性的判断, 很多类库提供了覆写这几个方法的工具类, Guava也提供了类似的方式。下面我们来看看Guava中这几个方法简单使用。

  equals方法:

  equals是一个经常需要覆写的方法, 可以查看Object的equals方法注释, 对equals有几个性质的要求:
    1. 自反性reflexive:任何非空引用x,x.equals(x)返回为true;
    2. 对称性symmetric:任何非空引用x和y,x.equals(y)返回true当且仅当y.equals(x)返回true;
    3. 传递性transitive:任何非空引用x和y,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)返回true;
    4. 一致性consistent:两个非空引用x和y,x.equals(y)的多次调用应该保持一致的结果,(前提条件是在多次比较之间没有修改x和y用于比较的相关信息);
    5. 对于所有非null的值x, x.equals(null)都要返回false。 (如果你要用null.equals(x)也可以,会报NullPointerException)。

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

  1. import org.junit.Test;
  2. import com.google.common.base.Objects;
  3.  
  4. public class ObjectTest {
  5.  
  6. @Test
  7. public void equalTest() {
  8. System.out.println(Objects.equal("a", "a"));
  9. System.out.println(Objects.equal(null, "a"));
  10. System.out.println(Objects.equal("a", null));
  11. System.out.println(Objects.equal(null, null));
  12. }
  13.  
  14. @Test
  15. public void equalPersonTest() {
  16. System.out.println(Objects.equal(new Person("peida",23), new Person("peida",23)));
  17. Person person=new Person("peida",23);
  18. System.out.println(Objects.equal(person,person));
  19. }
  20. }
  21.  
  22. class Person {
  23. public String name;
  24. public int age;
  25.  
  26. Person(String name, int age) {
  27. this.name = name;
  28. this.age = age;
  29. }
  30. }

  运行输出:

  1. true
  2. false
  3. false
  4. true
  5. false
  6. true

  hashCode方法:

  当覆写(override)了equals()方法之后,必须也覆写hashCode()方法,反之亦然。这个方法返回一个整型值(hash code value),如果两个对象被equals()方法判断为相等,那么它们就应该拥有同样的hash code。Object类的hashCode()方法为不同的对象返回不同的值,Object类的hashCode值表示的是对象的地址。
  hashCode的一般性契约(需要满足的条件)如下:
  1.在Java应用的一次执行过程中,如果对象用于equals比较的信息没有被修改,那么同一个对象多次调用hashCode()方法应该返回同一个整型值。应用的多次执行中,这个值不需要保持一致,即每次执行都是保持着各自不同的值。
  2.如果equals()判断两个对象相等,那么它们的hashCode()方法应该返回同样的值。
  3.并没有强制要求如果equals()判断两个对象不相等,那么它们的hashCode()方法就应该返回不同的值。即,两个对象用equals()方法比较返回false,它们的hashCode可以相同也可以不同。但是,应该意识到,为两个不相等的对象产生两个不同的hashCode可以改善哈希表的性能。
  写一个hashCode本来也不是很难,但是Guava提供给我们了一个更加简单的方法--Objects.hashCode(Object ...), 这是个可变参数的方法,参数列表可以是任意数量,所以可以像这样使用Objects.hashCode(field1, field2, ..., fieldn)。非常方便和简洁。

  

  1. import org.junit.Test;
  2. import com.google.common.base.Objects;
  3.  
  4. public class ObjectTest {
  5. @Test
  6. public void hashcodeTest() {
  7. System.out.println(Objects.hashCode("a"));
  8. System.out.println(Objects.hashCode("a"));
  9. System.out.println(Objects.hashCode("a","b"));
  10. System.out.println(Objects.hashCode("b","a"));
  11. System.out.println(Objects.hashCode("a","b","c"));
  12.  
  13. Person person=new Person("peida",23);
  14. System.out.println(Objects.hashCode(person));
  15. System.out.println(Objects.hashCode(person));
  16. }
  17. }
  18.  
  19. class Person {
  20. public String name;
  21. public int age;
  22.  
  23. Person(String name, int age) {
  24. this.name = name;
  25. this.age = age;
  26. }
  27. }
  1. 128
  2. 4066
  3. 4096
  4. 126145
  5. 19313256
  6. 19313256

  toString()方法:

  因为每个类都直接或间接地继承自Object,因此每个类都有toString()方法。这个方法是用得最多的, 覆写得最多, 一个好的toString方法对于调试来说是非常重要的, 但是写起来确实很不爽。Guava也提供了toString()方法。

  

  1. import org.junit.Test;
  2. import com.google.common.base.Objects;
  3.  
  4. public class ObjectTest {
  5.  
  6. @Test
  7. public void toStringTest() {
  8. System.out.println(Objects.toStringHelper(this).add("x", 1).toString());
  9. System.out.println(Objects.toStringHelper(Person.class).add("x", 1).toString());
  10.  
  11. Person person=new Person("peida",23);
  12. String result = Objects.toStringHelper(Person.class)
  13. .add("name", person.name)
  14. .add("age", person.age).toString();
  15. System.out.print(result);
  16. }
  17. }
  18.  
  19. class Person {
  20. public String name;
  21. public int age;
  22.  
  23. Person(String name, int age) {
  24. this.name = name;
  25. this.age = age;
  26. }
  27. }
  28.  
  29. //============输出===============
  30. ObjectTest{x=1}
  31. Person{x=1}
  32. Person{name=peida, age=23}

  compare/compareTo方法:

  CompareTo:compareTo(Object o)方法是java.lang.Comparable<T>接口中的方法,当需要对某个类的对象进行排序时,该类需要实现 Comparable<T>接口的,必须重写public int compareTo(T o)方法。java规定,若a,b是两个对象,当a.compareTo(b)>0时,则a大于b,a.compareTo(b)<0时,a<b,即规定对象的比较大小的规则;
  compare: compare(Object o1,Object o2)方法是java.util.Comparator<T>接口的方法,compare方法内主要靠定义的compareTo规定的对象大小关系规则来确定对象的大小。

  compareTo方法的通用约定与equals类似:将本对象与指定的对象停止比拟,如果本对象小于、等于、或大于指定对象,则分离返回正数、零、或正数。如果指定的对象类型无法与本对象停止比拟,则跑出ClassCastException。
  对称性:实现者必须保证对全部的x和y都有sgn(x.compareTo(y)) == -sgn(y.compareTo(x))。这也暗示当且仅当y.compareTo(x)抛出异常时,x.compareTo(y)才抛出异常。
  传递性:实现者必须保证比拟关系是可传递的,如果x.compareTo(y) > 0且y.compareTo(z) > 0,则x.compareTo(z) > 0。实现者必须保证x.compareTo(y)==0暗示着全部的z都有(x.compareTo(z)) == (y.compareTo(z))。
  虽不强制要求,但强烈建议(x.compareTo(y) == 0) == (x.equals(y))。一般来说,任何实现了Comparable的类如果违背了这个约定,都应该明白说明。推荐这么说:“注意:本类拥有自然顺序,但与equals不一致”。
  第一条指出,如果颠倒两个比拟对象的比拟顺序,就会发生以下情况:如果第一个对象小于第二个对象,则第二个对象必须大于第一个对象;如果第一个对象等于第二个对象,则第二个对象也必须等于第一个对象;如果第一个对象大于第二个对象,则第二个对象小于第一个对象。
  第二条指出,如果第一个对象大于第二个对象,第二个对象大于第三个对象,则第一个大于第三个。
  第三条指出,对于两个相称的对象,他们与其他任何对象比拟结果应该雷同。
  这三条约定的一个结果是,compareTo方法的等同性测试必须与equals方法满意雷同的约束条件:自反性、对称性、传递性。所以也存在类同的约束:不能在扩展一个可实例化的类并添加新的值组件时,同时保证compareTo的约定,除非你愿意放弃面向对象抽象的优势。可以用与equals雷同的规避措施:如果想在实现Comparable接口的类中增加一个值组件,就不要扩展它;应该写一个不相干的类,其中包括第一个类的实例。然后供给一个view方法返回该实例。这样你就可以再第二个类上实现任何compareTo方法,同时允许客户在须要的时候将第二个类看成是第一个类的一个实例。
  compareTo约定的最后一段是一个强烈的建议而非真正的约定,即compareTo方法的等同性测试必须与equals方法的结果雷同。如果遵照了这一条,则称compareTo方法所施加的顺序与equals一致;反之则称为与equals不一致。当然与equals不一致的compareTo方法仍然是可以工作的,但是,如果一个有序集合包括了该类的元素,则这个集合可能就不能遵照响应集合接口(Collection、Set、Map)的通用约定。这是因为这些接口的通用约定是基于equals方法的,但是有序集合却使用了compareTo而非equals来执行。

  下面我们简单自己实现一个类的compareTo方法:

  1. import org.junit.Test;
  2.  
  3. public class ObjectTest {
  4.  
  5. @Test
  6. public void compareTest(){
  7. Person person=new Person("peida",23);
  8. Person person1=new Person("aida",25);
  9. Person person2=new Person("aida",25);
  10. Person person3=new Person("aida",26);
  11. Person person4=new Person("peida",26);
  12.  
  13. System.out.println(person.compareTo(person1));
  14. System.out.println(person1.compareTo(person2));
  15. System.out.println(person1.compareTo(person3));
  16. System.out.println(person.compareTo(person4));
  17. System.out.println(person4.compareTo(person));
  18. }
  19. }
  20.  
  21. class Person implements Comparable<Person>{
  22. public String name;
  23. public int age;
  24.  
  25. Person(String name, int age) {
  26. this.name = name;
  27. this.age = age;
  28. }
  29.  
  30. @Override
  31. public int compareTo(Person other) {
  32. int cmpName = name.compareTo(other.name);
  33. if (cmpName != 0) {
  34. return cmpName;
  35. }
  36. if(age>other.age){
  37. return 1;
  38. }
  39. else if(age<other.age){
  40. return -1;
  41. }
  42. return 0;
  43. }
  44. }
  1. //========输出===========
    15
  2. 0
  3. -1
  4. -1
  5. 1

  上面的compareTo方法,代码看上去并不是十分优雅,如果实体属性很多,数据类型丰富,代码可读性将会很差。在guava里, 对所有原始类型都提供了比较的工具函数来避免这个麻烦. 比如对Integer, 可以用Ints.compare()。利用guava的原始类型的compare,我们对上面的方法做一个简化,实现compare方法:

  1. class PersonComparator implements Comparator<Person> {
  2. @Override
  3. public int compare(Person p1, Person p2) {
  4. int result = p1.name.compareTo(p2.name);
  5. if (result != 0) {
  6. return result;
  7. }
  8. return Ints.compare(p1.age, p2.age);
  9. }
  10. }

  上面的代码看上去简单了一点,但还是不那么优雅简单,对此, guava有一个相当聪明的解决办法, 提供了ComparisonChain:

  1. class Student implements Comparable<Student>{
  2. public String name;
  3. public int age;
  4. public int score;
  5.  
  6. Student(String name, int age,int score) {
  7. this.name = name;
  8. this.age = age;
  9. this.score=score;
  10. }
  11.  
  12. @Override
  13. public int compareTo(Student other) {
  14. return ComparisonChain.start()
  15. .compare(name, other.name)
  16. .compare(age, other.age)
  17. .compare(score, other.score, Ordering.natural().nullsLast())
  18. .result();
  19. }
  20. }
  21.  
  22. class StudentComparator implements Comparator<Student> {
  23. @Override public int compare(Student s1, Student s2) {
  24. return ComparisonChain.start()
  25. .compare(s1.name, s2.name)
  26. .compare(s1.age, s2.age)
  27. .compare(s1.score, s2.score)
  28. .result();
  29. }
  30. }
  31. }

  ComparisonChain是一个lazy的比较过程, 当比较结果为0的时候, 即相等的时候, 会继续比较下去, 出现非0的情况, 就会忽略后面的比较。ComparisonChain实现的compare和compareTo在代码可读性和性能上都有很大的提高。

  下面来一个综合应用实例:

  1. import java.util.Comparator;
  2.  
  3. import org.junit.Test;
  4.  
  5. import com.google.common.base.Objects;
  6. import com.google.common.collect.ComparisonChain;
  7. import com.google.common.collect.Ordering;
  8.  
  9. public class ObjectTest {
  10.  
  11. @Test
  12. public void StudentTest(){
  13.  
  14. Student student=new Student("peida",23,80);
  15. Student student1=new Student("aida",23,36);
  16. Student student2=new Student("jerry",24,90);
  17. Student student3=new Student("peida",23,80);
  18.  
  19. System.out.println("==========equals===========");
  20. System.out.println(student.equals(student2));
  21. System.out.println(student.equals(student1));
  22. System.out.println(student.equals(student3));
  23.  
  24. System.out.println("==========hashCode===========");
  25. System.out.println(student.hashCode());
  26. System.out.println(student1.hashCode());
  27. System.out.println(student3.hashCode());
  28. System.out.println(student2.hashCode());
  29.  
  30. System.out.println("==========toString===========");
  31. System.out.println(student.toString());
  32. System.out.println(student1.toString());
  33. System.out.println(student2.toString());
  34. System.out.println(student3.toString());
  35.  
  36. System.out.println("==========compareTo===========");
  37. System.out.println(student.compareTo(student1));
  38. System.out.println(student.compareTo(student2));
  39. System.out.println(student2.compareTo(student1));
  40. System.out.println(student2.compareTo(student));
  41.  
  42. }
  43.  
  44. }
  45.  
  46. class Student implements Comparable<Student>{
  47. public String name;
  48. public int age;
  49. public int score;
  50.  
  51. Student(String name, int age,int score) {
  52. this.name = name;
  53. this.age = age;
  54. this.score=score;
  55. }
  56.  
  57. @Override
  58. public int hashCode() {
  59. return Objects.hashCode(name, age);
  60. }
  61.  
  62. @Override
  63. public boolean equals(Object obj) {
  64. if (obj instanceof Student) {
  65. Student that = (Student) obj;
  66. return Objects.equal(name, that.name)
  67. && Objects.equal(age, that.age)
  68. && Objects.equal(score, that.score);
  69. }
  70. return false;
  71. }
  72.  
  73. @Override
  74. public String toString() {
  75. return Objects.toStringHelper(this)
  76. .addValue(name)
  77. .addValue(age)
  78. .addValue(score)
  79. .toString();
  80. }
  81.  
  82. @Override
  83. public int compareTo(Student other) {
  84. return ComparisonChain.start()
  85. .compare(name, other.name)
  86. .compare(age, other.age)
  87. .compare(score, other.score, Ordering.natural().nullsLast())
  88. .result();
  89. }
  90. }
  91.  
  92. class StudentComparator implements Comparator<Student> {
  93. @Override public int compare(Student s1, Student s2) {
  94. return ComparisonChain.start()
  95. .compare(s1.name, s2.name)
  96. .compare(s1.age, s2.age)
  97. .compare(s1.score, s2.score)
  98. .result();
  99. }
  100. }
  101.  
  102. //=============运行输出===========================
  103. ==========equals===========
  104. false
  105. false
  106. true
  107. ==========hashCode===========
  108. -991998617
  109. 92809683
  110. -991998617
  111. -1163491205
  112. ==========toString===========
  113. Student{peida, 23, 80}
  114. Student{aida, 23, 36}
  115. Student{jerry, 24, 90}
  116. Student{peida, 23, 80}
  117. ==========compareTo===========
  118. 1
  119. 1
  120. 1
  121. -1

  

Guava学习笔记:复写的Object常用方法的更多相关文章

  1. Guava学习笔记目录

    Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libra ...

  2. guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁

    guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁 1,本文翻译自 http://eclipsesource.com/blogs/2012/06/06/cleaner-code- ...

  3. guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用

    guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用 1,大纲 让我们来熟悉瓜娃,并体验下它的一些API,分成如下几个部分: Introduction Guava Collection ...

  4. 复写的Object常用方法

    复写的Object常用方法 在Java中Object类是所有类的父类,其中有几个需要override的方法比如equals,hashCode和toString等方法.每次写这几个方法都要做很多重复性的 ...

  5. Google Guava学习笔记——基础工具类针对Object类的使用

    Guava 提供了一系列针对Object操作的方法. 1. toString方法 为了方便调试重写toString()方法是很有必要的,但写起来比较无聊,不管如何,Objects类提供了toStrin ...

  6. Guava学习笔记(一)概览

    Guava是谷歌开源的一套Java开发类库,以简洁的编程风格著称,提供了很多实用的工具类, 在之前的工作中应用过Collections API和Guava提供的Cache,不过对Guava没有一个系统 ...

  7. Guava学习笔记:Google Guava 类库简介

    http://www.cnblogs.com/peida/tag/Guava/ Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, cachin ...

  8. Guava学习笔记(3):复写的Object常用方法

    转自:http://www.cnblogs.com/peida/p/Guava_Objects.html 在Java中Object类是所有类的父类,其中有几个需要override的方法比如equals ...

  9. [Guava学习笔记]Basic Utilities: Null, 前置条件, Object方法, 排序, 异常

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3842433.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

随机推荐

  1. DataGrid--多记录CRUD

    最近在做一个datagrid,但因为引用的Jquery,加上初学者,所以难免费尽周折.现在将完整版贴出来,跟大家分享,一起切磋,也方便自己回顾学习. ps:第一次发帖,不知排版效果如何,瑕疵勿怪. 首 ...

  2. Oracle 11g系列:数据库

    1.创建Oracle数据库 创建Oracle数据库的最常用工具为Database Configuration Assistant(数据库配置助手),依次选择[开始]|[所有程序]|[Oracle-Or ...

  3. Geometry Curve of OpenCascade BRep

    Geometry Curve of OpenCascade BRep eryar@163.com 摘要Abstract:几何曲线是参数表示的曲线 ,在边界表示中其数据存在于BRep_TEdge中,BR ...

  4. 【Discuz】关闭QQ互联插件提示信息:系统繁忙,请稍后再试

    版本:X3.2.20160601 提示信息 系统繁忙,请稍后再试 解决方案 Step1.删除QQ互联插件目录 网站的根目录\source\plugin\qqconnect Step2.上传原始QQ互联 ...

  5. Shell最多可以输入多少个参数?

    在脚本编写过程中,通常会涉及到参数的输入.譬如,sh 1.sh 10 20,在执行1.sh这个脚本中,10即为第一个参数,20即为第二个参数.有时,就会有这个疑惑,即shell脚本最多可以支持多少个变 ...

  6. Windows Azure Affinity Groups (3) 修改虚拟网络地缘组(Affinity Group)的配置

    <Windows Azure Platform 系列文章目录> 本文介绍的是国内使用世纪互联运维的Azure China 在笔者之前的文章中,我们知道现在微软官方不建议使用Affinity ...

  7. Elasticsearch——禁止Body中的index覆盖Url中的index参数

    本篇继续一下Elasticsearch日常使用的技巧翻译. 在Elasticsearch有很多的api支持在body中指定_index等信息,比如mget或者msearch以及bulk. 默认的情况下 ...

  8. 用Latex写学术论文: IEEE Latex模板和文档设置(\documentclass)

    1.可以在博客园中使用latex代码输出公式,以后再以不用复制图片粘贴啦: http://www.cnblogs.com/cmt/p/3279312.html 例如以下代码两边加上 $ 符号后 x(k ...

  9. Struts2 源码分析——Hello world

    新建第一个应用程序 上一章我们讲到了关于struts2核心机制.对于程序员来讲比较概念的一章.而本章笔者将会亲手写一个Hello world的例子.所以如果对struts2使用比较了解的朋友,请跳过本 ...

  10. PyQt写的五子棋

    技术路线 GUI的实现 使用PyQt技术作为基础.PyQt是一个支持多平台的客户端开发SDK,使用它实现的客户端可以运行在目前几乎所有主流平台之上. 使用PyQt,Qt设计器实现UI,通过pyuic4 ...