Java Set总结

    xiaoxiao2022-07-03  174

    Set接口的特性:Set接口继承了Collection接口,Set集合中不能包含重复的元素,每个元素必须是唯一的,且集合中的元素是无序的。

    Set接口的三个实现类:

    一、HashSet类: HashSet的实现原理其实是HashMap,只不过它的key也是value。采用hash表算法来实现,存放的元素是不重复,且无序的。

    如何判断两个元素重复? 通过hashCode和equals方法来保证元素的唯一性,add方法返回的是boolean类型。 首先,通过判断元素的hashCode值是否一致,只有在该值相同的情况下,才会进行equals判断。如果存储在HashSet中的两个对象HashCode值和equals方法返回的结果都相同时,那么认为这两个元素是相同元素,只能存储一个。 注意:hashCode值相同,而equals不相同的两个元素是不同的,只不过通过存储在同一个hashCode位置上而已。如图2: 应用场景:要一个能快速访问的Set,就使用HashSet。 如果我们添加自定义类的对象到HashSet中时,要重写HashCode方法和equals方法,来确保有相同属性的两个对象具有相同的hashCode值,判断它重复。

    二、TreeSet类: TreeSet是采用树结构实现(称为红黑树算法),元素是有序且不重复的,主要有add,remove,contains方法,时间复杂度都为O(log(n))。还提供一些处理排序的set方法,如first(),headSet(),tailSet(). 因为是有序的,所以输入和输出的顺序是不同的,输出是按顺序来输出的。

    TreeSet集合排序的两种方式:

    让元素自身具备比较性:即传入的元素自身要实现Comparable接口,覆盖compareTo方法。 这种方式也作为元素的自然排序,称为默认排序。 public class Demo4 { public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add(new Person("aa", 20, "男")); ts.add(new Person("bb", 18, "女")); ts.add(new Person("cc", 17, "男")); ts.add(new Person("dd", 17, "女")); ts.add(new Person("dd", 15, "女")); ts.add(new Person("dd", 15, "女")); System.out.println(ts); System.out.println(ts.size()); // 5 } } class Person implements Comparable { private String name; private int age; private String gender; public Person() { } public Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; } 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; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public int hashCode() { return name.hashCode() + age * 37; } public boolean equals(Object obj) { System.err.println(this + "equals :" + obj); if (!(obj instanceof Person)) { return false; } Person p = (Person) obj; return this.name.equals(p.name) && this.age == p.age; } public String toString() { return "Person [name=" + name + ", age=" + age + ", gender=" + gender + "]"; } @Override public int compareTo(Object obj) { Person p = (Person) obj; System.out.println(this+" compareTo:"+p); if (this.age > p.age) { return 1; } if (this.age < p.age) { return -1; } return this.name.compareTo(p.name); //当compareTo()函数返回值为0时,说明两个对象相等 } } 让容器自身具备比较性,自定义比较器:即当元素自身不具备比较性,或具备的比较性不是所需的时, 那么这时候只能让容器自身具备比较性。 定义一个类实现Comparator接口,覆盖compare方法,并将该类的对象作为参数传递给TreeSet集合的构造函数。 注意:当元素自身的比较器Comparable和容器的比较器Comparator同时存在的时候,以容器的Comparator为主。 public class Demo5 { public static void main(String[] args) { TreeSet ts = new TreeSet(new MyComparator()); //该类的对象作为参数传入到TreeSet中 ts.add(new Book("think in java", 100)); ts.add(new Book("java 核心技术", 75)); ts.add(new Book("现代操作系统", 50)); ts.add(new Book("java就业教程", 35)); ts.add(new Book("think in java", 100)); ts.add(new Book("ccc in java", 100)); System.out.println(ts); } } //定义一个类实现Comparator接口,覆盖compare方法 class MyComparator implements Comparator { public int compare(Object o1, Object o2) { Book b1 = (Book) o1; Book b2 = (Book) o2; System.out.println(b1+" comparator "+b2); if (b1.getPrice() > b2.getPrice()) { return 1; } if (b1.getPrice() < b2.getPrice()) { return -1; } return b1.getName().compareTo(b2.getName()); } } class Book { private String name; private double price; public Book() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public Book(String name, double price) { this.name = name; this.price = price; } @Override public String toString() { return "Book [name=" + name + ", price=" + price + "]"; } }

    注意:在重写compareTo或compare方法时,必须要明确比较的主要条件相等时,要比较次要条件。 即姓名相同时,要比较年龄是否相同。

    三、LinekHashSet类: 介于HashSet和TreeSet之间,也是一个hash表,但它同时维护了一个双链表来记录插入的顺序,基本方法的复杂度为O(1)。

    LinkedHashSet dset = new LinkedHashSet(); dset.add(new Apple(7)); dset.add(new Apple(6)); dset.add(new Apple(8)); dset.add(new Apple(10)); dset.add(new Apple(9)); Iterator iterator = dset.iterator(); while (iterator.hasNext()) { System.out.print(iterator.next() + " "); }

    输入和输出的顺序是一样的,因为它有记录插入时的顺序。

    记忆:

    看到array,就要想到角标。看到link,就要想到first,last。看到hash,就要想到hashCode,equals.看到tree,就要想到两个接口。Comparable,Comparator。

    借鉴于: https://blog.csdn.net/qq_33642117/article/details/52040345 https://blog.csdn.net/bestxiaok/article/details/78413022

    最新回复(0)