Searching Example Using Generics
This example has two main purposes:
- it shows how you can make use of Java's generic classes.
- it shows how you can use interfaces to allow for easy interchangeability
of data structures
Key points about Java generics
- They always use <> brackets
- The type parameters must be classes, not primitive types. The
reason that the type parameters must be classes is that Java
keeps only one bytecode copy of a generic class rather than
one copy for each type instantiation (e.g., one for List<Integer>
and one for List<String>) as in C++. Keeping one bytecode copy
works only if all generic variables represent classes since
the bytecode depends on all variables being a descendent of the
Object class (e.g., the bytecode assumes that all variable accesses
occur through pointers, not primitive types).
A generic can go further and require that its
type parameters implement certain interfaces. For example, a
SortedMap generic requires its key parameter to implement the
Comparator interface. The Comparator interface contains a
compare and equals method, and hence any
implementation of SortedMap can obtain an ordering of keys by
calling the compare and equals methods.
The program shown at the end of this web page solves the following problem:
Write a Java main program that determines whether or not various search
terms are in a list of strings. The input will come from the command
line as follows:
- an integer, n, that represents the number of strings in the list
- n strings representing the strings in the list
- an unspecified number of strings. For each string your program
should determine if the string is in the list.
Write a search method that you call from your main program to perform
the actual search. It should return true/false depending on whether or
not it finds the string. Its parameters should include the collection of
strings and the string to be found.
Your main program should use Java's sorted tree implementation to
store the list of strings. It should then loop through
the remaining strings on the command line, call the search method, and
print the result using System.out.printf. Your program should print the
string and either true/false.
For example, the command:
java search 3 brad nels james jim nancy brad nels
should produce the output:
jim false
nancy false
brad true
nels true
The Program
import java.util.*;
class search {
// The first type parameter to Map represents the type of the key and
// the second type parameter represents the type of the value. In this
// case String represents the key type and Integer represents the value
// type
static boolean find(Map myCollection, String key) {
return myCollection.containsKey(key);
}
public static void main(String args[]) {
int n = Integer.parseInt(args[0]); // parseInt converts String to int
// java.util.TreeMap is Java's sorted tree implementation--it currently
// uses a red-black tree implementation
Map searchCollection = new TreeMap();
int i;
// The reason for pre-allocating a dummy value is to allow all the
// values in the map to share the same piece of memory. Since we do not
// care about the value field, we want to minimize the amount of memory
// that the values in the map consume. We can minimize the amount of
// memory by making the value fields all point to the same object in
// memory
Integer dummyValue = new Integer(0);
// put is the method provided by Map to insert a (key, value) pair
for (i = 0; i < n; i++) {
searchCollection.put(args[i+1], dummyValue);
}
for (i = n+1; i < args.length; i++) {
// %b is the formatting string for a boolean
System.out.printf("%s %b\n", args[i], find(searchCollection, args[i]));
}
}
}
Interchangeability of Data Structures
Since the above code declares searchCollection to be an interface
type (i.e., Map), rather than a class type (i.e., TreeMap), a one word
change to the code transforms the program from using a tree to using a
hash table. I can simply change the line that reads:
Map searchCollection = new TreeMap();
to
Map searchCollection = new HashMap();
If I had instead declared searchCollection to be a specific
class type, namely TreeMap, then I would need to change the
declaration of searchCollection in both the above line and in
its parameter declaration in find. Hence by using interface types
I make it easier to rapidly replace data structures if I so desire.