Guava学习笔记(3):复写的Object常用方法
转自:http://www.cnblogs.com/peida/p/Guava_Objects.html
在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的方法的覆写变得更加容易, 而且可读性强,简洁优雅。
import org.junit.Test;
import com.google.common.base.Objects; public class ObjectTest { @Test
public void equalTest() {
System.out.println(Objects.equal("a", "a"));
System.out.println(Objects.equal(null, "a"));
System.out.println(Objects.equal("a", null));
System.out.println(Objects.equal(null, null));
} @Test
public void equalPersonTest() {
System.out.println(Objects.equal(new Person("peida",23), new Person("peida",23)));
Person person=new Person("peida",23);
System.out.println(Objects.equal(person,person));
}
} class Person {
public String name;
public int age; Person(String name, int age) {
this.name = name;
this.age = age;
}
}
运行输出:
true
false
false
true
false
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)。非常方便和简洁。
import org.junit.Test;
import com.google.common.base.Objects; public class ObjectTest {
@Test
public void hashcodeTest() {
System.out.println(Objects.hashCode("a"));
System.out.println(Objects.hashCode("a"));
System.out.println(Objects.hashCode("a","b"));
System.out.println(Objects.hashCode("b","a"));
System.out.println(Objects.hashCode("a","b","c")); Person person=new Person("peida",23);
System.out.println(Objects.hashCode(person));
System.out.println(Objects.hashCode(person));
}
} class Person {
public String name;
public int age; Person(String name, int age) {
this.name = name;
this.age = age;
}
}
128
4066
4096
126145
19313256
19313256
toString()方法:
因为每个类都直接或间接地继承自Object,因此每个类都有toString()方法。这个方法是用得最多的, 覆写得最多, 一个好的toString方法对于调试来说是非常重要的, 但是写起来确实很不爽。Guava也提供了toString()方法。
import org.junit.Test;
import com.google.common.base.Objects; public class ObjectTest { @Test
public void toStringTest() {
System.out.println(Objects.toStringHelper(this).add("x", 1).toString());
System.out.println(Objects.toStringHelper(Person.class).add("x", 1).toString()); Person person=new Person("peida",23);
String result = Objects.toStringHelper(Person.class)
.add("name", person.name)
.add("age", person.age).toString();
System.out.print(result);
}
} class Person {
public String name;
public int age; Person(String name, int age) {
this.name = name;
this.age = age;
}
} //============输出===============
ObjectTest{x=1}
Person{x=1}
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方法:
import org.junit.Test; public class ObjectTest { @Test
public void compareTest(){
Person person=new Person("peida",23);
Person person1=new Person("aida",25);
Person person2=new Person("aida",25);
Person person3=new Person("aida",26);
Person person4=new Person("peida",26); System.out.println(person.compareTo(person1));
System.out.println(person1.compareTo(person2));
System.out.println(person1.compareTo(person3));
System.out.println(person.compareTo(person4));
System.out.println(person4.compareTo(person));
}
} class Person implements Comparable<Person>{
public String name;
public int age; Person(String name, int age) {
this.name = name;
this.age = age;
} @Override
public int compareTo(Person other) {
int cmpName = name.compareTo(other.name);
if (cmpName != 0) {
return cmpName;
}
if(age>other.age){
return 1;
}
else if(age<other.age){
return -1;
}
return 0;
}
}

//========输出===========
15
0
-1
-1
1

上面的compareTo方法,代码看上去并不是十分优雅,如果实体属性很多,数据类型丰富,代码可读性将会很差。在guava里, 对所有原始类型都提供了比较的工具函数来避免这个麻烦. 比如对Integer, 可以用Ints.compare()。利用guava的原始类型的compare,我们对上面的方法做一个简化,实现compare方法:
class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
int result = p1.name.compareTo(p2.name);
if (result != 0) {
return result;
}
return Ints.compare(p1.age, p2.age);
}
}
上面的代码看上去简单了一点,但还是不那么优雅简单,对此, guava有一个相当聪明的解决办法, 提供了ComparisonChain:
class Student implements Comparable<Student>{
public String name;
public int age;
public int score; Student(String name, int age,int score) {
this.name = name;
this.age = age;
this.score=score;
} @Override
public int compareTo(Student other) {
return ComparisonChain.start()
.compare(name, other.name)
.compare(age, other.age)
.compare(score, other.score, Ordering.natural().nullsLast())
.result();
}
} class StudentComparator implements Comparator<Student> {
@Override public int compare(Student s1, Student s2) {
return ComparisonChain.start()
.compare(s1.name, s2.name)
.compare(s1.age, s2.age)
.compare(s1.score, s2.score)
.result();
}
}
}
ComparisonChain是一个lazy的比较过程, 当比较结果为0的时候, 即相等的时候, 会继续比较下去, 出现非0的情况, 就会忽略后面的比较。ComparisonChain实现的compare和compareTo在代码可读性和性能上都有很大的提高。
下面来一个综合应用实例:
import java.util.Comparator; import org.junit.Test; import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering; public class ObjectTest { @Test
public void StudentTest(){ Student student=new Student("peida",23,80);
Student student1=new Student("aida",23,36);
Student student2=new Student("jerry",24,90);
Student student3=new Student("peida",23,80); System.out.println("==========equals===========");
System.out.println(student.equals(student2));
System.out.println(student.equals(student1));
System.out.println(student.equals(student3)); System.out.println("==========hashCode===========");
System.out.println(student.hashCode());
System.out.println(student1.hashCode());
System.out.println(student3.hashCode());
System.out.println(student2.hashCode()); System.out.println("==========toString===========");
System.out.println(student.toString());
System.out.println(student1.toString());
System.out.println(student2.toString());
System.out.println(student3.toString()); System.out.println("==========compareTo===========");
System.out.println(student.compareTo(student1));
System.out.println(student.compareTo(student2));
System.out.println(student2.compareTo(student1));
System.out.println(student2.compareTo(student)); } } class Student implements Comparable<Student>{
public String name;
public int age;
public int score; Student(String name, int age,int score) {
this.name = name;
this.age = age;
this.score=score;
} @Override
public int hashCode() {
return Objects.hashCode(name, age);
} @Override
public boolean equals(Object obj) {
if (obj instanceof Student) {
Student that = (Student) obj;
return Objects.equal(name, that.name)
&& Objects.equal(age, that.age)
&& Objects.equal(score, that.score);
}
return false;
} @Override
public String toString() {
return Objects.toStringHelper(this)
.addValue(name)
.addValue(age)
.addValue(score)
.toString();
} @Override
public int compareTo(Student other) {
return ComparisonChain.start()
.compare(name, other.name)
.compare(age, other.age)
.compare(score, other.score, Ordering.natural().nullsLast())
.result();
}
} class StudentComparator implements Comparator<Student> {
@Override public int compare(Student s1, Student s2) {
return ComparisonChain.start()
.compare(s1.name, s2.name)
.compare(s1.age, s2.age)
.compare(s1.score, s2.score)
.result();
}
} //=============运行输出===========================
==========equals===========
false
false
true
==========hashCode===========
-991998617
92809683
-991998617
-1163491205
==========toString===========
Student{peida, 23, 80}
Student{aida, 23, 36}
Student{jerry, 24, 90}
Student{peida, 23, 80}
==========compareTo===========
1
1
1
-1
Guava学习笔记(3):复写的Object常用方法的更多相关文章
- Guava学习笔记:复写的Object常用方法
在Java中Object类是所有类的父类,其中有几个需要override的方法比如equals,hashCode和toString等方法.每次写这几个方法都要做很多重复性的判断, 很多类库提供了覆写这 ...
- Guava学习笔记目录
Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libra ...
- guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁
guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁 1,本文翻译自 http://eclipsesource.com/blogs/2012/06/06/cleaner-code- ...
- guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用
guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用 1,大纲 让我们来熟悉瓜娃,并体验下它的一些API,分成如下几个部分: Introduction Guava Collection ...
- 复写的Object常用方法
复写的Object常用方法 在Java中Object类是所有类的父类,其中有几个需要override的方法比如equals,hashCode和toString等方法.每次写这几个方法都要做很多重复性的 ...
- Guava学习笔记(一)概览
Guava是谷歌开源的一套Java开发类库,以简洁的编程风格著称,提供了很多实用的工具类, 在之前的工作中应用过Collections API和Guava提供的Cache,不过对Guava没有一个系统 ...
- Guava学习笔记:Google Guava 类库简介
http://www.cnblogs.com/peida/tag/Guava/ Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, cachin ...
- java WEB学习笔记32:HttpSession 接口常用方法 及 HttpServletRequest接口中的Session方法 Demo
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
- Google Guava学习笔记——基础工具类针对Object类的使用
Guava 提供了一系列针对Object操作的方法. 1. toString方法 为了方便调试重写toString()方法是很有必要的,但写起来比较无聊,不管如何,Objects类提供了toStrin ...
随机推荐
- RabbitMQ headers Exchange
Headers Exchange headers也是一种交换机类型,但是在rabbitmq官网中的教程中并没有说到.资料也很少,但是找一找总会有的. headers与direct的模式不同,不是使用r ...
- python学习笔记-(十五)RabbitMQ队列
rabbitMQ是消息队列:想想之前的我们学过队列queue:threading queue(线程queue,多个线程之间进行数据交互).进程queue(父进程与子进程进行交互或者同属于同一父进程下的 ...
- jquery,php之间的ajax关系以及json
1.最简介写法 function AjaxDepotGoods(id){ $.ajax({ url:"{:U('stock/depot_goods')}", success:fun ...
- 利用Render Texture实现游戏的小雷达效果(摄影机分屏)
最近游戏蛮牛在举办一个活动,就是要做出这样的效果: 题目:实现游戏分屏效果 要求:1. 分屏,且分割线不规则(即非水平或垂直):2. 各屏可单独操作(移动.缩放),操作指该 ...
- 【译文】Java Logging
本文讲Java内置的java.util.logging软件包中的 api.主要解释怎样使用该api添加logging到你的application中,怎样加配置它等.但是本文不谈你应该把什么东西写到日志 ...
- tyvj1172 自然数拆分Lunatic版
背景 话说小小鱼看了P1171(自然数拆分)之后感觉异常不爽,于是异常邪恶地将题目加强. 描述 输入自然数n,然后将其拆分成由若干数相加的形式,参与加法运算的数可以重复. 输入格式 输入只有一个整数n ...
- ANT的安装
1.下载ANT http://ant.apache.org/bindownload.cgi 2.将下载下来的压缩包解压到任意文件夹下,例如D盘根目录下D:/apache-ant-1.9.2 3.添加环 ...
- [Math] 常见的几种最优化方法
我们每个人都会在我们的生活或者工作中遇到各种各样的最优化问题,比如每个企业和个人都要考虑的一个问题“在一定成本下,如何使利润最大化”等.最优化方法是一种数学方法,它是研究在给定约束之下如何寻求某些因素 ...
- PHP函数 addslashes() 和 mysql_real_escape_string() 的区别 && SQL宽字节,绕过单引号注入攻击
首先:不要使用 mysql_escape_string(),它已被弃用,请使用 mysql_real_escape_string() 代替它. mysql_real_escape_string() 和 ...
- 关于DataTable添加新列到指定列的方法
在开发新项目的时候发现了一个问题 dtResult.Columns.Add()方法只能将指定的列添加到DataTable的列的最后的位置,但是不能添加到指定的列上.举例来说,假设dtResult总共有 ...