Comparable and Comparator Interfaces Ben Rodes Disclaimer Interfaces Problem: You don’t know what an interface is yet! Seems problematic So what is an interface? Its not a class! A group of related methods with no bodies (no definition, just method signatures) Interfaces A class may implement any number of interfaces. To implement an interface is a contract. The implementer must define the interface functions! Why do this? We can use objects of an interface type, without knowing their actual instance type. Let’s look at an example. Interfaces public interface TimeKeeper { public Time getTime(); public void setTime(Time); …. } Interfaces public class Watch implements TimeKeeper { //Whatever fields go here //Constructor, methods …. public Time getTime() { //Define this function } } public void setTime() { //Define this function } Interfaces You can think of Watch in these ways: You can treat a Watch object as a TimeKeeper A Watch object can do “TimeKeeper things” A Watch object can be used anywhere a TimeKeeper is legal to use A Watch object has more than one type It’s a Watch (defined by the class Watch) It’s a TimeKeeper (defined by the interface) Interfaces Okay but why? Hold on, I am getting there! Let’s pretend you want to write some generic function to work on TimeKeepers Interfaces public Time getAVGClkDiff(ArrayList<TimeKeeper> clocks) { //Loop over each element in clocks //for each element e e.getTime(); //Get the time, store it, take an average } This may not be the exactly right syntax, but the right idea Interfaces Okay, dumb example, but … We don’t care what the actual time keepers are Because an interface is a contract, we know a TimeKeeper has a getTime function, and we can treat each element as a TimeKeeper, rather than whatever instance it actually is. Similar idea to inheritance, but is subtly different. Interfaces do not show inheritance. Relationships are maintained among diverse objects. More to come later. The Comparable Interface Comparable is an interface Contains only one method Defined in the Java API compareTo(SomeObject o2) There are functions in the Java API you can use to do useful things if your objects implement this interface. Check out the Collections class Class Collections utility methods for doing operations on Collections See MSD textbook, Section 9.5, pp. 666f Methods (static, mostly for Lists) search a list for an item: binarySearch() sort(), max(), min() -- uses compareTo() or Comparator object reverse(), fill(), shuffle(), copy(), replaceAll() List list2 = Collections.unmodifiableList(list1); // p. 668 Note very similar Arrays class Collections Sort Accepts a List of comparable objects. How might a sort() or any other method use this? Imagine: Perhaps items stored as a list of Objects: List theList …; Inside a loop, code might look like this: Comparable item1 = (Comparable) theList.get(i); Comparable item2 = (Comparable) theList.get(j); int cmpResult = item1.compareTo(item2); Such code will work when the list stores any class that implements Comparable! But, what happens if list-elements are of different classes (still Comparable, but different)? compareTo() fails! Lets look at an example! Example: Writing compareTo() Imagine something like an entry in a phonebook Order by last name, first name, then number int compareTo(PhoneBookEntry item2 ) { int retVal= last.compareTo(item2.last); if ( retVal != 0 ) return retVal; retVal = first.compareTo(item2.first); if ( retVal != 0 ) return retVal; retVal = phNum - item2.phNum; return retVal; } Comparable Problems Lack of flexibility Just one way to compare is possible, because there’s just one compareTo method per class Possible solutions: Separate functions: sortByName(), sortByNum(),… We can’t predict in advance how you’ll want to sort! Pass a parameter to indicate control: sort(theList, “byName”) or sort(theList, “byNum”); Ugh. Same problem as before And the internals of sort() will grow to become very ugly Function Objects We need to somehow pass “how to execute” information as a parameter to sort() We pass objects as parameters Can we pass a method/operation as an object? Many languages support this, but in different ways: C and C++ – pointers to functions C# – delegates Java – “function objects” that implement a specified interface, and the one method in that interface does the needed work Function Objects in Java Idea: encapsulate a function inside a class Note: not our usual idea of a class State? (None.) Identity? (Just need one instance.) Represents an entity? (Nope! Just a place to stash a function so it can be passed as a parameter.) Warning / caveat! This idea is contrary to many OO principles, but… Useful if done in limited circumstances Use it when the libraries make it available Not often part of your own class-design But use it in libraries when it’s part of the framework Example: Comparator objects We want to pass a function-object to a method: Collections.sort(someList, function-object-goes-here); But what type should this object be? Use an Interface: Interface name can be used as a type in the parameter list Interface defines the method name itself! Java’s Comparator interface: int compare( Object o1, Object o2); Notes: not compareTo()! Takes two parameters! Define a class for each kind of comparison you want. E.g. Classes: CmpStudentByGpa, CmpStudentByGpaDesc Classes: CmpDogByName, CmpDogByBreed Example? Writing a Comparator Class Example on following slides like one from MSD text, p. 646647 We have a Dog class with name, breed and gender But see simpler example in Java on website list of Student objects sort by name, gpa Also sort in descending order too Look at testSorting1() in TestDriver class Look at compareTo() in Student Look at use of comparator classes