I know that this class compares two objects in a class(e.g. two Strings), but what types aren't comparable using this class?
That's not quite how it works. Comparable is an interface that any class may choose to implement in order to indicate that instances of the class may be compared using the class' compareTo() method. So you can choose to implement this interface in any class you create yourself (however, you must write the code for compareTo() yourself, since Java doesn't know how to compare your objects in a meaningful manner).
Some built-in classes implement Comparable and others don't - there might be a list somewhere, but it would be way too long for an SO answer. If you are wondering about whether a specific class implements compareTo(), check its documentation (and see if the comparison does what you expect) or simply try to call that method. If there is a built-in or third-party class that does not implement Comparable, you need to create a Comparator instead in order to compare them.
A Comparator may compare anything you wish, because you are the one who decides how it should work.
Actually, you can compare everything in Java.
For instance, you have a class X, which is incomparable. You can make this class an attribute to another class C and make C comparable, override its compareTo() method.
For example, it doesn't make sense to compare Colors
This is right. Even though it doesn't make sense, you can. Here is the answer for the question:
Which color is brighter?
public class ComparableColor implements Comparable<ComparableColor>
{
Color color;
public ComparableColor(Color color)
{
this.color = color;
}
#Override
public int compareTo(ComparableColor c)
{
return c.color.getAlpha() - this.color.getAlpha();
}
}
For example, it doesn't make sense to compare Colors, so this class doesn't implement the Comparable interface. Now, if you want a list of all classes that don't implement Comparable, I don't think there is one out there.
Related
I'd like to define an interface that will be used to implement keys for a map. The map uses equals and hasCode to locate and compare keys. My keys need to override these with custom computations. Here is what I'd like to do. It's important that the complex key is used. Thanks
public interface CachedRequestKey<T>{
public T complexKeyObject;
#Override
public boolean equals(T obj);
}
EDIT for down voters: I'm aware the above code is not valid. I'm looking for ideas to achieve an interface that insures the implementing class provides required methods using the generic type.
What you want isn't possible in Java. Object already implements equals and hashCode, so every subclass does automatically as well. There's no way for an interface or abstract class to require it to be reimplemented. It's assumed that equals and hashCode for a given class are implemented correctly for that class.
If you really need your classes to implement specific comparison operations and don't want to use the existing equality methods by accident, you could define your own comparison functions on you interface and require implementing classes to define those. Classes that already implement your equality mechanics in their equals and hashCode methods can delegate to the existing methods.
I don't get the point of implementing the Comparable interface, since I can't use the comparison operators <, <=, >=, and > for my custom classes like I would be able to with operator overriding in languages like C++; I still have to call the compareTo method directly.
I could write my own boolean methods like isEqual or bigger, which would be just as useful, if not more so, than the compareTo method.
Am I missing something? What is the point of implementing it?
The Comparable interface provides a means of communication to the implemented sorting algorithms, which would be impossible using custom methods for comparison.
The point of implementing Comparable is being able to sort arrays, Collections, etc... based on different criteria.
Other classes can take a parameter of type Comparable. They will not know your special methods, but they know the interface and can use it if implemented.
As an example, the method Collections.sort() can make use of an Comparable: http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#sort(java.util.List,%20java.util.Comparator)
This was one quite a unique question I came across (Maybe someone must have). Someone asked me that can we implement both comparable and comparator interface in a single class? I had slight hint that it might be possible. Since I had never tried such a thing before... I examined it myself.. and hence posting this question so that others my find it quickly over here.
Technically you can do this, but this will be bad practice. When class implements Comparable that means that class has natural order. For example, value classes, such as Integer implement Comparable, so you can just pass a list of them into Collections.sort and get the expected result.
On the other hand, Comparator is basically designed to be used as anonymous classes when you need to create some custom ordering for other classes. Or to provide ordering for the class that doesn't have natural ordering.
There can be situation, when class should have additional orderings in addition to it's natural ordering. The best way to handle such situation is to create static constant comparators in such class. For example, if you have class Person with name and age, you can have natural order by name and add additional comparator that will order Persons by age.
class Person implements Comparable<Person> {
public static final Comparator<Person> BY_AGE_COMPARATOR = new Comparator<Person>() {
#Override
public int compare(Person o1, Person o2) {
return o1.age < o2.age ? -1 : (o1.age == o2.age ? 0 : 1);
}
};
private int age;
private String name;
#Override
public int compareTo(Person o) {
return name.compareTo(o.name);
}
}
This approach is better because you don't need instance of the class to access it's comparator. Also you can add as many additional comparators to the class as you want.
To summarize, you when class implements Comparator it often means that order some entities is the main purpose of such class. Implementing Comparable means that instances of this class could be sorted using some natural ordering. Having class both implement Comparable and Comparator means that you have natural order for orderings. This doesn't make sense.
Pros
If most of the time we have a specific sorting method to be used, Comparable interface's compareTo() method can be used. For example, Employee object most of the times needs to be sorted using the name attribute you will use a compareTo() method of Comparable interface and sort it using employee name. User of the employee object can directly use Collections.sort(empList).
In case when we have a requirement for a specific sorting order, the comparator implementation can be used. So in employee case if we have a requirement to sort by address, we can have an implementation for address and use it as a parameter to Collections.sort(empList, new Employee());
The employee object here would implement compare(Object emp,Object emp1).
Cons
Comparator Implementation should implement the comparison between two objects. Hence we would have to pass the employee object as a comparator which is not very intutive.
Design-wise ideally the comparator method does not belong to employee class as it is not using any attribute of employee object (this) which is calling it.
Yes we can extend any pojo class to implement both comparable and comparator interface and implement the methods defined by them.
I implemented it in sample Student POJO class.
When called Collections.sort(studentList) ... compareTo() is used.
When called Collections.sort(studentList, new Student()) ... compare() is used.
Advantages:
1) I have single class implementation for both comparable and comparator interfaces.
Disadvantages:
1) I can define only one comparable and only one comparator inside one class.
2) Now to define any new comparator I have to move out to other class or define it on the fly (annonymous class).
3) But the motive of comparator is lost.Comparator provides an external implementation for comparison of class objects outside the class. Defining it inside might include confusion as to what is called and when?
People can add more points if I have missed out on any...
I see that Comparable interface allowed implementation of just the compareTo method. So why do we even need this interface? Why can't we simply define and declare the method in any class we want, without having to implement the Comparable interface?
I understand that this is correct: SortedSet<String> exampleSet = new TreeSet<String>(); <-- TreeSet implements SortedSet interface. So if I have a class called "Date" that implements Comparable, is this correct: Comparable<Date> example = new Date<Date>();. If yes, what exactly do I get? I mean what kind of object do I get? What properties does it have? If not, why not?
Why can't we simply define and declare the method in any class we want, without having to implement the Comparable interface?
How would you expect a sorting method to work in that case?
It's really handy to be able to sort any collection where the elements are all comparable with each other - and an interface is the way to express that.
is this correct: Comparable<Date> example = new Date<Date>();
No, not unless Date itself were generic. You could write:
Comparable<Date> example = new Date();
... but it would be odd to do so. Normally Comparable is used by code which wants to compare existing objects - so it would fetch values from a collection and compare them with each other, for example.
Why can't we simply define and declare the method in any class we
want, without having to implement the Comparable interface?
Some Collections like TreeMap, need to compare two objects, even for a simple add() operation. Such a tree needs that to internally put "smaller" object in the left tree, and bigger ín the right subtree (a bit simplified).
Because such a generic Collection (like TreeMap), is designed to work for all Objects, the Object, then must know how to perfrom a compareTo().
Other Collections like HashMaps do not need that the Objects implement Comparable (They use hashcode())
I have two objects of classes Person and Employee.
Both classes have common attribute age.
And I have added few objects of both theses classes to an Arraylist and now I want two write one Comparator and pass it to sort method of Collections class.
And want the list to be sorted on the basis of age.
I am trying this just for getting more clarity on use of Comparable and Comparator in Java.
EDIT:
Reason Why I was asking this question was that I was not clear about Comparator and Comparable.
I read somewhere that If Class implements Comparable then it can not be compared against objects of other classes (Because of Class cast exception).
Now if I create relation ship in Employee and Person then there is no need to implement Comparator (Unless I want to do sorting on the basis of name or other common attribute of these classes).
Once Again, I have asked this question to get more clarity on Comparator and Comparable.
Till now, What I have been able to understand is that If I want to do sorting on more than one parameters then I should implement Comparator and pass it to Collections.srot().
Or If I don't have control over the Class of object being sorted, then custom sorting I should implement Comparator.
(Correct me if I am wrong or I am missing something)
EDIT
I think now I understand the use of Comparable and Comparator.
To make sure I got the right concepts, here is what I understand:
If I want to compare two objects of different classes (and having no relation ) then I should use raw comparator and override the compare method.
Another reason why somebody would implement Comparator instead of Comparable is
to have flexibility in sorting.
And what I understand from natural sorting is the logic implemented by Class in CompareTo method.
Hope I am correct with all these points.
You can define an interface called Ageable and Employee and Person can implement this interface. Also you can define an abstract class (and Employee and Person will be inherited from the abstract class) with the same effect. Note that you can also use a normal class for this reason, you can do whatever you need.
Also, if there is no reason to say that an Employee is not a Person (for instance robots are working at the office) then Employee can be inherited from Person.
I would make an Employee a sub-class of Person. (Assuming all your employees are people) Then you can create a Comparator<Person>
You should create an interface AgeProvider:
public interface AgeProvider {
int getAge();
}
Both Person and Employee should implement AgeProvider. Now you can implement a Comparator that compares 2 AgeProvider.