home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Book Home Enterprise JavaBeans Search this book

Chapter 9. Design Strategies

The previous eight chapters have presented the core EJB technology. What's left is a grab bag of miscellaneous issues: how do you solve particular design problems, how do you work with particular kinds of databases, and topics of that nature.

9.1. Hash Codes in Compound Primary Keys

Chapter 6, "Entity Beans" discusses the necessity of overriding the Object.hashCode() and Object.equals() methods in the primary key class. As an example, we used the primary key for the Ship bean, ShipPK . This is a simple primary key with a single integer field, id . Therefore, our hashCode() and equals() methods were very simple; hashCode() just returned the id field as the hash value. With complex primary keys that have several fields, overriding the Object.equals() method remains trivial. However, the Object.hashCode() method is more complicated because an integer value that can serve as a suitable hash code must be created from several fields.

One solution is to concatenate all the values into a String and use the String object's hashCode() method to create a hash code value for the whole primary key. The String class has a decent hash code algorithm that generates a fairly well distributed and repeatable hash code value from any set of characters. The following code shows how to create such a hash code for a hypothetical primary key:

public class HypotheticalPrimaryKey implements java.io.Serializable { 
    public int primary_id;
    public short secondary_id;
    public java.util.Date date; 
    public String desc; 

    public int hashCode() { 

        StringBuffer strBuff = new StringBuffer(); 
        strBuff.append(primary_id); 
        strBuff.append(secondary_id); 
        strBuff.append(date); 
        strBuff.append(desc); 
        String str = strBuff.toString(); 
        int hashCode = str.hashCode(); 
        return hashCode; 
    } 
    // the constructor, equals, and toString methods follow 
}

A StringBuffer cuts down on the number of objects created, since String concatenation is expensive. The code could be improved by saving the hash code in a private variable and returning that value in subsequent method calls; this way, the hash code is only calculated once in the life of the instance.

9.1.1. Well-Distributed Versus Unique Hash Codes

A Hashtable is designed to provide fast lookups by binding an object to a key. Given any object's key, looking the object up in a hash table is a very quick operation. For the lookup, the key is converted to an integer value using the key's hashCode() method.

Hash codes do not need to be unique, only well-distributed. By "well-distributed," we mean that given any two keys, the chances are very good that the hash codes for the keys will be different. A well-distributed hash code algorithm reduces, but does not eliminate, the possibility that different keys evaluate to the same hash code. When keys evaluate to the same hash code, they are stored together and uniquely identified by their equals() method. If you look up an object using a key that evaluates to a hash code that is shared by several other keys, the Hashtable locates the group of objects that have been stored with the same hash code; then it uses the key's equals() method to determine which key (and hence, which object) you want. (That's why you have to override the equals() method in primary keys, as well as the hashCode() method.) Therefore, the emphasis in designing a good hash code algorithm is on producing codes that are well-distributed rather than unique. This allows you to design an index for associating keys with objects that is easy to compute, and therefore fast.



Library Navigation Links

Copyright © 2001 O'Reilly & Associates. All rights reserved.