EqualsBuilder和HashCodeBuilder 自动化hashCode()和equals()

问题产生:当需要自动实现hashCode()和equals()方法
解决方法:使用EqualsBuilder和HashCodeBuilder
使用举例:

import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.EqualsBuilder;

public class PoliticalCandidate {
// Member variables - omitted for brevity
// Constructors - omitted for brevity
// get/set methods - omitted for brevity
// A hashCode which creates a hash from the two unique identifiers

public int hashCode( ) {
return new HashCodeBuilder( 17 , 37 )
.append(firstName)
.append(lastName).toHashCode( );
}

// An equals which compares two unique identifiers
public boolean equals(Object o) {
boolean equals = false ;
if ( o != null && PoliticalCandidate. class .isAssignableFrom(o) ) {
PoliticalCandidate pc = (PoliticalCandidate) o;
equals = ( new EqualsBuilder( )
.append(firstName, ps.firstName)
.append(lastName, ps.lastName)).isEquals( );
}
return equals;
}

}

Discussion:
1.在上述例子中,当有相同的firstname和lastname时,认为两个对象的hashCode相同,从而equals()返回true.
如果hashCode取决于该class的所有filed时需要使用反射机制来产生一个hashCode。
public int hashCode( ) {
return HashCodeBuilder.reflectionHashCode( this );
}
和ToStringBuilder 与 HashCodeBuilder一样EqualsBuilder 也是使用append()方法进行配置, EqualsBuilder的append()方法可以接受基本类型、对象、数组作为参数。EqualsBuilder强大的地方在于可以直接把数组作为参数传入append()方法,EqualsBuilder会依次比较数组中的每个元素。
2.如果两个对象相等当且仅当每个属性值都相等 这句话可以由以下代码实现:
public boolean equals(Object o) {
return EqualsBuilder.reflectionEquals( this , o);
}
问题提出:需要快速实现compareTo()方法
解决方法:使用CompareToBuilder提供的compareTo()方法。同样的CompareToBuilder也使用了反射机制。以下代码提供了一个compareTo()方法,用于比较两个对象所有的非static和非transient成员变量。

import org.apache.commons.lang.builder.CompareToBuilder;

// Build a compareTo function from reflection
public int compareTo(Object o) {
return CompareToBuilder.reflectionCompare( this , obj);

}

Discussion: CompareToBuilder.reflectionCompare()提供了两个对象non-static和nontransient成员变量的方法。 reflectionCompare()方法不予理会static和transient变量,因此以下代码中的averageAge和fullName变量是不会进入比较表达式的。
public class PoliticalCandidate {
// Static variable
private static String averageAge;

// Member variables
private String firstName;
private String lastName;

private transient String fullName;
// Constructors
// get/set methods
// Build a compareTo function from reflection
public int compareTo(Object o) {
return CompareToBuilder.reflectionCompare( this , obj);
}

}
比较对象成员变量的时候应该有一个比较的次序存在,上述代码中默认的应该是先比较lastName,然后是firstName。调用append()方法可以把要比较的变量加入比较表达式中,并且遵循后加入的先比较的次序。
例如:
public int compareTo(Object o) {
int compare = - 1 ; // By default return less-than
if ( o != null && PoliticalCandidate. class .isAssignableFrom( o.getClass( ) ) ) {

PoliticalCandidate pc = (PoliticalCandidate) o;
compare = ( new CompareToBuilder( )
.append(firstName, pc.firstName)
.append(lastName, pc.lastName)).toComparison( );
}

return compare;
}
在比较的时候会先比较lastName,只有在lastName相同的情况下才会比较firstName。
ps:实现compareTo()的时候应保证和equals()规则相同,即当compareTo()返回是0的时候equals()应该返回true。
1.1 ReflectionToStringBuilder

本笔记是在阅读Jakarta Commons Cookbook时所留下的。
1.使用ReflectionToStringBuilder 或者ToStringBuilder 自动产生toString()的内容。
使用举例:假设有一个表征校长候选人信息的javabean-PoliticalCandidate。

public class PoliticalCandidate {
private String lastName;
private String firstName;
private Date dateOfBirth;
private BigDecimal moneyRaised;
private State homeState;

// get/set方法省略
public void toString( ) {
ReflectionToStringBuilder.toString( this );
}
}

该bean里面有个toString()方法,假设有以下操作:
// Create a State
State va = new State( "VA", "Virginia");

// Create a Birth Date
Calendar calendar = new GregorianCalendar( );
calendar.set( Calendar.YEAR, 1743 );
calendar.set( Calendar.MONTH, Calendar.APRIL );
calendar.set( Calendar.DAY_OF_MONTH, 13 );
Date dob = calendar.getTime( );

BigDecimal moneyRaised = new BigDecimal( 293829292.93 );

// Create a Political Candidate
PoliticalCandidate candidate =
new PoliticalCandidate( "Jefferson", "Thomas", dob, moneyRaised, va );

System.out.println( candidate );

假设State对象也是一个使用ReflectionToStringBuilder的javabean,上述程序一种可能的输出为com.discursive.jccook.lang.builders.PoliticalCandidate@187aeca
[lastName=Jefferson,\firstName=Thomas,
dateOfBirth=Sat Apr 13 22:38:42 CST 1743,
moneyRaised=\293829292.930000007152557373046875,
state=\com.discursive.jccook.lang.builders.State@87816d
[abbreviation=VA,name=Virginia]]


org.apache.commons.lang.builder
  CompareToBuilder – 用于辅助实现Comparable.compareTo(Object)方法;
  
  EqualsBuilder – 用于辅助实现Object.equals()方法;
  
  HashCodeBuilder – 用于辅助实现Object.hashCode()方法;
  
  ToStringBuilder – 用于辅助实现Object.toString()方法;
  
  ReflectionToStringBuilder – 使用反射机制辅助实现Object.toString()方法;
  
  ToStringStyle – 辅助ToStringBuilder控制输出格式;
  
  StandardToStringStyle – 辅助ToStringBuilder控制标准格式。
------------------------------------------------------------------
Apache Commons Lang之hashCode()、equals()和compareTo()

Apache Commons Lang提供一套生成hashCode()、equals()和compareTo()的API,简单易用。这个与toString()工具用法类似。

一、实现策略

1、hashCode()
通过HashCodeBuilder反射来生成,这说明类的hashCode与类中所有的域都相关。
也可以通过HashCodeBuilder实例来制定生成。

2、equals()
也有两种生成方式,与toString()、hashCode()的生成策略类似。

3、compareTo()
与以上都类似。

二、实例

为了测试,创佳两个类 Foo、Bar,参看上篇文章,分别通过两种方式实现其hashCode()和equals()方法

public class Foo {
private String name;
private int age;
private Bar bar;

public Foo(String name, int age) {
this.name = name;
this.age = age;
}

//省略getter/setter方法

}

public class Bar {
private String name;

public Bar(String name) {
this.name = name;
}

//省略getter/setter方法

}

1、实现hashCode()

反射方式
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);

}

制定方式
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(name)
.append(age)
.append(bar)
.toHashCode();
}

2、实现equals()

反射方式
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}

制定方式

@Override
public boolean equals(Object obj) {
boolean flag = false;
if (obj != null && Foo.class.isAssignableFrom(obj.getClass())) {
Foo f = (Foo) obj;
flag = new EqualsBuilder()
.append(name, f.getName())
.append(age, f.getAge())
.append(bar, f.getBar()).isEquals();
}
return flag;
}

3、生成compareTo()
当然,实现compareTo()的前提是Foo类实现了Comparable接口。否则没啥意义。

反射实现
public int compareTo(Object obj) {
return CompareToBuilder.reflectionCompare(this, obj);

}

制定实现
public int compareTo(Object obj) {
int flag = -1;
if (obj != null && Foo.class.isAssignableFrom(obj.getClass())) {
Foo f = (Foo) obj;
flag = new CompareToBuilder()
.append(name, getName())
.append(age, f.getAge())
.append(bar, f.getBar())
.toComparison();
}
return flag;
}

你可能感兴趣的:(java)