Set集合

    科技2024-01-23  104

    Set

    HashSet初探

    Set<String> strs = new HashSet<>(); strs.add("asdf"); strs.add("asdf"); strs.add("asdf"); strs.add("asdf"); strs.add("fdas"); strs.add("jmjm"); strs.add("jnjn"); for (String str : strs) { System.out.println(str); } /* jmjm asdf jnjn fdas */ 存储时的顺序和取出的顺序不同不可重复放到HashSet集合中的元素实际上是放到HashSet集合的key部分了。

    TreeSet初探

    二叉树

    TreeSet集合存储元素的特点:

    无序不可重复,但是存储的元素可以自动按照大小顺序排序!称为可排序集合

    无序代表没有下标并不是指顺序

    //创建集合 Set<String> set = new TreeSet<>(); //添加元素 set.add("A"); set.add("F"); set.add("B"); set.add("V"); set.add("C"); for (String s : set) { System.out.println(s); } /* A B C F V */ TreeSet集合底层实际上是一个TreeMapTreeMap集合底层是一个二叉树。放到TreeSet集合中的元素,等同于放到TreeMap集合key部分了TreeSet集合中的元素:无序不可重复,但是可以按照元素的大小自动排序。称为:可排序集合。

    数据库中有很多数据:

    userId name birth


    1 zs 1980-11-11

    2 ls 1980-10-11

    3 ww 1981-11-11

    4 zl 1979-11-11

    编写程序从数据库当中取出数据,在页面展示用户信息的时候按照生日升序或者降序。这个时候可以使用TreeSet集合,因为TreeSet集合放进去,拿出来就是有顺序的。

    //创建一个TreeSet集合 TreeSet<String> ts = new TreeSet<>(); //添加String ts.add("zhangsan"); ts.add("lisi"); ts.add("wangwu"); ts.add("zhangsi"); ts.add("wangliu"); //遍历 for (String t : ts) { //按照字典顺序升序 System.out.println(t); } /* lisi wangliu wangwu zhangsan zhangsi */ //创建第二个TreeSet TreeSet<Integer> ts2 = new TreeSet<>(); //添加元素 ts2.add(100); ts2.add(200); ts2.add(300); ts2.add(400); ts2.add(5400); ts2.add(70); ts2.add(52); ts2.add(1733); //遍历 for (Integer integer : ts2) { System.out.println(integer); } //升序排列 /* 52 70 100 200 300 400 1733 5400 */

    自定义类型排序

    对于自定义的对象与类型 ,TreeSet无法排序

    以下程序对于Person类型来说,无法排序。因为没有指定Person对象之间的比较规则。

    谁大谁小没有一个比较的规则。

    会出现错误:java.lang.ClassCastException:

    com.javase.collection.Set.Person cannot be cast to java.lang.Comparable

    public class TreeSetTest03 { public static void main(String[] args) { //创建对象 Person p1 = new Person(12); Person p2 = new Person(54); Person p3 = new Person(20); Person p4 = new Person(25); //创建TreeSet集合 TreeSet<Person> people = new TreeSet<>(); //添加元素 people.add(p1); people.add(p2); people.add(p3); people.add(p4); //遍历 for (Person person : people) { System.out.println(person); } } } class Person{ private int age; //构造方法 public Person() { } public Person(int age) { this.age = age; } //重写toString方法 @Override public String toString() { return "Person{" + "age=" + age + '}'; } }

    自定义规则

    第一种方法:类继承Comparable接口
    public class TreeSetTest04 { public static void main(String[] args) { //创建对象 Customer c1 = new Customer(12); Customer c2 = new Customer(54); Customer c3 = new Customer(20); Customer c4 = new Customer(25); //创建TreeSet集合 TreeSet<Customer> customers = new TreeSet<>(); //添加元素 customers.add(c1); customers.add(c2); customers.add(c3); customers.add(c4); //遍历 for (Customer customer : customers) { System.out.println(customer); } } } //放在TreeSet集合中的元素需要实现java.lang.Comparable接口。 //并且实现compareTo方法。equals可以不写 class Customer implements Comparable<Customer>{ private int age; //构造方法 public Customer() { } public Customer(int age) { this.age = age; } //需要在这个方法中编写比较的逻辑,或者说比较的规则 //k.compareTo(t.key) //拿着参数k和集合中每一个k进行比较,返回值可能是 >0 <0 ==0 //比较规则最终还是由程序员指定的:例如按照年龄升序。或者按照年龄降序。 @Override public int compareTo(Customer c) { // c1.compareTo(c2) //this是c1 //c是c2 //c1和c2比较的时候,就是this和c比较 /*int age1 = this.age; int age2 = c.age; if (age1 == age2){ return 0; }else if(age1 > age2) { return 1; }else { return -1; }*/ return this.age - c.age; //>0 <0 ==0 } //重写toString方法 @Override public String toString() { return "Customer{" + "age=" + age + '}'; } } //创建对象 Dog d1 = new Dog("小汪",7); Dog d2 = new Dog("小花",7); Dog d3 = new Dog("张三",8); Dog d4 = new Dog("小安",55); //创建集合 TreeSet<Dog> dogs = new TreeSet<>(); //添加元素 dogs.add(d4); dogs.add(d2); dogs.add(d1); dogs.add(d3); //遍历 for (Dog dog : dogs) { System.out.println(dog); } public class Dog implements Comparable<Dog>{ private String name; private int age; public Dog() { } public Dog(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override public int compareTo(Dog o) { //年龄相同按照名字排序 //姓名是String类型,可以直接比较。调用compareto来完成比较 if(this.age == o.age) return this.name.compareTo(o.name); //年龄不一样 return this.age - o.age; } }
    第二种方法:使用比较器

    Cat对象:

    public class Cat { private String name; private int age; //构造方法 public Cat() { } public Cat(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //重写toString方法 @Override public String toString() { return "小猫咪[" + "name='" + name + '\'' + ", age=" + age + ']'; } }

    比较器对象:

    /* 单独在这里编写一个比较器 比较器实现java.util.Comparator接口。(Comparable是java.lang包下的。Comparator是java.util包下的) */ public class CatComparator implements Comparator<Cat> { @Override public int compare(Cat o1, Cat o2) { if (o1.getAge() == o2.getAge()) return o1.getName().compareTo(o2.getName()); return o1.getAge() - o2.getAge(); } }

    测试类:

    public class TreeSetTest06 { public static void main(String[] args) { //创建TreeSet,需要使用这个比较器。 //TreeSet<Cat> cats = new TreeSet<>(); //这种方式不行 需要在构造方法传递一个比较器进去。创建TreeSet TreeSet<Cat> cats = new TreeSet<>(new CatComparator()); //添加对象 cats.add(new Cat("小沫",15)); cats.add(new Cat("小幂",7)); cats.add(new Cat("小咪",7)); cats.add(new Cat("小幂",8)); cats.add(new Cat("小米",7)); cats.add(new Cat("小米",9)); //遍历 for (Cat cat : cats) { System.out.println(cat); } } } /* 小猫咪[name='小咪', age=7] 小猫咪[name='小幂', age=7] 小猫咪[name='小米', age=7] 小猫咪[name='小幂', age=8] 小猫咪[name='小米', age=9] 小猫咪[name='小沫', age=15] */

    使用匿名内部类

    TreeSet<Cat> cats = new TreeSet<>(new Comparator<Cat>() { @Override public int compare(Cat o1, Cat o2) { if (o1.getAge() == o2.getAge()) return o1.getName().compareTo(o2.getName()); return o1.getAge() - o2.getAge(); } } );
    降序输出

    通过传入比较器让树降序输出

    public class TreeSetTest03 { public static void main(String[] args) { //创建集合 Set<Integer> set = new TreeSet<>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); //添加元素 set.add(15); set.add(17); set.add(188); set.add(173); //遍历 for (Integer integer : set) { System.out.println(integer); } } }

    总结

    Comparable和comparator怎么选择?

    ​ 当比较规则一成不变的时候,或者说当比较规则只有一个的时候,建议实现Comparable接口

    ​ 如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用Comparator接口。

    ​ Comparator接口的设计符合OCP原则

    OCP原则:软件实体应该对扩展开放,对修改关闭,其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。

    Processed: 0.014, SQL: 8