美文网首页
JavaTips01——Java自定义比较的实现

JavaTips01——Java自定义比较的实现

作者: SimonYi1230 | 来源:发表于2020-04-21 22:42 被阅读0次

参考文章

场景

  • 如果给你一个一维整型数组int[] array,使用Java进行升序排序怎么做?
// 直接使用sort进行排序
Arrays.sort(array)
  • 降序呢?
// 自定义Comparator
Arrays.sort(array,new Comparator<Integer>() {
            @Override
            public int compare(int o1, int o2) {
                return o2-o1;
            }
        });
  • 还有别的方法么?答:实现Comparable接口,对于基本数据类型不太适用(麻烦)
// 可以在自定义类上实现Comparable接口,重写compareTo方法,
// 并且有必要重写了object的equals、tostring、hashcode方法,这是一个好习惯
public class Employee implements Comparable<Employee>
  • 给你一个二维数组int[n][2],先按照每行的第1个元素进行降序排序,如果相同则按照第0个元素降序排列,怎么实现?
  • 。。。

今天笔试遇到的一道多维数组自定义排序问题,题目本身不难,核心就在于上述第四个问题的实现,编写代码的困难也让我意识到自己对于Java自定义比较的实现理解不够深,所以决定仔细梳理一下。

java核心技术I 13.2.5 对象的比较

书中以举例子的形式说明了TreeSet的自定义类对象元素如何进行自定义排序的方法,总结如下:

Comparable

  • 定义:Comparable是一个排序方法接口,通过重写实现接口的compareTo方法,实现自定义类的自定义规则比较

    • 也就是说,你可以对两个对象的若干个属性进行比较,用比较的结果作为这两个对象的比较结果
    • 重写完成之后,sort会自己去找到这个重写的方法,按照你规定的方式进行排序
  • 适用场景:自定义类对象的集合排序

  • 优点:

    • 将自定义类的比较拆解成为其内部属性对应类型的逐级比较,代码编写上更为清晰直观(你想倒序的话乘以result *= -1返回即可)
  • 举例子

    • TreeSet <Employee>
public class Employee implements Comparable{
    @Override
    public int compareTo(Employee other) 
    {
        // 这里并不是递归,而是通过自定义类Employee 的属性name调用该属性类的compareTo
        // Employee compareTo ——> String compareTo

        // String compareTo 相等——> Integer compare
        // 从这里也能看出来String作为重要的非基本类型数据,java专门为其重写了compareTo方法,已知String的底层实现是固定长度的char数组,我们可推知String的比较终归要落到对char数组的逐位比较(字典序的实现)
        // String compareTo——> 
        // StringLatin1.compareTo——> 
        // compareTo(byte[] value, byte[] other, int len1, int len2)——> 
        // return getChar(value, k) - getChar(other, k)
        int result = this.name.compareTo(other.getName());
        if (result == 0) 
        {
            result = Integer.compare(this.getAge(), other.getAge());
        }

        return result;
    }

    private String name;
    private int age;
    private MyDate birthday;

    // 忽略访问器的代码
    ··· ···
    
    
    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Employee employee = (Employee) o;

        if (age != employee.age) return false;
        if (name != null ? !name.equals(employee.name) : employee.name != null) return false;
        return birthday != null ? birthday.equals(employee.birthday) : employee.birthday == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        result = 31 * result + (birthday != null ? birthday.hashCode() : 0);
        return result;
    }
}
  • Tips:自定义类除了重写compareTo,还有必要重写toString、equals、hashCode,用以实现自定义类对象的判等(Hash类结构的存储与查询需要用到)、输出

Comparator方法接口——定制比较器

  • 定义:它不是类内部实现,而是专门另外找一个实现Comparator接口的类,在这个类里面重写compare方法,将这个类的对象传递。ArrayList.sort方法就需要这样的一个定制比较器.

  • 适用场景:多维基本类型数组的复杂排序(不适合在基本类型数据类的内部重写compareTo方法)

  • 优点:符合开闭原则——无需实现接口,避免在类内部修改

  • 举例子

    • 多维基本类型数组的复杂排序——上文提到的第四个问题
// 我们向sort函数传入一个Comparator方法接口类型的对象,这是一个方法接口,
// 里面有一个可重写的compare方法(这里涉及到泛型擦除,后续深入探究一下)
Arrays.sort(test, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                // 如果第一个元素相等,我们就返回每个子数组第0个元素的降序排列
                // 记住 return o1-o2; 是升序  return o2-o1; 是降序,就算是复杂元素的比较也会被拆解为若干个基本类型的比较
                if (o1[1]==o2[1])return o2[0]-o1[0];
                // 否则返回每个子数组第1个元素的降序排列
                return o2[1]-o1[1];
            }
        });

总结:

  • 都是接口,Comparable需要被某个类实现并在内部重写方法,Comparator可通过传参的方式在外部实现排序功能。

  • Comparable功能强大,可以为自定义类的自然排序乃至定制排序提供需要的排序功能,在涉及自定义类的多个属性的复杂规则的排序情况中,是更好的选择。

  • Comparator更为灵活,自已在不修改自定义类的定义的情况下进行类外的排序,符合开闭原则

  • 总而言之,还是需要根据场景,仔细考量两者带来的收益与风险,选择更为合适的方法完成排序功能

相关文章

  • JavaTips01——Java自定义比较的实现

    参考文章 java基础__comaprable和comparator的区别 TreeSet之定制排序和自然排序 场...

  • 面试题:请自己实现一个Arraylist

    MyIterator.java 自定义迭代器 MyArraylist.java 自己实现的Arraylist ...

  • 注解原理

    Java内置的注解以及自定义一个注解大家都比较熟悉的了,现在来看看注解实现的原理,看看Java的体系下面是如何对注...

  • 注解原理

    Java内置的注解以及自定义一个注解大家都比较熟悉的了,现在来看看注解实现的原理,看看Java的体系下面是如何对注...

  • 注解原理

    Java内置的注解以及自定义一个注解大家都比较熟悉的了,现在来看看注解实现的原理,看看Java的体系下面是如何对注...

  • 你一直使用注解,但是你知道它的实现原理吗?

    Java内置的注解以及自定义一个注解大家都比较熟悉的了,现在来看看注解实现的原理,看看Java的体系下面是如何对注...

  • Android-自定义全局拽托返回

    效果 自定义属性 代码实现 使用 布局xml Java代码

  • jvm类加载机制

    扩展阅读: Java 自定义 ClassLoader 实现隔离运行不同版本jar包的方式Java ClassLoa...

  • JMeter自定义Java Sample

    自定义Java Sample需要实现AbstractJavaSamplerClient抽象类。AbstractJa...

  • java 实现自定义线程池

    java 实现自定义线程池 定义线程池接口 线程池接口的默认实现 示例摘抄于《Java并发变成的艺术》4.4.3线...

网友评论

      本文标题:JavaTips01——Java自定义比较的实现

      本文链接:https://www.haomeiwen.com/subject/avcmihtx.html