我有一个抽象类:
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对象之后放在列表的末尾。
e.g
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对象感到困惑。
答案 0 :(得分:4)
您的情况听起来像创建Comparator
比实施Comparable
更合适:后者专门用于建模类的实例自然顺序。
例如,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"
}
}
答案 1 :(得分:1)
您可以使用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
因此速度相当快。这与使用比较器大致相同,但可能更具可读性。这真的取决于偏好。
答案 2 :(得分:1)
你的代码没有编译,你不能在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
答案 3 :(得分:1)
您可以创建自定义比较器并将其传递给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
个对象。