【问题标题】:Deciding to use Comparable or Comparator决定使用 Comparable 或 Comparator
【发布时间】:2012-11-12 15:51:02
【问题描述】:

我的程序实现了一个 Product 类,其对象包含以下实例变量:nameprioritypriceamount

我有一个LinkedListProduct 对象,在对LinkedList 执行任何其他操作之前,我需要对其进行排序。

我想首先按优先级(从最低到最高)对列表进行排序。如果优先级相同,则查看价格(从低到高),然后查看名称(按字母顺序)。

我已经阅读了大量关于Collections.sortComparableComparator 的内容。我相信我需要使用Comparable 接口并实现compareTo 方法。我的想法是,因为prioritypricename 都具有“自然”顺序,所以使用Comparable 更有意义。

public class Product extends ProductBase implements PrintInterface, Comparable<Product>{
    private String name;
    private int priority; 
    private int cents;
    private int quantity;

    // setters and getters

    /**
    * Compare current Product object with compareToThis
    * return 0 if priority, price and name are the same for both  
    * return -1 if current Product is less than compareToThis
    * return 1 if current Product is greater than compareToThis
    */ 

    @override
    public int compareTo(Product compareToThis)
}

然后,当我想对我的 LinkedList 进行排序时,我只需调用 Collections.sort(LinkedList)。在我开始编写代码之前,你能告诉我我是否遗漏或忘记了什么吗?

************ *更新********** *************** ******

我刚刚使用比较方法创建了一个名为 ProductComparator 的单独类。

这是 LinkedList 类的一部分。

import java.util.Collections;

public class LinkedList {

private ListNode head; 

public LinkedList() { 
    head = null;
}
     // this method will sort the LinkedList using a ProductComparator
public void sortList() {
    ListNode position = head;
    if (position != null) {
        Collections.sort(this, new ProductComparator());
    }
}
// ListNode inner class
private class ListNode {

    private Product item;
    private ListNode link;

    // constructor
    public ListNode(Product newItem, ListNode newLink) {
        item= newItem;
        link = newLink;
    }
}

}

我在编译时从 IDE 收到以下错误。

Collections 类型中的方法 sort(List, Comparator) 不适用于参数 (LinkedList, ProductComparator)。

有谁知道我为什么会收到此错误并可以指出正确的方向来解决它?

【问题讨论】:

  • 对于您更新的问题:您是否在 ProductComparator 中正确实施了 Comparator?

标签: java comparator comparable


【解决方案1】:

如果您的订单仅基于数字,Comparable 就可以了。

但是,由于您的顺序(有时)涉及文本的词汇顺序, Comparator 类更好,因为使用 Comparable 意味着使用 String.compareTo 这会阻止您进行国际化。

实现Comparator 的单独类可以使用 本地化 Collator 用于比较字符串。例如:

public class ProductComparator
implements Comparator<Product> {
    private final Collator collator;

    public ProductComparator() {
        this(Locale.getDefault());
    }

    public ProductComparator(Locale locale) {
        this.collator = Collator.getInstance(locale);
    }

    public int compare(Product product1,
                       Product product2) {

        int c = product1.getPriority() - product2.getPriority();
        if (c == 0) {
            c = product1.getPrice() - product2.getPrice();
        }
        if (c == 0) {
            c = collator.compare(product1.getName(), product2.getName());
        }
        return c;
    }
}

不管你是用 Comparable 还是 Comparator ,都是明智的 确保Product 有一个检查相同的equals 方法 属性作为比较代码。

【讨论】:

  • 感谢 VGR。那么调用 Collections.sort 的正确方法是什么?是 Collections.sort(MyLinkedListOfProductObjects, new ProductComparator) 吗?
  • 我尝试了您的建议来实现 Comparator 类对象并将其传递给 Collections.sort。我收到一条错误消息,我不知道为什么。我从 IDE 得到的错误消息是:Collections 类型中的方法 sort(List, Comparator super T>) 不适用于参数(LinkedList、ProductComparator)。你知道我遇到了这个错误,你能指出我正确的方向吗?
  • 这是我的 LinkedList 代码的一部分。导入 java.util.Collections;公共类 LinkedList { 私有 ListNode 头;公共 LinkedList() { 头 = null; } public void sortList() { ListNode position = head; if (position != null) { Collections.sort(this, new ProductComparator()); } } 私有类 ListNode { 私有产品项;私有 ListNode 链接;公共 ListNode(Product newItem, ListNode newLink) { item= newItem;链接=新链接; } } }
  • 我在 cmets 中正确格式化了我的代码。对不起。我会尝试更新 OP
【解决方案2】:

您在此处定义的产品顺序非常具体,并且

  • 可能会在您的程序的未来版本中发生变化
  • 可能会通过上下文参数化来丰富
  • 不会涵盖新功能

所以很难说“自然”。

我建议定义一个常量,例如

public static Comparator<Product> STANDARD_COMPARATOR = new Comparator<Product>() {
    public int compare(Product p1, Product p1) {
        return ...
    }
};

那么您就可以轻松地在任何地方进行排序

Collections.sort(myProductList, Product.STANDARD_COMPARATOR);

随着您添加其他比较器,您的代码将以更好的方式发展。

就像您通常更喜欢组合而不是继承一样,您应该尽量避免以不可变的方式定义对象的行为。

【讨论】:

  • 嗨,dystroy,我不太明白。您能否提供一个更详细的建议示例?
  • 是的,我想是的,但我确信在开始编码时会遇到一些问题。
  • 嗨,Dystroy,我还有一个问题。我读过的所有 Comparator 示例都使它成为一个单独的类。例如,Java doc docs.oracle.com/javase/tutorial/collections/interfaces/… 中的示例我也应该这样做,而不是让它成为我的 Product 类中的常量吗?
【解决方案3】:

如果存在“自然”排序,请使用 Comparable。判断顺序是否“自然”的经验法则是,对象的顺序是否总是如此。

话虽如此,使用 Comparable 还是 Camparator 的决定并不是你需要考虑太多的决定。大多数 IDE 都有重构工具,这使得 Comparable 和 Comparator 之间的转换非常变得容易。所以如果你现在选择走错路,改变它不需要太多的努力。

【讨论】:

  • 当您在团队中或与客户一起编码时,您最好拥有良好且不断发展的 API,而不是指望您的 IDE 稍后修复它们。
  • 完全同意。但是 Comparable 接口几乎从来都不是(使用的)公共 API 的一部分,除非它确实是一个自然顺序。如果有人在不代表自然顺序的情况下使用它,那可能是因为他们不在乎顺序是什么。
猜你喜欢
  • 2011-01-17
  • 2014-11-24
  • 1970-01-01
  • 2020-11-22
  • 2014-04-04
  • 2022-12-31
  • 1970-01-01
  • 2013-01-28
  • 2010-11-29
相关资源
最近更新 更多