簡體   English   中英

如何使用實現相同接口的不同對象對列表進行排序?

[英]How can I sort a list with different objects that implement the same interface?

我有一個抽象類:

public abstract class Employee implements Comparable<Employee>{
  public Double getSalary();


    @Override
    public Double compareTo(final Employee employee2) {
    }
}

擴展此抽象類的兩個類:

public class Manager {
  public Double getSalary(){}
}

public class Chef{
  public Double getSalary(){}
}

我想對它進行排序,以便列表中的所有Chef對象都在前面,然后在所有Chef對象之后,我希望Manager對象按降序排序,並以最高薪水排序。 換句話說,對於Chef對象,我只希望將它們推到列表的前面,沒有別的。 對於Manager對象,我希望它們按薪水排序,並在Chef對象之后放在列表的末尾。

例如

Manager manager1 = new Manager(40000);
Manager manager2 = new Manager(50000);
Manager manager3 = new Manager(60000);
Chef chef1 = new Chef(25000);
Chef chef2 = new Chef(25500);
Chef chef3 = new Chef(28000);
Chef chef4 = new Chef(29000);
List<Employee> employees = new ArrayList<Employee>();
employees.add(manager3);
employees.add(manager1);
employees.add(chef1);
employees.add(chef3);
employees.add(manager2);
employees.add(chef4);
employees.add(chef2);

排序后,列表中的元素可能是這樣的:

0. chef1 = 25000 // Chef objects pushed to front but not sorted by salary
1. chef3 = 28000
2. chef4 = 29000
3. chef2 = 25500
4. manager3 = 60000 // Manager objects pushed to the back and sorted by salary
5. manager2 = 50000
6. manager1 = 40000

我的compareTo方法:

@Override
public int compareTo(final Employee employee2) {
    if (this instanceof Manager|| employee2instanceof Manager) {
        return employee2.getSalary().compareTo(this.getSalary());
    }

    return -1;
}

但是,這會將Manager對象置於最前面。 我對如何使用compareTo方法中的Chef對象感到困惑。

您的情況聽起來像創建Comparator比實現Comparable更合適:后者專門用於建模類的實例的自然順序

例如, Integer implements Comparable<Integer>Integer implements Comparable<Integer>有一個非常明顯的自然排序。

您的案例聽起來更像是一個關於如何對它們進行排序的一次性案例,例如在特定報告中出現。

另外,我認為當父類需要知道它們的子類時,這是一種代碼味道。 沒有什么可以阻止創建新的子類; 沒有必要更新Employee來處理這個事實。

很容易從一個轉換為另一個:不是將int compare(Employee that)方法添加到Employee ,而是在比較器中實現一個方法:

class ChefsAndManagersComparator implements Comparator<Employee> {
  @Override
  public int compare(Employee employee1, Employee employee2) {
    // The logic from any of the other answers,
    // just replacing "this" references with "employee1"
  }
}

您可以使用3個列表,因此您不必檢查特定的子類型:

List<Chef> chefs = new ArrayList<Chef>();
List<Manager> managers = new ArrayList<Manager>();

managers.add(manager3);
managers.add(manager1);
chefs.add(chef1);
chefs.add(chef3);
managers.add(manager2);
chefs.add(chef4);
chefs.add(chef2);

Collections.sort(managers);

List<Employee> employees = new ArrayList<Employee>();
employees.addAll(chefs);
employess.addAll(managers);

但是,如果您無法更改員工存儲的實現方式,您仍然可以遍歷員工列表,檢查每種類型並插入特定列表。 然后,在最后連接:

...
List<Chef> chefs = new ArrayList<Chef>();
List<Manager> managers = new ArrayList<Manager>();
List<Employee> others = new ArrayList<Employee>();

for(Employee e : employees) {
    if(e instanceof Chef)
        chefs.add(e);
    else if(e instanceof Manager)
        managers.add(e);
    else
        others.add(e);
}

Collections.sort(managers);

List<Employee> result = new ArrayList<Employee>();
result.addAll(chefs);
result.addAll(managers);
result.addAll(others);

ArrayList::addAll使用System::arrayCopy因此速度非常快。 這與使用比較器大致相同,但可能更具可讀性。 這取決於偏好。

你的代碼沒有編譯,你不能在getSalary返回的原始int上調用compareTo()而是可以使用實用程序方法Long.compare()

if (this instanceof Manager || employee2 instanceof Manager) {
    return Long.compare(this.getSalary(), employee2.getSalary());
}

此外,鑒於這不是一個“自然搜索順序”,我將其表示為比較器而不是Comparable ...,即Employee類的外部,而不是嵌入其中。

Collections.sort(employees, new Comparator<Employee>() {
    @Override
    public int compare(Employee o1, Employee o2) {
        if (o1 instanceof Manager && o2 instanceof Chef) {
            return 1;
        } else if (o1 instanceof Chef && o2 instanceof Manager) {
            return -1;
        } else if (o1 instanceof Chef && o2 instanceof Chef) {
            return 0;
        } else {
            return Long.compare(o1.getSalary(), o2.getSalary());
        }
    }
});

產量

Chef 25000
Chef 28000
Chef 29000
Chef 25500
Manager 40000
Manager 50000
Manager 60000

您可以創建自定義比較器並將其傳遞給Collections.sort(..) 一旦你有比較器,你可以做Collections.sort(employees, new CustomComparator());

以下是這樣做的一種方法,但我並不強烈建議這種做法,因為它可能會在運行時引起復雜化,甚至在檢查/反對子類時會出錯。

public class CustomComparator implements Comparator<Employee> {
    @Override
    public int compare(Employee o1, Employee o2) {
        if(o1 instanceof Chef && o2 instanceof Manager)
            return -1;

        if(o1 instanceof Manager && o2 instanceof Chef)
            return +1;

        if(o1 instanceof Manager && o2 instanceof Manager) 
            return Double.compare(o1.getSalary(), o2.getSalary());

        return 0;
    }  
}

在我寫這篇文章時,我認為更好的方法是使用多個列表來存儲每個Employee類型。 這將解決在運行時使用檢查的問題。

或者,也許您可​​以在界面中實現一些字段,為每個實現類型提供不同的分數,這些分類又可用於比較Employee對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM