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;
}
}
分享到:
相关推荐
2. **事务处理**:Java EE中的Java Transaction API(JTA)和Java Transaction Service(JTS)提供了分布式事务管理,确保了在SOA环境下服务调用的原子性、一致性、隔离性和持久性(ACID属性)。 3. **安全性**:...
Implementing.SAP.ERP.Sales.and.Distribution
《现代多线程:实现、测试与调试多线程Java和C++/Pthreads/Win32程序》一书由Richard H. Carver和Kuo-Chung Tai共同编写,是John Wiley & Sons, Inc.出版社于2006年出版的一部专业著作。该书深入探讨了在现代软件...
IBM.Press.Implementing.IBM.Rational.ClearQuest.An.End.to.End.Deployment.Guide
读书笔记:Implementing.DomainDriven.Design实现领域驱动设计 中英文对照翻译
### Java CAPS基础知识:实现常见的EAI模式 #### 概述 《Java™ CAPS 基础知识:实现常见的EAI模式》是一本由Michael Czapski、Sebastian Krueger、Brendan Marry、Saurabh Sahai、Peter Vaneris和Andrew Walker...
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-...
在"Implementing_QuantLib.rar"中,我们可能找到关于如何配置和使用QuantLib的详细指南。 QuantLib的核心特性包括: 1. **时间序列处理**:库内包含了处理日期、日历和时间跨度的功能,这对于计算利息和到期日等...
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 ...
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 ...
通过以上六个方面的深入探讨,我们可以看到,《Managing and Implementing Microsoft SharePoint 2010 Projects》这本书不仅提供了一套全面的项目管理指南,还涵盖了从需求分析到后期维护的整个过程。这对于任何希望...
关于软件工程方面的一本参考书。
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 ...
### 实施 AWS 云设计模式的关键知识点 #### 一、书名解读:《实施 AWS 云设计模式》 - **核心概念**:“云设计模式”指的是在云计算环境中为解决特定问题而采用的一系列最佳实践和技术架构。这些模式有助于构建可...
Sams.Applied.SOAP.Implementing.NET.XML.Web.Services