2013-02-25 3 views
3

Я пытаюсь создать класс, который можно либо сравнить с экземпляром того же класса, либо String.Java, сопоставимый с экземпляром или строкой

Для примера рассмотрим следующее:

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); 
    } 
} 

Затем я кладу это в ArrayList следующим образом:

ArrayList<Record> records = new ArrayList<Record>(); 
records.add(new Record("3")); 
records.add(new Record("1")); 
records.add(new Record("2")); 

Если я затем отсортировать их, они сортируются правильно:

Collections.sort(records); 

Однако я не хочу получать запись через двоичный поиск на основе строки. Например:

int index = Collections.binarySearch(records, "3"); 

Проблема заключается в том, что нет compareTo метода, который принимает строку в качестве аргумента, и я не уверен, как это осуществить.

Я попытался сделать:

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); 
    } 
} 

Но, конечно, вы не можете реализовать тот же интерфейс с различными аргументами более чем один раз.

Итак, я ищу способ сделать это. Я рассмотрел следующие предыдущие ответы, но не нашел того, который действительно достаточно прав. По крайней мере, если бы это было так, я не понял этого.

В общем, что я хочу сделать, это следующее:

public int compare(Record r, String s) { 
    return r.name.compareTo(s); 
} 

Насколько я могу судить, вы не можете сравнивать объекты разных типов без реализации своего рода общий интерфейс или суперкласс. У меня нет такого варианта с String.

Может кто-нибудь, пожалуйста, покажите мне, как это сделать, если это возможно? Благодарю.

UPDATE Я понимаю, что я мог бы сделать следующее:

Collections.binarySearch(records, new Record("3")); 

Но это не то, что я после. Благодарю.

+1

В Java, вы всегда ** ** имеют общий суперкласс, 'Object' , –

+0

@PatriciaShanahan Если я использую 'Comparable ', не будет ли позволять сравнивать с объектами, отличными от 'String' или' Record', хотя? – crush

+0

Включено ли int int, что ** всегда ** список? – skuntsel

ответ

4

Вы можете реализовать Comparable без квалификации его с типом и проверить входящий объект с instanceof и вести себя по-разному в зависимости от того, какой тип вы получаете.

+0

И если это не ожидаемый тип, я должен сделать исключение? – crush

+1

Да, согласно API сопоставления, бросайте ClassCastException, если он не является ожидаемым типом –

0

Есть ли проблемы с определением интерфейса ComparableToString и его внедрением? Метод compareTo может ограничивать вызывающих абонентов для String. Нет экземпляра, не требуется литье.

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); 
    } 
+0

Можете ли вы привести пример того, что вы имеете в виду? – crush

+0

'Collections.binarySearch (записи,« 3 »);' не работает с этим примером. Я уже пробовал это. Я получаю сообщение об ошибке: 'Метод binarySearch (List >, T) в типе Collections не применим для аргументов (ArrayList , String)' – crush

+0

Да, это не будет работать для вашего * расширенного * вопрос - для вашего оригинала «Я пытаюсь создать класс, который можно либо сравнить с экземпляром того же класса, либо с помощью String». Это нормально. Но вы также хотите передать полученный класс тому, что будет использовать интерфейс Comparable, и это не справится с этим. – arcy

1

Вы не можете этого сделать. от 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.

Что вы можете сделать, это создать компаратор, который будет сравнивать строки и записи. Просто оставьте это без дженериков.

+0

также из javadoc: 'Настоятельно рекомендуется (хотя и не обязательно), чтобы естественные порядки были согласованы с equals.' –

1

Вы можете попробовать следующее для получения индекса в отсортированной коллекции:

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); 
    } 

} 

И:

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 

} 
+0

Поэтому вместо того, чтобы делать это' Comparable ', я делаю это только' Comparable 'без определения пользовательского' Comparator' , Это неплохая идея. Я мог бы сделать это еще дальше, инкапсулируя «новый компаратор () {}' в 'public Comparator метод getComparator() {}' в моем классе записи, я полагаю. – crush

Смежные вопросы