`
stanxl
  • 浏览: 4389 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

自定义类的对象作为TreeSet元素的两种方法排序浅谈

 
阅读更多

我们知道TreeSet是Set接口下的一个实现类,TreeSet中的元素的排列顺序是和添加的顺序是没有关系的,并且它里面元素也是不能重复的
但是,TreeSet集合有它独有的特点,比如:

import java.util.*;
public class Test{
    public static void main(String[] args){
        TreeSet ts = new TreeSet();
        ts.add("x");
        ts.add("a");
        ts.add("c");
        ts.add("j");
        System.out.println(ts);
    }
}

看输出结果:

这里写图片描述

集合里元素的排序,虽然和你添加的顺序无关,但它会根据元素的unicode自然排序

但是,当你给集合中添加不同类型的数据时:

import java.util.*;
public class Test{
    public static void main(String[] args){
        TreeSet ts = new TreeSet();
        ts.add("x");
        ts.add("a");
        ts.add("c");
        ts.add(1);
        System.out.println(ts);
    }
}

出现的结果是:

这里写图片描述

就会报ClassCastException 类型转换异常
String 不能转成Integer类型,要排序,类型必须一致
说了这么多,TreeSet的排序好像就这么多了??
当然不是了,再往下看:
如果现在给集合里添加自定义类的对象怎么办?它又是怎么排序的呢?

import java.util.*;

class Person{
    private String name ;
    private int age;
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "Person[name="+name+",age="+age+"]";
    }
}
public class Test{
    public static void main(String[] args){
        TreeSet ts = new TreeSet();
        ts.add(new Person("ab",20));
        ts.add(new Person("ac",10));
        ts.add(new Person("aa",20));
        ts.add(new Person("ad",50));
        System.out.println(ts);
    }
}

再看运行结果:

这里写图片描述

可以看出,给出的异常信息是:Person类不能比较,为什么呢?
它给的异常信息指示是应该去实现Comparable接口,一般系统内置的类都已经实现了Comparable接口,像上面的String类,Integer类

不卖关子了,说一下,自定义类的对象作为TreeSet元素的两种方法排序
第一种:让自定义的类实现Comparable接口,并实现里面的compareTo()抽象方法,此时自定义的类的对象就有了可比性
第二种:当自定义的类没有实现Comparable接口时,这时自定义的类的对象也就不具备可比性了,这时需要让集合自身具备可比性,在集合初始化时,可以指明集合的比较方式,即在new TreeSet()时,在里面写一个匿名内部类,该匿名内部类实现Comparator接口,再重写它的compare()方法,具体看代码

先看第一种:
看下面的代码,排序规则是自定义的,先按照年龄排序,在年龄相同的情况下,再按名字排序

import java.util.*;
class Person implements Comparable{
    private String name ;
    private int age;
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "Person[name="+name+",age="+age+"]";
    }
    // compareTo()方法是一个回调方法!
    // 返回值有3种情况:
    // 1. 返回大于0的数字,表示传入的参数比当前对象大
    // 2. 返回小于0的数字,表示传入的参数比当前对象小
    // 3. 返回0,表示当前对象等于传入的参数
    public int compareTo(Object obj){
        if(!(obj instanceof Person)){
            //这里先判断Obj是不是Person的实例,如果不是直接抛异常
            //不用再进行下面的比较
            throw new ClassCastException("这不是人");
        }
        Person p = (Person)obj;
        int n = this.age - p.age;
        //先按年龄比,年龄相同时,再按名字比
        if(n == 0){
            return this.name.compareTo(p.name);
        }
        return n;
    }
}
public class Test{
    public static void main(String[] args){
        Set set = new TreeSet();
        set.add(new Person("ab",20));
        set.add(new Person("ac",10));
        set.add(new Person("aa",20));
        set.add(new Person("ad",50));
        System.out.println(set);
    }
}

看输出结果:

这里写图片描述

看中间两项,当年龄相同,都是20,此时,两者再按照名字排序

第二种:
此时,不实现Comparable接口,在new TreeSet()时,在里面写一个匿名内部类,该匿名内部类实现Comparator接口,再重写它的compare()方法

import java.util.*;
class Person{
    private String name ;
    private int age;
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "Person[name="+name+",age="+age+"]";
    }
    public int getAge(){
        return age;
    }
    public String getName(){
        return name;
    }
}
public class Test{
    public static void main(String[] args){
        Set set = new TreeSet(new Comparator(){
            //这里的compare()传两个参数
            //第一种方法里的compareTo()传一个参数
            public int compare(Object obj1,Object obj2){
                if(!((obj1 instanceof Person)&&(obj1 instanceof Person))){
                    throw new ClassCastException("这不是人");
                }
                Person p1 = (Person)obj1;
                Person p2 = (Person)obj2;
                System.out.println(p1 + "vs" + p2);
                return p1.getAge()-p2.getAge();
            }
        });
        set.add(new Person("ab",20));
        set.add(new Person("ac",10));
        set.add(new Person("aa",20));
        System.out.println(set);
    }
}

看输出结果:

这里写图片描述
最后一行是最终结果,前面三行是比较过程
这里只按照年龄排序,没有再按名字排序,所以最后输出的set只有两项,第三项和第一项重复,直接被过滤掉

注意一点,当两种方法都存在时,到底以哪种方法为主呢?
答案是,以第二种方法,以比较器comparator()为主
我们可以验证一下:看下面,把两个方法都放进去

import java.util.*;
class Person implements Comparable{
    //这里实现了Comparable接口
    private String name ;
    private int age;
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "Person[name="+name+",age="+age+"]";
    }
    public int getAge(){
        return age;
    }
    public String getName(){
        return name;
    }

    public int compareTo(Object obj){
        if(!(obj instanceof Person)){

            throw new ClassCastException("这不是人");
        }
        Person p = (Person)obj;
        int n = this.age - p.age;

        if(n == 0){
            return this.name.compareTo(p.name);
        }
        return n;
    }
}
public class Test{
    public static void main(String[] args){
        Set set = new TreeSet(new Comparator(){
            //这里也实现了Comparator接口
            //那么以哪种为主呢?
            //看最下面的结果
            public int compare(Object obj1,Object obj2){
                if(!((obj1 instanceof Person)&&(obj1 instanceof Person))){
                    throw new ClassCastException("这不是人");
                }
                Person p1 = (Person)obj1;
                Person p2 = (Person)obj2;
                return p1.getAge()-p2.getAge();
            }
        });
        set.add(new Person("ab",20));
        set.add(new Person("ac",10));
        set.add(new Person("aa",20));

        System.out.println(set);
    }
}

如果输出的集合中有三项,则说明以第一种为主;
如果输出的集合中有两项,则说明以第二种为主

最终结果为:

这里写图片描述

输出的只有两项,说明了:当两种排序方式都存在时,以比较器为主

其实第一种方式是有安全隐患的,后续再来完善…..

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>

版权声明:本文为博主原创文章,未经博主允许不得转载。

分享到:
评论

相关推荐

    Java SE程序 TreeSet类中自定义CompareTo类

    Java SE程序 TreeSet类中自定义CompareTo类Java SE程序 TreeSet类中自定义CompareTo类Java SE程序 TreeSet类中自定义CompareTo类Java SE程序 TreeSet类中自定义CompareTo类Java SE程序 TreeSet类中自定义CompareTo类...

    在TreeSet中添加自定义对象

    通过以上两种方法,我们可以在`TreeSet`中添加自定义对象,并按照特定规则进行排序。选择哪种方法取决于实际需求:如果排序规则简单且固定,那么实现`Comparable`接口即可;若排序规则复杂或需要动态变化,则应考虑...

    浅谈TreeSet中的两种排序方式

    Java 中 TreeSet 的两种排序方式 TreeSet 是 Java 中一种基于树形结构的 Set 实现,它具有自动排序的功能。在使用 TreeSet 时,我们可以通过实现 Comparable 接口或提供Comparator 对象来指定排序规则。下面,我们...

    学生成绩排序(TreeSet方式实现)

    总的来说,使用`TreeSet`实现学生成绩排序是一种简洁高效的方法,它利用了内置的数据结构和排序机制,减少了代码量,同时保证了排序的稳定性。这种方式尤其适用于需要动态维护排序的数据集,因为`TreeSet`在添加或...

    解决TreeSet类的排序问题

    TreeSet提供两种排序方式:自然排序和定制排序。 1. 自然排序: 自然排序是TreeSet默认的排序方式。当向TreeSet中添加元素时,它会调用这些元素的`compareTo(Object obj)`方法进行比较。这个方法源自`Comparable`...

    java排序代码

    TreeSet支持两种排序方式: 自然排序:TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系,然后将集合元素按升序排列。 定制排序:在创建TreeSet集合对象时,并提供一个Comparator接口...

    java泛型 用了treeset

    使用TreeSet和Comparator,编写TreeSetTest2类,要求对TreeSet中的元素1-元素10进行排列,排序逻辑为奇数在前偶数在后,奇数按照升序排列,偶数按照降序排列。 如果需要的话可以下载,有写成文章的。有写了一点中文...

    尚硅谷-实验:TreeSet的自然排序与定制排序.pdf

    ·拒绝晦涩难懂的呆板教学,宋老师语言生动幽默,举例形象生动深入浅出,迅速让你把握问题本质,四两拨千斤 2.课程内容推陈出新: ·基于JDK 11,将Java8、Java9、Java10、Java11新特性一网打尽 ·课程中,Eclipse...

    HashSet和TreeSet_围墙之外

    HashSet和TreeSet是Java集合框架中的两种重要数据结构,它们都是Set接口的实现类,用于存储不重复的元素。在编程实践中,理解它们的区别和应用场景至关重要。 HashSet是基于HashMap实现的,它不保证元素的顺序,...

    排序之HashSet和TreeSet的区别

    在Java编程语言中,集合框架是处理数据的重要组成部分,其中`HashSet`和`TreeSet`是两种常用的Set接口实现类。它们各自具有独特的特性和用途,理解它们的区别对于编写高效且正确的代码至关重要。 首先,`HashSet`是...

    TreeSet 红黑树结构算法

    例如,TreeSet 的 addAll 方法就是调用 TreeMap 的 putAll 方法来添加元素。TreeSet 的其他方法,如 contains、remove、size 等,也都是调用 TreeMap 的对应方法来实现。 红黑树数据结构是 TreeSet 的核心,它是一...

    浅谈java中的TreeMap 排序与TreeSet 排序

    在Java编程语言中,`TreeMap` 和 `TreeSet` 是两种基于红黑树数据结构实现的集合类,它们都提供了自动排序的功能。本文将详细探讨 `TreeMap` 和 `TreeSet` 的排序机制以及如何自定义排序规则。 首先,`TreeMap` 是...

    JCF(List、Set、Map)学习,实现了<key,value>按value排序噢

    对于`TreeSet`,由于其只能存储单个对象,若要按值排序,我们需要创建一个包含键值对的自定义类,然后重写`compareTo()`方法,使其根据值进行比较。例如: ```java class ValueWrapper implements Comparable...

    492.490.JAVA基础教程_常用类-自定义类实现Comparable自然排序(492).rar

    在Java编程语言中,`Comparable`接口是一个非常重要的概念,特别是在处理对象排序的时候。这个教程很可能是关于如何在自定义类中实现`Comparable`接口,以便进行自然排序。`Comparable`接口位于`java.lang`包中,它...

    HashSet,TreeSet和LinkedHashSet的区别1

    如果元素不支持自然排序,或者需要自定义排序规则,可以传递一个Comparator对象给TreeSet构造函数,实现定制排序。在Comparator的compare()方法中,返回0表示两个对象相等,正数表示第一个对象大于第二个,负数则...

    Java 对象排序详解.rar_java 对象排序_对象_排序

    在Java编程语言中,对象排序是一项关键操作,特别是在处理集合数据结构时。本文将深入探讨如何对ArrayList、HashSet、TreeSet以及数组中的对象进行排序。理解这些排序机制对于编写高效且可维护的代码至关重要。 ...

    java集合-TreeSet的使用

    TreeSet 是 Java 中的一个集合类,它实现了 SortedSet 接口,并且使用红黑树作为底层数据结构。TreeSet 具有以下主要特点: 排序性:TreeSet 中的元素是有序的,默认按照元素的自然顺序进行排序。或者,可以在创建 ...

    java 集合框架(TreeSet练习)

    2. **自定义比较器**:如果我们需要自定义元素的排序规则,可以通过传递一个实现了`Comparator`接口的对象给`TreeSet`的构造函数来实现。`compare()`方法在这个比较器中定义了元素的比较逻辑。 3. **基本操作**:`...

    最快的排序算法 java最快的排序-在Java中对列表进行排序的最快方法,排序算法数据结构

    在上述代码中,使用了 ServerInfoComparator 类来实现自定义的比较器,该类实现了 Comparator 接口,并提供了 compare() 方法,该方法用于比较两个 ServerInfo 对象的大小。通过使用 ServerInfoComparator 类,可以...

    Java集合框架总结:TreeSet类的排序问题

    发布于2012-5-8TreeSet支持两种排序方法:自然排序和定制排序。TreeSet默认采用自然排序。TreeSet会调用集合元素的compareTo(Objectobj)方法来比较元素之间大小关系,然后将集合元素按升序排列,这种方式就是自然...

Global site tag (gtag.js) - Google Analytics