Java Comparable与Comparator的区别

117 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

在java中实现比较功能是很容易的。当遇到自定义类型,或比较对象不能直接进行比较,我们需要使用比较策略,通过Comparator 或 Comparable 接口即可简单实现。

可以说一个是自已完成比较,一个是外部程序实现比较的差别而已。用 Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。

相同点

1.两者都是接口。

2.两者的功能都是排序。

不同点

1.Comparable在java.lang包下,Comparator在java.util包下

2.实现Comparable接口要重写compareTo方法

Comparable

对于自定义类的对象我们想要进行排序,则可以让自定义类实现Comparable接口,重写compareTo(obj)方法,指明如何排序。

    class Movie implements Comparable<Movie> {
        private double rating;
        private String name;
        private int year;

        // Used to sort movies by year
        public int compareTo(Movie m) {
            return this.year - m.year;
        }

        // Constructor
        public Movie(String nm, double rt, int yr) {
            this.name = nm;
            this.rating = rt;
            this.year = yr;
        }

        // Getter methods for accessing private data
        public double getRating() {
            return rating;
        }

        public String getName() {
            return name;
        }

        public int getYear() {
            return year;
        }
    }

    class Main {
        public static void main(String[] args) {
            ArrayList<Movie> list = new ArrayList<Movie>();
            list.add(new Movie("Force Awakens", 8.3, 2015));
            list.add(new Movie("Star Wars", 8.7, 1977));
            list.add(new Movie("Empire Strikes Back", 8.8, 1980));
            list.add(new Movie("Return of the Jedi", 8.4, 1983));

            Collections.sort(list);

            System.out.println("Movies after sorting : ");
            for (Movie movie : list) {
                System.out.println(movie.getName() + " " +
                        movie.getRating() + " " +
                        movie.getYear());
            }
        }
    }

Comparator

对已经实现了Comparable接口的类想改变排序方式,只是临时用一下不想改类代码(如默认是升序,想改成降序),可以临时用Comparator实现。

   class Movie implements Comparable<Movie> {
        private double rating;
        private String name;
        private int year;

        // Used to sort movies by year
        public int compareTo(Movie m) {
            return this.year - m.year;
        }

        // Constructor
        public Movie(String nm, double rt, int yr) {
            this.name = nm;
            this.rating = rt;
            this.year = yr;
        }

        // Getter methods for accessing private data
        public double getRating() {
            return rating;
        }

        public String getName() {
            return name;
        }

        public int getYear() {
            return year;
        }
    }

    // Class to compare Movies by ratings
    class RatingCompare implements Comparator<Movie> {
        public int compare(Movie m1, Movie m2) {
            if (m1.getRating() < m2.getRating()) return -1;
            if (m1.getRating() > m2.getRating()) return 1;
            else return 0;
        }
    }

    // Class to compare Movies by name
    class NameCompare implements Comparator<Movie> {
        public int compare(Movie m1, Movie m2) {
            return m1.getName().compareTo(m2.getName());
        }
    }

    // Driver class
    class Main {
        public static void main(String[] args) {
            ArrayList<Movie> list = new ArrayList<Movie>();
            list.add(new Movie("Force Awakens", 8.3, 2015));
            list.add(new Movie("Star Wars", 8.7, 1977));
            list.add(new Movie("Empire Strikes Back", 8.8, 1980));
            list.add(new Movie("Return of the Jedi", 8.4, 1983));

            // Sort by rating : (1) Create an object of ratingCompare
            //                  (2) Call Collections.sort
            //                  (3) Print Sorted list
            System.out.println("Sorted by rating");
            RatingCompare ratingCompare = new RatingCompare();
            Collections.sort(list, ratingCompare);
            for (Movie movie : list)
                System.out.println(movie.getRating() + " " +
                        movie.getName() + " " +
                        movie.getYear());


            // Call overloaded sort method with RatingCompare
            // (Same three steps as above)
            System.out.println("\nSorted by name");
            NameCompare nameCompare = new NameCompare();
            Collections.sort(list, nameCompare);
            for (Movie movie : list)
                System.out.println(movie.getName() + " " +
                        movie.getRating() + " " +
                        movie.getYear());

            // Uses Comparable to sort by year
            System.out.println("\nSorted by year");
            Collections.sort(list);
            for (Movie movie : list)
                System.out.println(movie.getYear() + " " +
                        movie.getRating() + " " +
                        movie.getName() + " ");
        }
    }

总结

用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。

用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象。