Below is the syntax highlighted version of Transaction.java from § Algorithms.
/*************************************************************************
* Compilation: javac Transaction.java
* Execution: java Transaction
*
* Data type for commercial transactions.
*
*************************************************************************/
import java.util.Arrays;
import java.util.Comparator;
public class Transaction implements Comparable<Transaction> {
private final String who; // customer
private final Date when; // date
private final double amount; // amount
public Transaction(String who, Date when, double amount) {
this.who = who;
this.when = when;
this.amount = amount;
}
// create new transaction by parsing string of the form: name,
// date, real number, separated by whitespace
public Transaction(String transaction) {
String[] a = transaction.split("\\s+");
who = a[0];
when = new Date(a[1]);
amount = Double.parseDouble(a[2]);
}
// accessor methods
public String who() { return who; }
public Date when() { return when; }
public double amount() { return amount; }
public String toString() {
return String.format("%-10s %10s %8.2f", who, when, amount);
}
public int compareTo(Transaction that) {
if (this.amount < that.amount) return -1;
else if (this.amount > that.amount) return +1;
else return 0;
}
// is this Transaction equal to x?
public boolean equals(Object x) {
if (x == this) return true;
if (x == null) return false;
if (x.getClass() != this.getClass()) return false;
Transaction that = (Transaction) x;
return (this.amount == that.amount) && (this.who.equals(that.who))
&& (this.when.equals(that.when));
}
public int hashCode() {
int hash = 17;
hash = 31*hash + who.hashCode();
hash = 31*hash + when.hashCode();
hash = 31*hash + ((Double) amount).hashCode();
return hash;
}
// ascending order of account number
public static class WhoOrder implements Comparator<Transaction> {
public int compare(Transaction v, Transaction w) {
return v.who.compareTo(w.who);
}
}
// ascending order of time
public static class WhenOrder implements Comparator<Transaction> {
public int compare(Transaction v, Transaction w) {
return v.when.compareTo(w.when);
}
}
// ascending order of ammount
public static class HowMuchOrder implements Comparator<Transaction> {
public int compare(Transaction v, Transaction w) {
if (v.amount < w.amount) return -1;
else if (v.amount > w.amount) return +1;
else return 0;
}
}
// test client
public static void main(String[] args) {
Transaction[] a = new Transaction[4];
a[0] = new Transaction("Turing 6/17/1990 644.08");
a[1] = new Transaction("Tarjan 3/26/2002 4121.85");
a[2] = new Transaction("Knuth 6/14/1999 288.34");
a[3] = new Transaction("Dijkstra 8/22/2007 2678.40");
StdOut.println("Unsorted");
for (int i = 0; i < a.length; i++)
StdOut.println(a[i]);
StdOut.println();
StdOut.println("Sort by date");
Arrays.sort(a, new Transaction.WhenOrder());
for (int i = 0; i < a.length; i++)
StdOut.println(a[i]);
StdOut.println();
StdOut.println("Sort by customer");
Arrays.sort(a, new Transaction.WhoOrder());
for (int i = 0; i < a.length; i++)
StdOut.println(a[i]);
StdOut.println();
StdOut.println("Sort by amount");
Arrays.sort(a, new Transaction.HowMuchOrder());
for (int i = 0; i < a.length; i++)
StdOut.println(a[i]);
StdOut.println();
}
}
Implementing hashCode : ■if a class overrides equals, it must override hashCode
■when they are both overridden, equals and hashCode must use the same set of fields
■if two objects are equal, then their hashCode values must be equal as well
■if the object is immutable, then hashCode is a candidate for caching and lazy initialization
It is a popular misconception that hashCode provides a unique identifier for an object. It does not.
Example 1
The following utility class allows simple construction of an effective hashCode method. It is based on the recommendations of Effective Java, by Joshua Bloch.
import java.lang.reflect.Array;
/**
* Collected methods which allow easy implementation of <code>hashCode</code>.
*
* Example use case:
* <pre>
* public int hashCode(){
* int result = HashCodeUtil.SEED;
* //collect the contributions of various fields
* result = HashCodeUtil.hash(result, fPrimitive);
* result = HashCodeUtil.hash(result, fObject);
* result = HashCodeUtil.hash(result, fArray);
* return result;
* }
* </pre>
*/
public final class HashCodeUtil {
/**
* An initial value for a <code>hashCode</code>, to which is added contributions
* from fields. Using a non-zero value decreases collisons of <code>hashCode</code>
* values.
*/
public static final int SEED = 23;
/**
* booleans.
*/
public static int hash( int aSeed, boolean aBoolean ) {
System.out.println("boolean...");
return firstTerm( aSeed ) + ( aBoolean ? 1 : 0 );
}
/**
* chars.
*/
public static int hash( int aSeed, char aChar ) {
System.out.println("char...");
return firstTerm( aSeed ) + (int)aChar;
}
/**
* ints.
*/
public static int hash( int aSeed , int aInt ) {
/*
* Implementation Note
* Note that byte and short are handled by this method, through
* implicit conversion.
*/
System.out.println("int...");
return firstTerm( aSeed ) + aInt;
}
/**
* longs.
*/
public static int hash( int aSeed , long aLong ) {
System.out.println("long...");
return firstTerm(aSeed) + (int)( aLong ^ (aLong >>> 32) );
}
/**
* floats.
*/
public static int hash( int aSeed , float aFloat ) {
return hash( aSeed, Float.floatToIntBits(aFloat) );
}
/**
* doubles.
*/
public static int hash( int aSeed , double aDouble ) {
return hash( aSeed, Double.doubleToLongBits(aDouble) );
}
/**
* <code>aObject</code> is a possibly-null object field, and possibly an array.
*
* If <code>aObject</code> is an array, then each element may be a primitive
* or a possibly-null object.
*/
public static int hash( int aSeed , Object aObject ) {
int result = aSeed;
if ( aObject == null) {
result = hash(result, 0);
}
else if ( ! isArray(aObject) ) {
result = hash(result, aObject.hashCode());
}
else {
int length = Array.getLength(aObject);
for ( int idx = 0; idx < length; ++idx ) {
Object item = Array.get(aObject, idx);
//recursive call!
result = hash(result, item);
}
}
return result;
}
/// PRIVATE ///
private static final int fODD_PRIME_NUMBER = 37;
private static int firstTerm( int aSeed ){
return fODD_PRIME_NUMBER * aSeed;
}
private static boolean isArray(Object aObject){
return aObject.getClass().isArray();
}
}
Here is an example of its use. When debugging statements are uncommented in HashCodeUtil, the reuse of the boolean, char, int and long versions of hash is demonstrated :
boolean...
char...
int...
long...
long...
int...
int...
int...
int...
int...
hashCode value: -608077094
import java.util.*;
public final class ApartmentBuilding {
public ApartmentBuilding (
boolean aIsDecrepit,
char aRating,
int aNumApartments,
long aNumTenants,
double aPowerUsage,
float aWaterUsage,
byte aNumFloors,
String aName,
List aOptions,
Date[] aMaintenanceChecks
){
fIsDecrepit = aIsDecrepit;
fRating = aRating;
fNumApartments = aNumApartments;
fNumTenants = aNumTenants;
fPowerUsage = aPowerUsage;
fWaterUsage = aWaterUsage;
fNumFloors = aNumFloors;
fName = aName;
fOptions = aOptions;
fMaintenanceChecks = aMaintenanceChecks;
}
@Override public boolean equals(Object that) {
if ( this == that ) return true;
if ( !(that instanceof ApartmentBuilding) ) return false;
ApartmentBuilding thatBuilding = (ApartmentBuilding)that;
return hasEqualState(thatBuilding);
}
@Override public int hashCode() {
//this style of lazy initialization is
//suitable only if the object is immutable
if ( fHashCode == 0) {
int result = HashCodeUtil.SEED;
result = HashCodeUtil.hash( result, fIsDecrepit );
result = HashCodeUtil.hash( result, fRating );
result = HashCodeUtil.hash( result, fNumApartments );
result = HashCodeUtil.hash( result, fNumTenants );
result = HashCodeUtil.hash( result, fPowerUsage );
result = HashCodeUtil.hash( result, fWaterUsage );
result = HashCodeUtil.hash( result, fNumFloors );
result = HashCodeUtil.hash( result, fName );
result = HashCodeUtil.hash( result, fOptions );
result = HashCodeUtil.hash( result, fMaintenanceChecks );
fHashCode = result;
}
return fHashCode;
}
//..other methods elided
// PRIVATE ////
/**
* The following fields are chosen to exercise most of the different
* cases.
*/
private boolean fIsDecrepit;
private char fRating;
private int fNumApartments;
private long fNumTenants;
private double fPowerUsage;
private float fWaterUsage;
private byte fNumFloors;
private String fName; //possibly null, say
private List fOptions; //never null
private Date[] fMaintenanceChecks; //never null
private int fHashCode;
/**
* Here, for two ApartmentBuildings to be equal, all fields must be equal.
*/
private boolean hasEqualState( ApartmentBuilding that ) {
//note the different treatment for possibly-null fields
return
( this.fName==null ? that.fName==null : this.fName.equals(that.fName) ) &&
( this.fIsDecrepit == that.fIsDecrepit )&&
( this.fRating == that.fRating )&&
( this.fNumApartments == that.fNumApartments ) &&
( this.fNumTenants == that.fNumTenants ) &&
( this.fPowerUsage == that.fPowerUsage ) &&
( this.fWaterUsage == that.fWaterUsage ) &&
( this.fNumFloors == that.fNumFloors ) &&
( this.fOptions.equals(that.fOptions) )&&
( Arrays.equals(this.fMaintenanceChecks, that.fMaintenanceChecks) );
}
/**
* Exercise hashcode.
*/
public static void main (String [] aArguments) {
List options = new ArrayList();
options.add("pool");
Date[] maintenanceDates = new Date[1];
maintenanceDates[0] = new Date();
byte numFloors = 8;
ApartmentBuilding building = new ApartmentBuilding (
false,
'B',
12,
396L,
5.2,
6.3f,
numFloors,
"Palisades",
options,
maintenanceDates
);
System.out.println("hashCode value: " + building.hashCode());
}
}
Example 2
The WEB4J tool defines a utility class for implementing hashCode. Here is an example of a Model Object implemented with that utility.
Items to note :
■the hashCode value is calculated only once, and only if it is needed. This is only possible since this is an immutable object.
■calling the getSignificantFields() method ensures hashCode and equals remain 'in sync'
package hirondelle.fish.main.discussion;
import java.util.*;
import hirondelle.web4j.model.ModelCtorException;
import hirondelle.web4j.model.ModelUtil;
import hirondelle.web4j.model.Check;
import hirondelle.web4j.security.SafeText;
import static hirondelle.web4j.util.Consts.FAILS;
/**
Comment posted by a possibly-anonymous user.
*/
public final class Comment {
/**
Constructor.
@param aUserName identifies the logged in user posting the comment.
@param aBody the comment, must have content.
@param aDate date and time when the message was posted.
*/
public Comment (
SafeText aUserName, SafeText aBody, Date aDate
) throws ModelCtorException {
fUserName = aUserName;
fBody = aBody;
fDate = aDate.getTime();
validateState();
}
/** Return the logged in user name passed to the constructor. */
public SafeText getUserName() {
return fUserName;
}
/** Return the body of the message passed to the constructor. */
public SafeText getBody() {
return fBody;
}
/**
Return a <a href="http://www.javapractices.com/Topic15.cjp">defensive copy</a>
of the date passed to the constructor.
<P>The caller may change the state of the returned value, without affecting
the internals of this <tt>Comment</tt>. Such copying is needed since
a {@link Date} is a mutable object.
*/
public Date getDate() {
// the returned object is independent of fDate
return new Date(fDate);
}
/** Intended for debugging only. */
@Override public String toString() {
return ModelUtil.toStringFor(this);
}
@Override public boolean equals( Object aThat ) {
Boolean result = ModelUtil.quickEquals(this, aThat);
if ( result == null ){
Comment that = (Comment) aThat;
result = ModelUtil.equalsFor(
this.getSignificantFields(), that.getSignificantFields()
);
}
return result;
}
@Override public int hashCode() {
if ( fHashCode == 0 ) {
fHashCode = ModelUtil.hashCodeFor(getSignificantFields());
}
return fHashCode;
}
// PRIVATE //
private final SafeText fUserName;
private final SafeText fBody;
/** Long is used here instead of Date in order to ensure immutability.*/
private final long fDate;
private int fHashCode;
private Object[] getSignificantFields(){
return new Object[] {fUserName, fBody, new Date(fDate)};
}
private void validateState() throws ModelCtorException {
ModelCtorException ex = new ModelCtorException();
if( FAILS == Check.required(fUserName) ) {
ex.add("User name must have content.");
}
if ( FAILS == Check.required(fBody) ) {
ex.add("Comment body must have content.");
}
if ( ! ex.isEmpty() ) throw ex;
}
}
分享到:
相关推荐
Addison.Wesley.Implementing.SOA.Using.Java.EE
Modern.Multithreading.Implementing.Testing.and.Debugging.Multithreaded.Java.and.C.Plus.Plus.Pthreads.Win32.Programs.Oct.2005.eBook-DDU.pdf
Java.CAPS.Basics.Implementing.Common.EAI.Patterns
Implementing.SAP.ERP.Sales.and.Distribution
Cisco.Press.Cisco.Self-Study.Implementing.IPv6.Networks.pdf
高清彩版 Packt.Implementing.Cloud.Design.Patterns.for.AWS
Implementing.Cisco.Unified.Communications.Manager.Part1.2nd.Edition
Implementing.802.11.with.Microcontrollers.Wireless.Networking.for.Embedded.Systems.Designers
IBM.Press.Implementing.IBM.Rational.ClearQuest.An.End.to.End.Deployment.Guide
Title: Implementing Cloud Design Patterns for AWS Author: Marcus Young Length: 234 pages Edition: 1 Language: English Publisher: Packt Publishing Publication Date: 2015-05-15 ISBN-10: 1782177345 ISBN-...
In this book, we walk through each step in relatively more detail and show intermediate R output to help students make sure they are implementing the analyses correctly. Second, most books deal with ...
Further, the Xtend programming language (a fully-featured Java-like language tightly integrated with Java) will be introduced. We then explain the main concepts of Xtext, such as validation, code ...
Create highly efficient design patterns for scalability, redundancy, and high availability in the AWS Cloud About This Book Create highly robust systems using cloud infrastructure ...
关于软件工程方面的一本参考书。
With this practical guide, you'll gain project management practices for implementing SharePoint, and learn how to customize the system to match the unique collaboration and data-sharing needs of your...
Implementing Splunk Second Edition is a learning guide that introduces you to all the latest features and improvements of Splunk 6.2. The book starts by introducing you to various concepts such as ...
Implementing CIFS will be indispensable to every developer who wants to provide CIFS compatibility—and every administrator or security specialist who needs an in-depth understanding of how it really ...
Key Features Work through practical examples and gain DevOps best practices to successfully deploy applications on AWS Successfully provision and operate distributed application systems and your AWS ...