2010-09-14 1 views
1

Мне нужно отсортировать списки объектов с нестатическим компаратором, который использует значение из его внешнего поля объекта.Java: ссылка от нестатического компаратора на его внешнее поле класса

class A { 
    public int x; 
    public int y; 
    public int z; 

    public Comparator<A> scoreComparator = new Comparator<A>() { 
     public compare(A o1, A o2) { 
      // System.out.println("this: " + this); 
      return (int) (x * o1.x - x * o2.x); 
     } 
    } 

    public A(int _x, int _y, int _z) { 
     x = _x; 
     y = _y; 
     z = _z; 
    } 
} 

A var_1 = new A(1, 2, 3); 
A var_2 = new A(5, 6, 7); 
List<A> list = getMyListFromSomewhere(); 

// the following will produce different ordering 
Collections.sort(list, var_1.scoreComparator); 
Collections.sort(list, var_2.scoreComparator); 

Но по какой-то причине это не работает должным образом. Когда я раскомментирую строку println в компараторе, это показывает, что ссылки относятся к объектам A, но они различаются внутри одного вызова sort(), поэтому значение «x» отличается. Что я здесь делаю неправильно?

ответ

1

Можете ли вы объяснить, почему вам нужен Comparator нестатический? Почему не только следующее?

 
    static class MyComparator implements Comparator { 
     public compare(A o1, A o2) { 
      // System.out.println("this: " + this); 
      return o1.x - o2.x; 
     } 
    } 

    public Comparator scoreComparator = new MyComparator(); 
+0

В вашем примере не учитывается внутреннее состояние другого объекта. То, что я хочу достичь, - это различный порядок в зависимости от того, какой экземпляр A я беру как «базу». Например: у меня есть объекты v1 и v2 - оба экземпляра A. У меня есть список [v3, v4, v5]. Когда я сортирую с «базовым» v1, я получаю [v4, v5, v1], когда сортирую «основанный» на v2, я получаю [v5, v1, v4]. Порядок отсортированного списка зависит от внутренних значений полей v1 и v2 соответственно. – osjak

+0

Хорошо, ваш код выглядит хорошо. Можете привести несколько примеров? – gpeche

+0

И вообще, я бы сделал компаратор статическим классом и передал бы «x» в качестве пареметра к его конструктору. – gpeche

0

Это зависит от того, чего вы хотите достичь. Приведенный выше код не работает, потому что вы используете разные значения x при создании экземпляров A.

Каждый раз, когда вы создаете экземпляр A, вы также создаете экземпляр компаратора, который привязан к экземпляру A. Это означает, что x в методе compare() является либо o1.x, либо o2.x.

Я предлагаю создать новый класс, который реализует компаратор и который имеет поле x, чтобы сделать его независимым от A:

public class ScoreComparator implements new Comparator<A>() { 
    private int x; 
    public ScoreComparator(int x) { this.x = x; } 
    public compare(A o1, A o2) { 
     // System.out.println("this: " + this); 
     return (int) (x * o1.x - x * o2.x); 
    } 
} 
+0

"Это означает, что x в методе compare() является либо o1.x, либо o2.x." - Не понял? –

+0

Когда я передаю «var_1.scoreComparator» в качестве моего компаратора, не имеет ли уже ссылку на var_1? Поэтому, когда JVM смотрит на «(x * o1.x - x * o2.x)», он переведет его в «(var_1.x * o1.x - var_1.x * o2.x)». Разве это не так? – osjak

+0

Я перечитал ваш комментарий, и я думаю, что ваше решение отлично подойдет для меня. Я могу, конечно, передать значение «х» компаратору. Спасибо! Но я до сих пор не понимаю, почему мое решение не получилось. – osjak

0

Давайте посмотрим, что первый scoreComparator делает. Линия

(int) (x * o1.x - x * o2.x) 

можно также записать в виде

(int) x * (o1.x - o2.x) 

что означает знак x - положительный или отрицательный результат инвертирует Comparation вернется упорядоченность в сортировочном списке.

Casting к int добавляется, чтобы обеспечить целочисленное переполнение, если значения x и o1.x или x и o2.x слишком велики. Опять же, знак x просто вернет порядок.

Поскольку и var_1, и var_2 имеют положительные значения для поля x, мы можем заключить, что второй сценарий вызывает целочисленное переполнение и различное упорядочение. var_1.x равно 1 и var_2.x равно 5, что в последнем случае делает число, превышающее в пять раз более вероятным.

0

Я не уверен на 100%, чего вы хотите достичь этим дизайном, но это очень плохой дизайн. Если вы хотите, чтобы нестатический компаратор находился внутри одного и того же типа класса, попробуйте сравнить compareTo, а не сравнивать. В противном случае поместите метод сравнения в отдельный класс, как предложил @Aaron.

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