比较优越的比较器是什么?

bra*_*orm 5 java sorting comparable comparator

"您将如何按其ID或名称对员工对象的集合进行排序".为此,我们可以使用两个接口,即,Comparator and Comparable. 这似乎是常见的面试问题之一

但我没有看到为什么我应该使用它们来排序员工对象的原因

我一直在思考comparator那些Comparable做不到的事情.我理解,如果对象(被比较的实例变量)具有自然顺序,那么这comparable是正确的选择.但是如果需要自定义排序(例如字符串长度)那么可以comparator. 在这里写一个我的观点,comparator如果他想要通过其他一些标准对数据进行排序,则只需要客户端.例如,我将实现一个使用Employee class排序.但是如果客户端希望按(名称)对Employee对象进行排序,他将实现为具体类或匿名排序.这里有什么我想念的吗?idcomparable interfaceStringcomparator

例如,在下面的代码中,对于Person对象,我的compareTo方法,比较年龄并对其进行排序.在compare方法中,我使用String length(人名)进行排序.从理论上讲,我可以在compareTo方法中完成这两个方法,如下所示.

最后,除了其他方面之外还有其他任何好处,我已经用两种方式实现了比较器1.作为一个静态方法,它被注释掉2.作为主方法中的匿名对象(?)被注释掉3. make一个实现比较器并在collections.sort()中调用该类实例的新类 - 我还没有在这里完成

(The commented-out parts of the code works. They are just different implementations)

mport java.util.Collections;
import java.util.Comparator;
import java.util.*;

public class PersonComparator implements Comparable{
    private String name;
    private int age;

    public PersonComparator(String name, int age) {
        this.name = name;
        this.age = age;
    }
@Override
public String toString() {
    return "name=" + name + ", age=" + age;
}

/*@Override
public int compareTo(Object obj) {
    if (!(obj instanceof PersonComparator)) {
        throw new ClassCastException("Invalid object");
    }
    PersonComparator p2 = (PersonComparator)obj;
    return this.age-p2.age;
}*/

/*Alternative CompareTo that checks for both age and name*/
 public int compareTo(Object obj) {
    if (!(obj instanceof PersonComparator)) {
        throw new ClassCastException("Invalid object");
    }
    PersonComparator p2 = (PersonComparator)obj;
    if (this.age!=p2.age){
        return this.age-p2.age;
    }
    else {
    return (this.name.length()-p2.name.length());
}
} 


/*public static Comparator nameLengthComparator 
= new Comparator() {


    @Override
    public int compare(Object obj1, Object obj2) {
        if (!(obj1 instanceof PersonComparator) || !(obj2 instanceof PersonComparator)){
            throw new ClassCastException("Invalid object");
        }
        else {
            PersonComparator p1 = (PersonComparator)obj1;
            PersonComparator p2 = (PersonComparator)obj2;
            return p1.name.length()-p2.name.length();
        }
}
};*/

 public static void main(String[] args){
     PersonComparator p1 = new PersonComparator("Alexander", 45);
     PersonComparator p2 = new PersonComparator("Pat", 27);
     PersonComparator p3 = new PersonComparator("Zacky", 45);
     PersonComparator p4 = new PersonComparator("Rake", 34);

     List<PersonComparator> list = new ArrayList<PersonComparator>();
     list.add(p1);
     list.add(p2);
     list.add(p3);
     list.add(p4);

     System.out.println("Before sorting "+ list);
     Collections.sort(list);
     //System.out.println("After sorting by age "+ list);
     //System.out.println("Before sorting "+ list);
     //Collections.sort(list, nameLengthComparator);
     System.out.println("After sorting by name length "+ list);
     /*Collections.sort(list, new Comparator<PersonComparator>() {
         @Override
            public int compare(PersonComparator p1, PersonComparator p2) {
                    return p1.name.length()-p2.name.length();
                }
        }
    );*/
     System.out.println("After sorting by name length "+ list);
 }

}
Run Code Online (Sandbox Code Playgroud)

谢谢

Ste*_*n C 8

比较器的优势是什么?

它不是"优越的".只是两个接口以不同的方式(大致)做同样的事情.在Comparable订购逻辑位于订购对象的情况下.在这种Comparator情况下,逻辑与声明的对象位于不同的类中.

但我没有看到为什么我应该使用它们来排序员工对象的原因

如果您需要能够将对象排序为不同的顺序,那么使用两者的唯一情况是有意义的.然后,您可以将相关类声明为实现Comparable"自然"订单,并使用Comparator对象来实现其他订单.

顺便说一下,比较器可能不应该实现Comparable,反之亦然.

如果比较器实现Comparable意味着您正在尝试对比较器对象本身的实例进行排序......

你的PersonComparator班级名不副实.它应该真的被称为Person.


你能否在答案中澄清一下我们已经有equals()来自Object类的方法然后为什么Comparator界面equals()再次促进该方法?

一些要点:

  • 你似乎仍然是混乱的目的ComparableComparator.对象equals上的方法Comparator将比较器与其他比较器进行比较!

  • equals方法告诉您两个对象是否相等...而不是哪一个是第一个.

  • 其原因Comparator覆盖equals仅仅他们能够清楚地记录了什么equals(Object),当你把它叫做上确实Comparator对象.(实际行为完全符合Object.equals(Object)......但他们显然认为有必要这样做,因为程序员反复得到方法的语义错误.)


Deb*_*kia 7

Comparable 接口

Comparable接口定义了一个类型的自然排序.假设您有一个String或多个Integer对象的列表; 你可以将该列表传递给

Collections.sort(list);
Run Code Online (Sandbox Code Playgroud)

你将有一个排序列表.怎么样?因为String并且Integer实现Comparable接口和接口的实现Comparable提供了自然的顺序.它就像类定义那样 - " 如果找到我的类型的对象集合,请根据我在compareTo方法中定义的策略对它们进行排序 ".

现在,当您定义自己的类型时,可以通过实现接口来定义类的对象的自然顺序Comparable.有关对象排序的更多信息,请参阅Java文档.

Comparator 接口

Comparator接口描述了如何为对象排序定义自定义策略.假设我们有一个简单的Person类型如下:

public class Person {
    String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,通过实现Comparator界面,您可以编写不同的策略来订购Person类型的实例.例如,考虑Person下面给出的两个对象排序策略:

class StrategyOne implements Comparator<Person> {

    @Override
    public int compare(Person p1, Person p2) {
        return p1.getName().length() - p2.getName().length();
    }

}

class StrategyTwo implements Comparator<Person> {

    @Override
    public int compare(Person p1, Person p2) {
        return p1.getName().compareTo(p2.getName());
    }

}
Run Code Online (Sandbox Code Playgroud)

在这里,StrategyOne将责令Person基于其名称的长度对象,StrategyTwo订货会Person根据他们的名字的字典顺序对象.

实施方式 Comparator

如您所见,具体策略类是无状态的,因此所有实例在功能上都是等效的.因此,我们只需要任何具体策略类的单个实例.因此,它应该是一个单身人士.每次执行调用时,使用匿名类将创建一个新实例.考虑将对象存储在私有静态final字段中,并使用静态工厂方法重新访问它们.例如,您可以重复使用以下两种具体策略:

class Strategies {
    private static final Comparator<Person> PERSON_NAME_LENGTH_COMPARATOR = new StrategyOne();

    private static final Comparator<Person> PERSON_NAME_LEXICAL_COMPARATOR = new StrategyTwo();

    public static Comparator<Person> personNameLengthComparator(){
         return  PERSON_NAME_LENGTH_COMPARATOR;
    }


    public static Comparator<Person> personNameLexicalComparator(){
         return  PERSON_NAME_LEXICAL_COMPARATOR;
    }
}
Run Code Online (Sandbox Code Playgroud)

摘要

总而言之,Comparable接口用于定义类的自然顺序,Comparator接口用于定义对象排序的特定策略.