Reputation: 17023
I'm trying to create a class that can either be compared to an instance of the same class, or to String
.
For example, consider the following:
public class Record implements Comparable<Record> {
public String name;
public Record(String name) {
this.name = name;
}
public int compareTo(Record o) {
return name.compareTo(o.name);
}
}
I then place this into an ArrayList
as follows:
ArrayList<Record> records = new ArrayList<Record>();
records.add(new Record("3"));
records.add(new Record("1"));
records.add(new Record("2"));
If I then sort them, they are sorted properly:
Collections.sort(records);
However, I not want to be able to get a record via binary search based on a string. For example:
int index = Collections.binarySearch(records, "3");
The problem is that there is no compareTo
method that takes a String as argument, and I'm unsure how to implement it.
I tried doing:
public class Record implements Comparable<Record>, Comparable<String> {
public String name;
public Record(String name) {
this.name = name;
}
public int compareTo(Record o) {
return name.compareTo(o.name);
}
public int compareTo(String o) {
return name.compareTo(o);
}
}
But, of course, you cannot implement the same interface with different arguments more than once.
So, I'm looking for a method to do the above. I have looked at the following previous answers, but have not found one that truly answers this sufficiently. At least, if it did, I did not understand it.
Basically, what I want to do is the following:
public int compare(Record r, String s) {
return r.name.compareTo(s);
}
As far as I can tell, though, you cannot compare objects of differing types without implementing some sort of common interface or superclass. I don't really have that option with String
.
Can someone please show me how to do this, if it is possible? Thanks.
UPDATE I realize that I could do the following:
Collections.binarySearch(records, new Record("3"));
But, that is not what I'm after. Thanks.
Upvotes: 2
Views: 2687
Reputation: 42040
You can try the next for getting the index in the sorted collection:
class Record implements Comparable<String> {
public String name;
public Record(String name) {
this.name = name;
}
@Override
public int compareTo(String o) {
return name.compareTo(o);
}
}
And:
public static void main(String[] args) {
ArrayList<Record> records = new ArrayList<Record>();
records.add(new Record("3"));
records.add(new Record("1"));
records.add(new Record("2"));
Collections.sort(records, new Comparator<Record>() {
@Override
public int compare(Record a, Record b) {
return a.name.compareTo(b.name);
}
});
int index = Collections.binarySearch(records, "3");
System.out.println(index); // 2
}
Upvotes: 1
Reputation: 1344
You cannot do that. from javadoc
It follows immediately from the contract for compareTo that the quotient is an equivalence relation on C and String's compareTo will never return true for your Record.
What you could do, is create Comparator that would compare Strings and Records. Just leave it without generics.
Upvotes: 1
Reputation: 13133
Is there some problem with defining the interface ComparableToString and implementing it? Its compareTo method can restrict callers to String. No instanceof, no casting required.
public class Record implements Comparable<Record>, ComparableToString
{
public String name;
public Record(String name)
{
this.name = name;
}
public int compareTo(Record o)
{
return name.compareTo(o.name);
}
public int compareTo(String o)
{
return name.compareTo(o);
}
}
interface ComparableToString
{
public int compareTo(String s);
}
Upvotes: 0
Reputation: 1700
You can implement Comparable without qualifying it with a type, and check the incoming Object with instanceof, and behave differently depending on what type you receive.
Upvotes: 4