您可以在这里快速查找:


 
您的位置: 编程学习 > java教程 > 200601
文章分类

Java技术
2005: 03 04 05 06 07 08
09 10 11 12
2006: 01 02

Asp.net
2005: 07 08 09 10 11 12
2006: 01 02

VB编程
2006: 02

Asp编程
2005: 11 12
2006: 01 02

C++/VC
2005: 10 11 12
2006: 01 02

Delphi
2005: 12
2006: 01 02

其它

 本文章适合所有读者

覆盖equals【引自http://www.javapractices.com/Topic17.cjp】

hongz
Implementing equals
Discussion:

All objects have both identity (the object´s location in memory) and state (the object´s data). The == operator always compares identity. The default implementation of equals compares identity as well.

Sometimes the default implementation of equals has the desired behaviour (as in a type-safe enumeration, for example), but  equals should usually compare state, not identity. This is particularly true for "data-centric" classes which map to database records.

hashCode and equals are closely related :

  • if you override equals, you must override hashCode
  • hashCode must generate equal values for equal objects
Objects placed in a List , Set, or Map (as either a key or value) should have an appropriate definition of equals. (See, for example, the javadoc for Collection.contains , Map.containsKey, and Map.containsValue .)

If you extend a concrete class, and add a new field which contributes to equals, then it is not possible to write a perfectly correct equals method for the new class. Instead, you should use composition instead of inheritance.

Example

Here is an implementation of equals for a data-centric class. It demonstrates how different types of fields are treated:

  • object fields, including collections : use equals
  • type-safe enumerations : use either equals or == (they amount to the same thing, in this case)
  • possibly-null object fields : use both == and equals
  • array fields : use Arrays.equals
  • primitive fields other than float or double : use ==
  • float : convert to int using Float.floatToIntBits, then use ==
  • double :  convert to long using Double.doubleToLongBits, then use ==
It is worth noting that if fields are implemented with wrapper classes (Integer, Boolean, and so on), then implementation of equals is simpler, since there is only one case : calling the equals method recursively. (The compareTo method is also simplified in this case.)

The above policies can be collected in a utility class :

import java.util.Arrays; /** * Collected methods which allow easy implementation of <code>equals</code>. * * Example use case in a class called Car: * <pre> public boolean equals(Object that){ if ( this == that ) return true; if ( !(that instanceof Car) ) return false; Car thatCar = (Car)that; return EqualsUtil.areEqual(this.fName, that.fName) && EqualsUtil.areEqual(this.fNumDoors, that.fNumDoors) && EqualsUtil.areEqual(this.fGasMileage, that.fGasMileage) && EqualsUtil.areEqual(this.fColor, that.fColor) && Arrays.equals(this.fMaintenanceChecks, that.fMaintenanceChecks); //array! } * </pre> * * <em>Arrays are not handled by this class</em>. * This is because the <code>Arrays.equals</code> methods should be used for * array fields. */ public final class EqualsUtil { static public boolean areEqual(boolean aThis, boolean aThat){ //System.out.println("boolean"); return aThis == aThat; } static public boolean areEqual(char aThis, char aThat){ //System.out.println("char"); return aThis == aThat; } static public boolean areEqual(long aThis, long aThat){ /* * Implementation Note * Note that byte, short, and int are handled by this method, through * implicit conversion. */ //System.out.println("long"); return aThis == aThat; } static public boolean areEqual(float aThis, float aThat){ //System.out.println("float"); return Float.floatToIntBits(aThis) == Float.floatToIntBits(aThat); } static public boolean areEqual(double aThis, double aThat){ //System.out.println("double"); return Double.doubleToLongBits(aThis) == Double.doubleToLongBits(aThat); } /** * Possibly-null object field. * * Includes type-safe enumerations and collections, but does not include * arrays. See class comment. */ static public boolean areEqual(Object aThis, Object aThat){ //System.out.println("Object"); return aThis == null ? aThat == null : aThis.equals(aThat); } }

Car is a class which uses EqualsUtil to implement its equals method :
import java.util.*; public final class Car { public Car ( String aName, int aNumDoors, List<String> aOptions, double aGasMileage, String aColor, Date[] aMaintenanceChecks ){ fName = aName; fNumDoors = aNumDoors; fOptions = new ArrayList<String>(aOptions); fGasMileage = aGasMileage; fColor = aColor; fMaintenanceChecks = new Date[aMaintenanceChecks.length]; for (int idx=0; idx < aMaintenanceChecks.length; ++idx) { fMaintenanceChecks[idx] = new Date( aMaintenanceChecks[idx].getTime() ); } } public boolean equals(Object aThat) { //check for self-comparison if ( this == aThat ) return true; //use instanceof instead of getClass here for two reasons //1. if need be, it can match any supertype, and not just one class; //2. it renders an explict check for "that == null" redundant, since //it does the check for null already - "null instanceof [type]" always //returns false. (See Effective Java by Joshua Bloch.) if ( !(aThat instanceof Car) ) return false; //Alternative to the above line : //if ( aThat == null || aThat.getClass() != this.getClass() ) return false; //cast to native object is now safe Car that = (Car)aThat; //now a proper field-by-field evaluation can be made return EqualsUtil.areEqual(this.fName, that.fName) && EqualsUtil.areEqual(this.fNumDoors, that.fNumDoors) && EqualsUtil.areEqual(this.fOptions, that.fOptions) && EqualsUtil.areEqual(this.fGasMileage, that.fGasMileage) && EqualsUtil.areEqual(this.fColor, that.fColor) && Arrays.equals(this.fMaintenanceChecks, that.fMaintenanceChecks); } //..other methods elided // PRIVATE //// /** * The following fields are chosen to exercise most of the different * cases. */ private String fName; private int fNumDoors; private List<String> fOptions; private double fGasMileage; private String fColor; //treat as possibly-null private Date[] fMaintenanceChecks; /** * Exercise the equals method. */ public static void main (String[] aArguments) { List<String> options = new ArrayList<String>(); options.add("sunroof"); Date[] dates = new Date[1]; dates[0] = new Date(); //Create a bunch of Cars; only one and two should be equal Car one = new Car("Nissan", 2, options, 46.3, "Green", dates); //two is equal to one Car two = new Car("Nissan", 2, options, 46.3, "Green", dates); //three has a differs in fName only Car three = new Car("Pontiac", 2, options, 46.3, "Green", dates); //four differs in fNumDoors only Car four = new Car("Nissan", 4, options, 46.3, "Green", dates); //five differs in fOptions only List<String> optionsTwo = new ArrayList<String>(); optionsTwo.add("air conditioning"); Car five = new Car("Nissan", 2, optionsTwo, 46.3, "Green", dates); //six differs in fGasMileage only Car six = new Car("Nissan", 2, options, 22.1, "Green", dates); //seven differs in fColor only Car seven = new Car("Nissan", 2, options, 46.3, "Fuchsia", dates); //eight differs in fMaintenanceChecks only Date[] datesTwo = new Date[1]; datesTwo[0] = new Date(1000000); Car eight = new Car("Nissan", 2, options, 46.3, "Green", datesTwo); System.out.println( "one = one: " + one.equals(one) ); System.out.println( "one = two: " + one.equals(two) ); System.out.println( "two = one: " + two.equals(one) ); System.out.println( "one = three: " + one.equals(three) ); System.out.println( "one = four: " + one.equals(four) ); System.out.println( "one = five: " + one.equals(five) ); System.out.println( "one = six: " + one.equals(six) ); System.out.println( "one = seven: " + one.equals(seven) ); System.out.println( "one = eight: " + one.equals(eight) ); System.out.println( "one = null: " + one.equals(null) ); } }

An example run of this class demonstrates that only objects one and two are equal :
one = one: true
one = two: true
two = one: true
one = three: false
one = four: false
one = five: false
one = six: false
one = seven: false
one = eight: false
one = null: false