在一次采访中我遇到了这个问题。
编写一个接受bean类字段的类,并根据传递的字段对包含bean对象的列表进行排序。
1)用于分类的技术应该是什么? 我回答了比较者。
2)我不希望为每个字段创建许多Comparator类。你能写一个适用于所有领域的通用比较器吗? 以下是我的代码。
请告诉我这是否是正确的做法,或者有更好的方法来做到这一点。如果我错了,我请你纠正我。
public class GenericComparatorDemo {
static List<Employee> al = new ArrayList<Employee>();
static{
al.add(new Employee(45, "Vijay", "Bangalore", "Banking", 88, 99999));
al.add(new Employee(13, "Manoz", "Chennai", "Insurance", 48, 28000));
al.add(new Employee(79, "Ajay", "Hyderabad", "Real Estate", 54, 24000));
al.add(new Employee(21, "Sindu", "Noida", "Analyst", 89, 99998));
al.add(new Employee(67, "Honey", "Mumbai", "Social", 88, 111111));
al.add(new Employee(12, "Lucky", "Mysore", "Social", 86, 99997));
}
/**
* @param args
*/
public static void main(String[] args) {
Scanner scn = new Scanner(System.in);
System.out.println("Please enter the field on which you want to sort employee's...");
final String input = scn.nextLine();
if(null != input && !"".equals(input)){
Collections.sort(al, new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
if("id".equals(input)){
return (o1.getId() < o2.getId()) ? -1 : ((o1.getId() == o2.getId()) ? 0 : 1);
}else if("name".equals(input)){
return o1.getName().compareTo(o2.getName());
}else if("location".equals(input)){
return o1.getLocation().compareTo(o2.getLocation());
}else if("department".equals(input)){
return o1.getDepartment().compareTo(o2.getDepartment());
}else if("rewardPoints".equals(input)){
return (o1.getRewardPoints() < o2.getRewardPoints()) ? -1 : ((o1.getRewardPoints() == o2.getRewardPoints()) ? 0 : 1);
}else if("salary".equals(input)){
return (o1.getSalary() < o2.getSalary()) ? -1 : ((o1.getSalary() == o2.getSalary()) ? 0 : 1);
}else{
return 0;// when proper field is not entered sorting will not happen
}
}
});
}else{
System.out.println("Please enter valid employee field to sort employee's...");
}
for(Employee alObj:al){
System.out.println("\n" + alObj.toString());
}
}
}
///员工类///
公共类员工{
private long id;
private String name;
private String location;
private String department;
private int rewardPoints;
private double salary;
public Employee(long id, String name, String location, String department,
int rewardPoints, double salary) {
this.id = id;
this.name = name;
this.location = location;
this.department = department;
this.rewardPoints = rewardPoints;
this.salary = salary;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public int getRewardPoints() {
return rewardPoints;
}
public void setRewardPoints(int rewardPoints) {
this.rewardPoints = rewardPoints;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", location="
+ location + ", department=" + department + ", rewardPoints="
+ rewardPoints + ", salary=" + salary + "]";
}
}
////根据tieTYT和radai的评论。我做了以下更改。如果有任何问题,请纠正我////
public class GenericComparatorReflectionDemo {
static List<Employee> al = new ArrayList<Employee>();
static{
al.add(new Employee(45, "Vijay", "Bangalore", "Banking", 88, 99999));
al.add(new Employee(13, "Manoz", "Chennai", "Insurance", 48, 28000));
al.add(new Employee(79, "Ajay", "Hyderabad", "Real Estate", 54, 24000));
al.add(new Employee(21, "Sindu", "Noida", "Analyst", 89, 99998));
al.add(new Employee(67, "Honey", "Mumbai", "Social", 88, 111111));
al.add(new Employee(12, "Lucky", "Mysore", "Social", 86, 99997));
}
/**
* @param args
*/
public static void main(String[] args) {
Scanner scn = new Scanner(System.in);
System.out.println("Please enter the field on which you want to sort employee's...");
final String input = scn.nextLine();
if(null != input && !"".equals(input)){
Collections.sort(al, new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
try {
Field employeeField = Employee.class.getDeclaredField(input);
employeeField.setAccessible(true);
Comparable employeeFieldValue1 = (Comparable)employeeField.get(o1);
Comparable employeeFieldValue2 = (Comparable)employeeField.get(o2);
return employeeFieldValue1.compareTo(employeeFieldValue2);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
// when proper field is not entered sorting or any exception occurs
return 0;
}
}
});
}else{
System.out.println("Please enter valid employee field to sort employee's...");
}
for(Employee alObj:al){
System.out.println("\n" + alObj.toString());
}
}
}
答案 0 :(得分:1)
是的,您可以使用反射编写通用比较器。获得字段名称后,可以使用反射检索字段值。执行此操作后,您可以使用java中的所有基本值保持类(如Boolean,Integer,String,uuid,date等)的可比性,将使用反射获得的值转换为Comparable,并比较它们
答案 1 :(得分:1)
这可能是主观的,因为我无法阅读采访者的想法。但如果我是你,我会用反射找到这个领域。如果字段为Comparable
,则使用该接口。否则,您将不得不询问面试官您希望它如何在某些类型的领域工作。
您的代码存在的问题是它非常特定于当前类。如果添加了新字段,除非您编写和编译新代码,否则它将无法对其进行排序。它也只适用于此类。使用反射,几乎可以在任何类中使用它。
答案 2 :(得分:0)
为了做到这一点,你应该将getting
要比较的值的概念抽象为接口(或Java 8中的函数),如下所示:
此函数将为您创建一个Comparator
,使用getter
Function
来读取bean中的值:
public static <T> Comparator<T> createComparator(Function<T, R extends Comparable> getter)
{
return (obj1, obj2) -> getter.apply(obj1).compareTo(getter.apply(obj2);
}
可以这样使用:
Collections.sort(employees, createComparator((employee) -> employee.getName()));
如果您已开始使用String
名称来阅读该字段,请使用getter
函数的反射实现,如下所示:
private Function<Employee, Comparable> reflectiveGetter(String fieldName) throws NoSuchFieldException
{
Field field = Employee.class.getDeclaredField(fieldName);
field.setAccessible(true);
return (employee) ->
{
try
{
return (Comparable)field.get(employee);
}
catch (IllegalAccessException e)
{
throw new RuntimeException(e);
}
}
}
可以这样使用:
Collections.sort(employees, reflectiveGetter("name"));
完全相同的事情可以在使用接口的任何Java版本中实现,只是它有点冗长。