【问题标题】:Making a comparator for two classes that extend super为两个扩展 super 的类做一个比较器
【发布时间】:2013-10-16 09:09:03
【问题描述】:

抱歉,我事先对泛型的了解有限

我有以下情况:

第 1 类:

public class PostProcess implements Serializable {
    public int          order;
    // Several other variables.

    // Constructor setting vars
    public PostProcess(){

    }

    /* Getters and setters for variables */
}

第 2 类:

public class Application extends PostProcess{
    public int      subOrder;
    // Several other variables.

    // Constructor setting vars
    public Application(){

    }

    /* Getters and setters for variables */

}

第 3 类:

public class FileOperation extends PostProcess{
    public int      subOrder;
    // Several other variables (different from class 'Application').

    // Constructor setting vars
    public FileOperation(){

    }

    /* Getters and setters for variables */

}

我试图在不同的类中实现的是对包含定义为“FileOperation”和“Application”对象的列表进行排序:

private ArrayList<? extends PostProcess> processList = new ArrayList<PostProcess>();

这种排序必须在这两个对象的两个字段上,即:'order' 和 'subOrder'。 'order' 继承自 PostProcess,'subOrder' 定义在 'Application' 和 'FileOperation' 类中。

在我阅读泛型、可比较、比较器和接口的整个过程中,我认为我把事情搞混了。

我正在尝试使用以下方式应用排序:

Collections.sort(processList, new PostProcessComparator());

PostProcessComparator 定义为:

public class PostProcessComparator implements Comparator<? extends PostProcess> {

    @Override
    public int compare(Object p1, Object p2) {

      int mainOrderCompare = p1.getOrder().compareTo(p2.getOrder());
      if (mainOrderCompare != 0) {
        return mainOrderCompare;
      } else {
        return p1.getSubOrder().compareTo(p2.getSubOrder());
      }
    }
}

问题:

我知道我的 Comparator(可能还有更多)是错误的,但我不知道具体在哪里。我是来学习的;)

  1. 我注意到定义“processList”列表不是正确的方法。当我尝试将 'FileOperation' 或 'Application' 对象添加到 List 时,编译器会以“找不到适合 add(Application) 的方法”(FileOperation 相同)打我耳光。我是否错误地假设我可以使用泛型来声明我的 processList 类型?应该是正确的,因为这两个类都将 PostProcess 作为它们的超类,对吧?
  2. 用类边界定义 PostProcessComparator 在我看来应该可行,因为我只希望能够比较具有 PostProcess 作为超类的对象(因此可以访问相同的方法)。
  3. 如何访问 Comparator 类中 p1 和 p2 的参数对象(因为我仍然需要为参数声明它们的类型:

    @Override
    public int compare(<What to put here?> p1, <And here?> p2) {
    
    }
    

真心希望大家帮忙! 如果我有什么不清楚的地方,请告诉我并详细说明。

谢谢!

编辑

感谢 NickJ 和 Winzu,我对比较器和 ArrayList 定义进行了必要的更改。

  • 我已将 subOrder 从 Application 和 FileOperation 移至父类(并使其受到保护)
  • 将比较器的参数化重新定义为:

    public class PostProcessComparator<T extends PostProcess> implements Comparator<T> 
    
  • 使用 Integer.compare(p1.getOrder(), p2.getOrder()) 进行初始比较器比较。

现在是最后的挑战(编译器警告) 调用时:

    Collections.sort(processList, new PostProcessComparator());

我收到警告: - [unchecked] 未经检查的方法调用:类 Collections 中的方法排序应用于给定类型

    required:  List<T>,Comparator<? super T>
    found: ArrayList<PostProcess>,PostProcessComparator

在我看来,这个比较器的参数化是正确的,除了我没有检查对象类型。

这哪里出错了?

【问题讨论】:

  • 设计问题——为什么不将 subOrder 属性放在 PostProcess 类中,并使其受到保护,例如,派生类可以使用它?
  • @AlexAdas 这是个好主意。我还没有考虑过。让我试试看!谢谢
  • 更新了我对您最后一个问题的回答
  • 非常感谢 Winzu。完美的工作。现在很难选择正确的答案,因为它分为两部分。 +2 给你。非常感谢您的帮助。

标签: java generics inheritance collections comparator


【解决方案1】:

我发现的唯一问题是你需要像这样参数化 PostProcessComparator:

public class PostProcessComparator<T extends PostProcess> implements Comparator<T> {

  @Override
  public int compare(T p1, T p2) {

    int mainOrderCompare = p1.getOrder().compareTo(p2.getOrder());
    if (mainOrderCompare != 0) {
      return mainOrderCompare;
    } else {
      return p1.getSubOrder().compareTo(p2.getSubOrder());
    }
  }
}

现在 compare() 方法将接受正确的类(扩展 PostProcess),因此可以从 complpare() 中调用 PostProcess 的任何公共方法

最后,您的字段不应公开。我建议将字段设置为受保护的,这样子类仍然可以继承它们,但会保持封装。

【讨论】:

  • 您不能在原始类型 int 上使用 compareTo。使用运算符“ - ”或 Integer.compare(p1.getOrder(), p2.getOrder());
  • 好点!我只是复制了原始代码更改了泛型参数化。
  • @NickJ 非常感谢它似乎确实有效。然而另一个编译器错误告诉我我的 p1 和 p2 对象没有方法 getSubOrder() (找不到符号)。哪一个可能是正确的,因为我声明我的列表只包含 类型而不包含它的子类型?对象 p1(T 类型)和 p2 不能访问 getSubOrder() 方法吗?
  • 否 - 因为 T 扩展了 PostProcess,所以比较器只知道 PostProcess 中定义的方法,而不知道它的任何子类。如果您需要调用子类方法,请使用单独的比较器,每个子类一个,或者使用 instanceof 检查实际类,然后将它们强制转换。
【解决方案2】:

上面 NickJ 的回答显示了如何实现比较器。

对于你正在做的事情你也想改变

private ArrayList<? extends PostProcess> processList = new ArrayList<PostProcess>();.

ArrayList<PostProcess> processList = new ArrayList<PostProcess>();

这就是为什么您不能将 Application et FileOperation 对象添加到列表中的原因。

这有点棘手。或许这篇文章可以帮助你理解

Java using generics with lists and interfaces

您还希望在父类中使用 SubOrder。

import java.io.Serializable;

public class PostProcess implements Serializable {
private int          order;
private int      subOrder;
// Several other variables.

public int getSubOrder() {
    return subOrder;
}

public void setSubOrder(int subOrder) {
    this.subOrder = subOrder;
}

public int getOrder() {
    return order;
}

public void setOrder(int order) {
    this.order = order;
}

// Constructor setting vars
public PostProcess(){

}

}

最后像这样调用比较器以避免未经检查的警告:

 Collections.sort(processList, new PostProcessComparator<PostProcess>());

【讨论】:

  • 谢谢Winzu!这成功了(对于编译器),但比较器中定义的 p1 和 p2 对象(T 类型)现在无法访问(找不到符号)getSubOrder 方法。这是因为 ArrayList 限制了可访问的方法吗?
  • 由于您的 Application 和 FileOperation 对象都有一个 SubOrder,我认为 SubOrder 没有理由不在 PostProcess 类中。让我编辑答案。
  • 谢谢。我已经使用当前的解决方案和最后出现的编译器警告进行了编辑。
【解决方案3】:

只需将其更改为:

public class PostProcessComparator implements Comparator<PostProcess> {
    @Override
    public int compare(PostProcess p1, PostProcess p2) {
      //...
    }
}

就是这样。你有一个比较器,可以比较PostProcess 的任意两个实例(PostProcess 的子类实例是PostProcess 的实例)。

【讨论】:

  • 最初我将“subOrder”字段添加到子“FileOperation”和“Application”中。通过将传递的对象转换为“PostProcess”,我将无法访问这些访问器方法,因为它们没有被“PostProcess”继承,对吗?通过修改我的设计(将 subOrder 移动到父类 PostProcess),这将是一个解决方案。但是,如果我理解正确,当 subOrder 仅是孩子的一部分时,您的解决方案就不会起作用?还是我在这里弄错了?
  • @Rhizosis: 但PostProcess 会有一个getSubOrder() 方法,对吧?因为否则,接受的解决方案也不起作用,因为T 拥有getSubOrder() 方法的唯一方法是PostProcess 拥有它。
猜你喜欢
  • 2013-02-25
  • 1970-01-01
  • 2011-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-18
相关资源
最近更新 更多