Apache Commons EqualsBuilder and HashCodeBuilder

Introduction

Before we go ahead and explore Apache Commons**_ EqualsBuilder_** and HashCodeBuilder, we must know the relationship between equals and hashCode.

java.lang.Object which is the super class of all Java classes has two very important methods defined in it. They are:

public boolean equals(Object obj)

public int hashCode()

These two methods are very important when our classes deal with other Java classes such as Collection API used for searching, sorting, comparison and eliminate duplicate objects from a set.

public boolean equals(Object obj)

This method checks if some other object passed to it as an argument is equal to the object on which this method is invoked. The default implementation of this method in ** Object** class simply checks if two object references x and y refer to the same object, i.e., it checks if ** x == y**. This particular comparison is also known as “shallow comparison”. However, the classes providing their own implementations of the equals method are supposed to perform a “deep comparison”

public int hashCode()

This method returns the hash code value for the object on which this method is invoked. This method returns the hash code value as an integer and is supported for the benefit of hashing based collection classes such as Hashtable, HashMap,_ HashSet_, etc.

Relationship between equals and hashCode

Equal objects must produce the same hash code as long as they are equal, however unequal objects need not produce distinct hash codes.

Implementation

While_** hashCode()_ and_ equals()_ typically impact logic and performance, they are also often more tricky to implement correctly. The most important rule is that when one of these two methods is overridden, the other one should be as well. Because it can be tricky to implement hashCode() and equals() correctly, it is helpful to have_ EqualsBuilder_** and_** HashCodeBuilder**_ two reusable implementations of these provided as part of Apache Commons Lang builder package.

I particularly like the way how EqualsBuilder uses reflection to determine if the two Objects are equal or HashCodeBuilder uses reflection to build a valid hash code. But reflection hits the performance of application, so use it where the performance is not very critical. However these two builders also provide the alternative approach. Let’s demonstrate both approaches one by one:

  • Using Reflection:

Let’s create a simple class called Employee as the following mentioned code:

package blog.commons;

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

public class Employee {

	private int id;
	private String name;
	private int deptId;
	private String designation;

	public Employee(int id, String name, int deptId, String designation) {
		this.id = id;
		this.name = name;
		this.deptId = deptId;
		this.designation = designation;
	}

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

	@Override
	public int hashCode() {
		return HashCodeBuilder.reflectionHashCode(this);
	}
}

Now create a _ Main_ class to check how it works:

package blog.commons;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class Main {

	public static void main(String[] args) {
		Employee emp1 = new Employee(1, "Allen", 12, "Accountant");
		Employee emp2 = new Employee(1, "Allen", 13, "Accountant");
		System.out.println
			("Is emp1 equals to emp2: " + emp1.equals(emp2));
		Set<Employee> employees = new HashSet<Employee>();
		employees.addAll(Arrays.asList(emp1,emp2));

		System.out.println("Size of set: " + employees.size());

	}
}

If you execute the**_ main_** method, the output will be as follows:

Is emp1 equals to emp2: false
Size of set: 2

Here you can see that the employee “Allen” whose employee Id is “1? is an “Accountant” does his book keeping job for two different departments which department ids are**_ 12_** and 13 respectively. But the object**_ emp1_** and emp2 are treated as two different persons.

Now, let’s exclude the**_ deptId_** field to determine equality and build hashCode and see the effect. For doing this, you need to slightly modify the code of Employee class:

package blog.commons;

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

public class Employee {

	private int id;
	private String name;
	private int deptId;
	private String designation;

	public Employee(int id, String name, int deptId, String designation) {
		this.id = id;
		this.name = name;
		this.deptId = deptId;
		this.designation = designation;
	}

	@Override
	public boolean equals(Object obj) {
		return EqualsBuilder.reflectionEquals
			(this, obj,new String[] {"deptId"});
	}

	@Override
	public int hashCode() {
		return HashCodeBuilder.reflectionHashCode
				(this,new String[] {"deptId"});
	}
}

Again, execute the same**_ main_** method to see the output:

Is emp1 equals to emp2: true
Size of set: 1

Here, as you can see, now**_ emp1_** and emp2 are treated as equal but**_ emp1_** are been replaced by emp2, hence the size of the set employees is one. To overcome this problem, do not exclude the deptId while generating hashCode. Your**_ hashCode_** method should look like the following:

@Override
	public int hashCode() {
		return HashCodeBuilder.reflectionHashCode(this);
	}

Now the output should be shown as below if you execute the**_ main_** method again:

Is emp1 equals to emp2: true
Size of set: 2
  • Without Using Reflection:

In my previous examples, you have seen how easily and in a fascinating manner we can use reflection capability of EqualsBuilder and HashCodeBuilder to override**_ equals _**and hashCode methods. Now, I am going to show you how can you achieve the same output without using reflection which helps to improve performance:

package blog.commons;

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

public class Employee {

	private int id;
	private String name;
	private int deptId;
	private String designation;

	public Employee(int id, String name, int deptId, String designation) {
		this.id = id;
		this.name = name;
		this.deptId = deptId;
		this.designation = designation;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Employee == false) {
			return false;
		}

		if (this == obj) {
			return true;
		}
		Employee other = (Employee) obj;
		return new EqualsBuilder().append(this.id , other.id)
		.append(this.name , other.name)
		.append(this.designation , other.designation).isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder().append(this.id)
		.append(this.name)
		.append(this.deptId)
		.append(this.designation)
		.hashCode();
	}
}

If you run the _ main_ method this time, you get similar output as it has been shown in the last output result. Just notice here that I am not appending deptId in _ EqualsBuilder_ but I am doing it while generating _ hashCode_.

转载于:https://my.oschina.net/u/3238650/blog/1248260

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
commons-lang3.3.1.jar、Apache Commons包中的一个,包含了一些数据类型工具类,是java.lang.*的扩展。必须使用的jar包。为JRE5.0+的更好的版本所提供 Jar文件包含的类: META-INF/MANIFEST.MFMETA-INF/LICENSE.txtMETA-INF/NOTICE.txtorg.apache.commons.lang.ArrayUtils.class org.apache.commons.lang.BitField.class org.apache.commons.lang.BooleanUtils.class org.apache.commons.lang.CharEncoding.class org.apache.commons.lang.CharRange.class org.apache.commons.lang.CharSet.class org.apache.commons.lang.CharSetUtils.class org.apache.commons.lang.CharUtils.class org.apache.commons.lang.Clas sUtils.class org.apache.commons.lang.Entities$ArrayEntityMap.class org.apache.commons.lang.Entities$BinaryEntityMap.class org.apache.commons.lang.Entities$EntityMap.class org.apache.commons.lang.Entities$HashEntityMap.class org.apache.commons.lang.Entities$LookupEntityMap.class org.apache.commons.lang.Entities$MapIntMap.class org.apache.commons.lang.Entities$PrimitiveEntityMap.class org.apache.commons.lang.Entities$TreeEntityMap.class org.apache.commons.lang.Entities.class org.apache.commons.lang.IllegalClassException.class org.apache.commons.lang.IncompleteArgumentException.class org.apache.commons.lang.IntHashMap$Entry.class org.apache.commons.lang.IntHashMap.class org.apache.commons.lang.LocaleUtils.class org.apache.commons.lang.NotImplementedException.class org.apache.commons.lang.NullArgumentException.class org.apache.commons.lang.NumberRange.class org.apache.commons.lang.NumberUtils.class org.apache.commons.lang.ObjectUtils$Null.class org.apache.commons.lang.ObjectUtils.class org.apache.commons.lang.RandomStringUtils.class org.apache.commons.lang.SerializationException.class org.apache.commons.lang.SerializationUtils.class org.apache.commons.lang.StringEscapeUtils.class org.apache.commons.lang.StringUtils.class org.apache.commons.lang.SystemUtils.class org.apache.commons.lang.UnhandledException.class org.apache.commons.lang.Validate.class org.apache.commons.lang.WordUtils.class org.apache.commons.lang.builder.CompareToBuilder.class org.apache.commons.lang.builder.EqualsBuilder.class org.apache.commons.lang.builder.HashCodeBuilder.class org.apache.commons.lang.builder.ReflectionToStringBuilder$1.class org.apache.commons.lang.builder.ReflectionToStringBuilder.class org.apache.commons.lang.builder.StandardToStringStyle.class org.apache.commons.lang.builder.ToStringBuilder.class org.apache.commons.lang.builder.ToStringStyle$DefaultToStringStyle.class org.apache.commons.lang.builder.ToStringStyle$MultiLineToStringStyle.class org.apache.commons.lang.builder.ToStringStyle$NoFieldNameToStringStyle.class org.apache.commons.lang.builder.ToStringStyle$ShortPrefixToStringStyle.class org.apache.commons.lang.builder.ToStringStyle$SimpleToStringStyle.class org.apache.commons.lang.builder.ToStringStyle.class org.apache.commons.lang.enum.Enum$Entry.class org.apache.commons.lang.enum.Enum.class org.apache.commons.lang.enum.EnumUtils.class org.apache.commons.lang.enum.ValuedEnum.class org.apache.commons.lang.enums.Enum$Entry.class org.apache.commons.lang.enums.Enum.class org.apache.commons.lang.enums.EnumUtils.class org.apache.commons.lang.enums.ValuedEnum.class org.apache.commons.lang.exception.ExceptionUtils.class org.apache.commons.lang.exception.Nestable.class org.apache.commons.lang.exception.NestableDelegate.class org.apache.commons.lang.exception.NestableError.class org.apache.commons.lang.exception.NestableException.class org.apache.commons.lang.exception.NestableRuntimeException.class org.apache.commons.lang.math.DoubleRange.class org.apache.commons.lang.math.FloatRange.class org.apache.commons.lang.math.Fraction.class org.apache.commons.lang.math.IntRange.class org.apache.commons.lang.math.JVMRandom.class org.apache.commons.lang.math.LongRange.class org.apache.commons.lang.math.NumberRange.class org.apache.commons.lang.math.NumberUtils.class org.apache.commons.lang.math.RandomUtils.class org.apache.commons.lang.math.Range.class org.apache.commons.lang.mutable.Mutable.class org.apache.commons.lang.mutable.MutableBoolean.class org.apache.commons.lang.mutable.MutableByte.class org.apache.commons.lang.mutable.MutableDouble.class org.apache.commons.lang.mutable.MutableFloat.class org.apache.commons.lang.mutable.MutableInt.class org.apache.commons.lang.mutable.MutableLong.class org.apache.commons.lang.mutable.MutableObject.class org.apache.commons.lang.mutable.MutableShort.class org.apache.commons.lang.text.CompositeFormat.class org.apache.commons.lang.text.StrBuilder$StrBuilderReader.class org.apache.commons.lang.text.StrBuilder$StrBuilderTokenizer.class org.apache.commons.lang.text.StrBuilder$StrBuilderWriter.class org.apache.commons.lang.text.StrBuilder.class org.apache.commons.lang.text.StrLookup$MapStrLookup.class org.apache.commons.lang.text.StrLookup.class org.apache.commons.lang.text.StrMatcher$CharMatcher.class org.apache.commons.lang.text.StrMatcher$CharSetMatcher.class org.apache.commons.lang.text.StrMatcher$NoMatcher.class org.apache.commons.lang.text.StrMatcher$StringMatcher.class org.apache.commons.lang.text.StrMatcher$TrimMatcher.class org.apache.commons.lang.text.StrMatcher.class org.apache.commons.lang.text.StrSubstitutor.class org.apache.commons.lang.text.StrTokenizer.class org.apache.commons.lang.time.DateFormatUtils.class org.apache.commons.lang.time.DateUtils$DateIterator.class org.apache.commons.lang.time.DateUtils.class org.apache.commons.lang.time.DurationFormatUtils$Token.class org.apache.commons.lang.time.DurationFormatUtils.class org.apache.commons.lang.time.FastDateFormat$CharacterLiteral.class org.apache.commons.lang.time.FastDateFormat$NumberRule.class org.apache.commons.lang.time.FastDateFormat$PaddedNumberField.class org.apache.commons.lang.time.FastDateFormat$Pair.class org.apache.commons.lang.time.FastDateFormat$Rule.class org.apache.commons.lang.time.FastDateFormat$StringLiteral.class org.apache.commons.lang.time.FastDateFormat$TextField.class org.apache.commons.lang.time.FastDateFormat$TimeZoneDisplayKey.class org.apache.commons.lang.time.FastDateFormat$TimeZoneNameRule.class org.apache.commons.lang.time.FastDateFormat$TimeZoneNumberRule.class org.apache.commons.lang.time.FastDateFormat$TwelveHourField.class org.apache.commons.lang.time.FastDateFormat$TwentyFourHourField.class org.apache.commons.lang.time.FastDateFormat$TwoDigitMonthField.class org.apache.commons.lang.time.FastDateFormat$TwoDigitNumberField.class org.apache.commons.lang.time.FastDateFormat$TwoDigitYearField.class org.apache.commons.lang.time.FastDateFormat$UnpaddedMonthField.class org.apache.commons.lang.time.FastDateFormat$UnpaddedNumberField.class org.apache.commons.lang.time.FastDateFormat.class org.apache.commons.lang.time.StopWatch.class

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值