

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

| 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 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:
The above policies can be collected in a utility class : 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 |