Java集合中Set

Set

Set是继承了Collection接口的抽象接口,不包含重复元素的集合。简单地说,集合不包含一对元素e1和e2,例如e1.equals(e2),最多包含一个空元素。



一、Set


/*
* Set元素特点:无序(添加顺序)不可重复
*   TreeSet: 底层红黑树
*   HashSet: 底层散列表
* */
public class _01_Collection_Set {

    public static void main(String[] args) {
        TreeSet<Object> treeSet = new TreeSet<>();
        treeSet.add(1);
        treeSet.add(2);
        System.out.println(treeSet.size());
        for (Object o : treeSet) {
            System.out.println(o);
        }
    }
}

二、TreeSet


/*
* TreeSet:元素不可重复,添加的元素会按照某种规则自动排序
*   想要使用TreeSet,元素必须要排序
*       数字:默认从小到大
*       字符串:默认比较每位ASCII码
*       日期:默认比较自然日期 昨天、今天、明天
* */
public class _02_Collection_TreeSet {

    public static void main(String[] args) {
        TreeSet<Object> treeSet = new TreeSet<>();
        treeSet.add(1);
        treeSet.add(5);
        treeSet.add(2);
        treeSet.add(9);
        // 上面添加的是数字,下面如果是字符串就会报错,因为添加的时候需要比较元素大小
        // 而 不同类型 元素,没有可比性
        // treeSet.add("aaa");
        for (Object o : treeSet) {
            System.out.println(o);
        }
        System.out.println("-------");
        TreeSet<Object> treeSet2 = new TreeSet<>();
        treeSet2.add("a");
        treeSet2.add("1");
        // 如果有多个字符,先比较第一位,如果第一位不同,则第一位小的在上面
        // 如果第一位相同,在比较第二位,依次类推
        treeSet2.add("11"); // 第一位为1,其ASCII码值为47,a的ASCII值97
        treeSet2.add("101");
        treeSet2.add("b");
        treeSet2.add("c");
        for (Object o : treeSet2) {
            System.out.print(o + " "); // 输出:1 101 11 a b c
        }
    }
}

三、比较器Comparable和Comparator


/*
* Comparable
*   比较器有两种:1 元素自身比较器 2 比较器类
*   为什么字符串、Integer、Date可以排序?
*       因为都实现了 implement Comparable
*   使用TreeSet在进行数据添加的时候,会自动调用该对象的comparableTo()方法
*       和集合中元素进行比较
*       如果想要存储自定义类型?需要实现该接口
* */
public class _03_Collection_TreeSet {

    public static void main(String[] args) {
        TreeSet<Object> treeSet = new TreeSet<>();
        User user = new User(10);
        // 类型转换异常java.lang.ClassCastException:
        // com.tianl.Collection.Set.User cannot be cast to java.lang.Comparable
        // User必须实现Comparable接口才能存入TreeSet,添加的时候,会自动调用该对象的comparableTo()方法
        // 没有实现comparableTo()方法,则不能添加入TreeSet
        // treeSet.add(user);
        treeSet.add(new User(12));
        treeSet.add(new User(13));
        treeSet.add(new User(15));
        // treeSet.add(1); // 重复存入无效
        System.out.println(treeSet.size());
        for (Object o : treeSet) {
            System.out.println(o);
        }
    }
}

class User implements Comparable{
    private int age;

    public User(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public int compareTo(Object obj) {
        // this表示当前对象
        // obj 表示集合内对象
        // 返回值为0 表示 相等 ,则不添加
        // 返回大于0 表示 要添加的元素大,则放在后面
        // 返回小于0 表示 要添加的元素小,则放在前面
        User other = (User) obj;
        return this.age - other.age; // 升序,
        // return other.age - this.age; // 升序,
    }

    @Override
    public String toString() {
        return "User: [age=" + age + "]";
    }
}

/*
 // TreeSet中add方法源码,底层红黑树
 public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
 public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key); // 自动调用该对象的comparableTo()方法
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }
* */

/*
* TreeSet添加元素必须排序
*   实现排序的两种方法
*       1 要添加的元素对应的类实现java.lang.Comparable接口,并实现comparableTo()方法
*       2 使用java.util.Comparator比较器类
*   Comparable:添加元素实现该接口并覆写comparableTo()方法
*   Comparator:第三方比较器类,应用于:Integer默认升序,如何实现降序?使用Comparator进行降序排序
*
* 如果添加元素的类 是 自定义类, 应该使用Comparable,可对扩展开放,其他人还可以使用Comparator实现新的排序
* 如果添加元素的类 不是 自定义类,
*    1 该类有排序(实现了Comparable),如Integer,但默认排序不满足需求
*       则可以使用Comparator调整排序,其优先级高
*    2 该类没有实现排序(没有实现Comparable),则需要使用Comparator进行排序,因为不可能修改源码实现
* */
public class _04_Collection_TreeSet {

    public static void main(String[] args) {
        // TreeSet<Object> treeSet = new TreeSet<>(); // 默认升序
        // 实现Comparator接口compare()方法传入
        //TreeSet<Object> treeSet = new TreeSet<>(new SortTest());
        // 匿名内部类写法传入
        TreeSet<Object> treeSet = new TreeSet<>(new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                Integer i1 = (Integer) o1;
                Integer i2 = (Integer) o2;
                return i2 - i1;
            }
        }); // 实现降序
        treeSet.add(2);
        treeSet.add(4);
        treeSet.add(8);
        treeSet.add(16);
        for (Object o : treeSet) {
            System.out.println(o);
        }
    }
}

// 比较器类
class SortTest implements Comparator{
    @Override
    public int compare(Object o1, Object o2) {
        Integer i1 = (Integer) o1;
        Integer i2 = (Integer) o2;
        return i2 - i1;
    }
}

/*
* TreeSet中使用Comparator排序demo实现多属性比较
* */
public class _01_Collection_Sort {

    public static void main(String[] args) {
        // Comparator
        TreeSet<Object> treeSet = new TreeSet<>(new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                Student s1 = (Student) o1;
                Student s2 = (Student) o2;
                if (s1.getId() > s2.getId()) {
                    return 1;
                } else if (s1.getId() < s2.getId()) {
                    return -1;
                } else {
                    return s1.getAge() - s2.getAge(); // ID相同情况返回
                }
            }
        });

        treeSet.add(new Student(3,18,"AAA"));
        treeSet.add(new Student(2,13,"AAB"));
        treeSet.add(new Student(1,21,"AAC"));
        treeSet.add(new Student(5,28,"AAG"));
        treeSet.add(new Student(4,25,"AAD"));
        treeSet.add(new Student(4,22,"AAE"));
        treeSet.add(new Student(4,31,"AAF"));

        for (Object o : treeSet) {
            System.out.println(o);
        }
    }
}

// Student类中没有实现Comparable接口,则必须使用Comparator接口才能实现排序
class Student{
    private int id;
    private int age;
    private String name;

    public Student(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "id: " + id + ", age: " + age + ", name: " + name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

/*
* List排序,想要实现排序,元素必须实现Comparable方法
* */
public class _02_Collection_Sort {

    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(21);
        arrayList.add(16);
        arrayList.add(11);
        // 可以使用 Collections 包中的sort方法排序,是因为Integer中实现了Comparable接口
        Collections.sort(arrayList);
        System.out.println(arrayList);
    }
}

/*
* 默认排序不满足需求,或者没有实现Comparable排序接口
*   则使用Comparator接口实现
* */
public class _03_Collection_Sort {

    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(10);
        arrayList.add(1);
        arrayList.add( 16);
        arrayList.add(31);
        // 使用Comparator接口实现降序
        // 不改变源码条件下实现重新排序
        Collections.sort(arrayList, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                Integer i1 = (Integer) o1;
                Integer i2 = (Integer) o2;
                return i2 - i1;
            }
        });
        System.out.println(arrayList);
    }
}

/*
* ArrayList下 需求:在main方法中,不改变其他源码情况下,输出语句按照年龄排序
* */
public class _04_Collection_SortTest {

    public static void main(String[] args) {
        ArrayList<Object> arrayList = new ArrayList<>();
        arrayList.add(new Person("AAA",18));
        arrayList.add(new Person("BBB",28));
        arrayList.add(new Person("CCC",8));
        arrayList.add(new Person("DDD",8)); // 可重复

        // Comparator接口实现按照年龄排序
        Collections.sort(arrayList,new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                Person p1 = (Person) o1;
                Person p2 = (Person) o2;
                // return Integer.compare(p1.getAge(), p2.getAge())
                // 下面是上面语句的详细形式
                if (p1.getAge() > p2.getAge()){
                    return 1; // 返回正数放在后边
                } else if (p1.getAge() < p2.getAge()){
                    return -1; // 返回正数放在前边
                } else {
                    return 0; // 相等
                }
            }
        });

        for (Object o : arrayList) {
            System.out.println(o);
        }
        System.out.println("-----------");

        for (Object o : arrayList) {
            Person person = (Person) o;
            System.out.println("name: "+person.getName()+", age: "+person.getAge());
        }
    }
}

class Person{
    private int age;
    private String name;

    @Override
    public String toString() {
        return "name: " + name + ", age: " + age;
    }

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public Person(String name, int age) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

四、HashSet


/*
* hash算法:一种安全的加密算法,把不定长值变为定长值,不能保证唯一性
*
* 散列表:
*   数组中 保存链表() 单向链表,并且链表节点内有四个属性
*       1、key 2、value 3、next 4、hash
*   散列表是一种数据结构,在Java中被封装到HashSet、HashMap、HashTable中
*       HashTable过时
*   hash算法在Java中是指 hashCode 函数及重写
*   目的:为了查询快,因为hash值是一个固定的值
*
* 1 hash过程
*   获取对象,调用对象自身的hashCode()方法,进行hash算法,得到数组下标,把hash值保存到对应数组中
*   Set特性:无序(添加顺序),不可重复(先hashCode比较,若hash值相等,在equals比较)
* 2 HashSet和HashMap
*   HashSet是HashMap的封装,本质是一个HashMap
*   默认初始化容量都是 16
*   封装之后HashSet把value值屏蔽了,只能操作key。
*   所以在使用HashSet添加的时候,只需要传入key即可
* 3 HashSet添加过程
*   1 使用添加的键值对中的key,调用key的hashCode方法,生成hash值,进行hash算法得到数组下标
*       判断该下标上是否有元素,如果没有,把 键值对 保存到该数组中即可
*   2 如果该数组中有对象,则调用key的equals方法和数组中元素进行比较
*       如果相等则key不添加,value值覆盖
*   3 如果不等,则把 该对象 添加到已有元素的next属性,形成链表
*   4 如果添加时,已经是链表,则需要使用key和链表中所有元素的key进行比较是否相等
*
* 散列表中需要使用hashCode和equals来表示对象的唯一性
*   在添加自定义类型元素的时候,需要考虑按需求重写hashCode和equals方法
* */
public class _05_Collection_hashSet {

    public static void main(String[] args) {
        HashSet<Object> hashSet = new HashSet<>();
        hashSet.add(111);
        hashSet.add(222);
        hashSet.add("xxx");
        // hashSet.add("xxx"); // 相同不添加
        for (Object o : hashSet) {
            System.out.println(o);
        }

    }
}

/*
* 按需求重写hashCode和equals方法实现hashSet排序
* */ 
public class _06_Collection_hashSet {

    public static void main(String[] args) {
        HashSet<Object> hashSet = new HashSet<>();
        hashSet.add(new Employee("30","不可计数V字领"));
        hashSet.add(new Employee("45","护服务"));
        hashSet.add(new Employee("83","v哈哈ds,,"));
        hashSet.add(new Employee("18","AAA"));
        hashSet.add(new Employee("19","BBB"));
        hashSet.add(new Employee("20","CCC0"));
        hashSet.add(new Employee("20","CCC1")); // 不添加,比较的是number
        hashSet.add(new Employee("20","CCC2")); // 需求中:number相同则是同一个对象
        for (Object o : hashSet) {
            System.out.println(o);
        }
    }
}

class Employee{
    private String number;
    private String name;

    public Employee(String number, String name) {
        this.number = number;
        this.name = name;
    }

    @Override
    public int hashCode() {
        System.out.println("hashCode()方法执行");
        return number.hashCode(); // 只根据number属性判断自定义类类型
    }

    @Override
    public boolean equals(Object obj) {
        System.out.println("equals方法执行");
        if (this == obj) return true;
        if (obj == null) return false;
        if (obj instanceof Employee){
            Employee other = (Employee) obj;
            return other.getNumber().equals(this.number);
        }
        return false;
    }

    @Override
    public String toString() {
        return "number: " + number + ", name: " + name;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值