专业企业网站设计服务公司,连云港网站推广优化,服务器搭建网站,专业的网站建设服务交易平台这节我们接着学习 Set 集合。一、Set 集合1.1 Set 概述java.util.Set 接口继承了 Collection 接口#xff0c;是常用的一种集合类型。 相对于之前学习的List集合#xff0c;Set集合特点如下#xff1a;除了具有 Collection 集合的特点#xff0c;还具有自己的一些特点… 这节我们接着学习 Set 集合。一、Set 集合1.1 Set 概述 java.util.Set 接口继承了 Collection 接口是常用的一种集合类型。 相对于之前学习的List集合Set集合特点如下 除了具有 Collection 集合的特点还具有自己的一些特点 Set是一种无序的集合 Set是一种不带下标索引的集合 Set是一种不能存放重复数据的集合Set 接口继承体系Set 接口方法基础案例实例化一个Set集合往里面添加元素并输出注意观察集合特点无序、不重复
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;public class SetTest {public static void main(String[] args) {//1.实例化Set集合指向HashSet实现类对象SetString set new HashSet();set.add(hello1);set.add(hello2);set.add(hello3);set.add(hello4);set.add(hello5);set.add(hello5); //添加失败 重复元素//增强for循环遍历for (String obj : set) {System.out.println(obj);}System.out.println(------------------);//迭代器遍历IteratorString it set.iterator();while (it.hasNext()) {Object obj it.next();System.out.println(obj);}}
}
运行结果
hello1
hello4
hello5
hello2
hello3
------------------
hello1
hello4
hello5
hello2
hello3
通过以上代码和运行结果可以看出Set类型集合的特点无序、不可重复
1.2 HashSet java.util.HashSet 是Set接口的实现类它使用哈希表Hash Table作为其底层数据结构来存储数据。HashSet特点无序性HashSet中的元素的存储顺序与插入顺序无关HashSet使用哈希表来存储数据哈希表根据元素的哈希值来确定元素的存储位置而哈希值是根据元素的内容计算得到的与插入顺序无关。唯一性HashSet中不允许重复的元素即每个元素都是唯一的关键存储自定义对象时必须同时重写hashCode()和equals()否则无法保证唯一性默认用地址值计算哈希导致内容相同的对象被视为不同元素。允许null元素HashSet允许存储null元素但只能存储一个null元素 HashSet中不允许重复元素高效性HashSet的插入、删除和查找操作的时间复杂度都是O(1)哈希表通过将元素的哈希值映射到数组的索引来实现快速的插入、删除和查找操作。基础案例1实例化HashSet对象往里面插入多个字符串验证HashSet特点。
import java.util.HashSet;
import java.util.Set;public class HashSetTest {public static void main(String[] args) {//1.实例化HashSet对象SetString set new HashSet();//2.添加元素set.add(hello);set.add(world);set.add(nihao);set.add(hello);set.add(null);set.add(null);System.out.println(size:set.size());//3.遍历for (String str : set) {System.out.println(str);}}
}
运行结果
size:4
null
world
nihao
hello
根据结果可知HashSet无序、唯一、null值可存在且只能存在一个。
元素插入过程当向HashSet中插入元素时先获取元素的hashCode()值再检查HashSet中是否存在相同哈希值的元素如果元素哈希值唯一则直接插入元素如果存在相同哈希值的元素会调用元素的equals()方法来进一步判断元素是否是相同。如果相同则不会插入重复元素如果不同则插入元素案例展示重写Student类的hashCode()方法
class Student {private String id; // 关键属性1equals中比较private String name; // 关键属性2equals中比较private int age; // 非关键属性equals中不比较hashCode中也不参与计算// 构造方法public Student(String id, String name, int age) {this.id id;this.name name;this.age age;}// 先重写equals()必须与hashCode()基于相同属性Overridepublic boolean equals(Object obj){if (this obj) {return true;}if (obj null) {return false;}if (getClass() ! obj.getClass()) {return false;}Student other (Student)obj;if (name null) {if (other.name ! null) {return false;}}else if (!name.equals(other.name)) {return false;}if (age ! other.age) {return false;}return true;}// 重写hashCode()基于id和name计算Overridepublic int hashCode() {int result 17; // 初始化哈希种子非零经验值// 处理id引用类型可能为nullint idHash (id null) ? 0 : id.hashCode();result 31 * result idHash; // 31是质数减少哈希冲突// 处理name引用类型可能为nullint nameHash (name null) ? 0 : name.hashCode();result 31 * result nameHash;return result; // 返回最终哈希值}
}
如果要往HashSet集合存储自定义类对象那么一定要重写自定义类中的 hashCode方法和equals方法
1.3 TreeSet TreeSet是SortedSetSet接口的子接口的实现类它基于红黑树Red Black Tree数据结构实现。TreeSet特点有序性插入的元素会自动排序每次插入、删除或查询操作后TreeSet会自动调整元素的顺序以保持有序性。唯一性TreeSet中不允许重复的元素即集合中的元素是唯一的。如果尝试插入一个已经存在的元素该操作将被忽略。动态性TreeSet是一个动态集合可以根据需要随时添加、删除和修改元素。插入和删除操作的时间复杂度为O(log n)其中n是集合中的元素数量。高效性由于TreeSet底层采用红黑树数据结构它具有快速的查找和插入性能。对于有序集合的操作TreeSet通常比HashSet更高效。基础案例准备一个TreeSet集合放入多个自定义类Person对象观察是否自动进行排序。基础类Person类
import java.util.Set;import java.util.TreeSet;class Person {private String name;private int age;public Person() {}public Person(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;}Overridepublic String toString() {return Person [name name , age age ];}
}测试类
public class Test_Person {public static void main(String[] args) {//1.实例化TreeSetSetPerson set new TreeSet();//2.添加元素set.add(new Person(zs, 21));set.add(new Person(ls, 20));set.add(new Person(tom, 19));//3.遍历集合for (Person person : set) {System.out.println(person);}}
}运行程序发现
//程序运行提示异常具体如下
Exception in thread main java.lang.ClassCastException:
java.lang.Comparableat java.util.TreeMap.compare(TreeMap.java:1290)at java.util.TreeMap.put(TreeMap.java:538)at java.util.TreeSet.add(TreeSet.java:255)at Test_Person.main(Test_Person.java:41)问题分析根据异常提示可知错误原因是 Person 无法转化成 Comparable 从而导致 ClassCastException 异常 。 为什么会这样呢解析TreeSet是一个有序集合存储数据时一定要指定元素的排序规则有两种指定的方式具体如下自然排序元素所属类型要实现 java.lang.Comparable 接口比较器排序1自然排序如果一个类实现了 java.lang.Comparable 接口并重写了 compareTO 方法那么这个类的对象就是可以比较大小的。
public interface ComparableT {public int compareTo(T o);
}compareTo方法说明int result this.属性.compareTo(o.属性);
result的值大于0说明this比o大result的值小于0说明this比o小result的值等于0说明this和o相等元素插入过程 当向TreeSet插入元素时TreeSet会使用元素的 compareTo() 方法来比较元素之间的大小关系。根据比较结果TreeSet会将元素插入到合适的位置以保持有序性。如果两个元素相等 compareTo() 方法返回0TreeSet会认为这是重复的元素只会保留一个。基础 Person 类
//定义Person类实现自然排序
public class Person implements ComparablePerson {private String name;private int age;public Person() {}public Person(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;}Overridepublic String toString() {return Person [name name , age age ];}//重写方法指定比较规则先按name升序name相同则按age降序Overridepublic int compareTo(Person o) {//注意字符串比较需要使用compareTo方法int r name.compareTo(o.name);if(r 0) {r o.age - this.age;}return r;}
}测试类
import java.util.Set;
import java.util.TreeSet;
import com.briup.chap08.bean.Person;//自然排序测试
public class Test073_Comparable {public static void main(String[] args) {//1.实例化TreeSetSetPerson set new TreeSet();//2.添加元素set.add(new Person(zs, 21));set.add(new Person(ww, 20));set.add(new Person(zs, 21));set.add(new Person(tom, 19));set.add(new Person(tom, 23));set.add(new Person(jack, 20));//3.遍历集合for (Person person : set) {System.out.println(person);}}
}运行结果
Person [namejack, age20]
Person [nametom, age23]
Person [nametom, age19]
Person [nameww, age20]
Person [namezs, age21]对于整型、浮点型元素它们会按照从小到大的顺序进行排序。对于字符串类型的元素它们会按照字典顺序进行排序。注意事项compareTo方法的放回结果只关心正数、负数、零不关心具体的值是多少
2TreeSet 比较器排序思考如果上述案例中Person类不是自定义类而是第三方提供好的不可以修改源码那么如何实现排序规则的指定我们可以使用比较器Comparator来自定义排序规则。比较器排序步骤创建一个实现了Comparator接口的比较器类并重写其中的 compare() 方法该方法定义了元素之间的比较规则。在 compare() 方法中我们可以根据元素的属性进行比较并返回负整数、零或正整数来表示元素之间的大小关系。创建TreeSet对象时将比较器对象作为参数传递给构造函数这样TreeSet 会根据比较器来进行排序。compare方法说明int result compare(o1, o2);
result的值大于0表示升序result的值小于0表示降序result的值等于0表示元素相等不能插入
注意这里和自然排序的规则是一样的只关心正数、负数、零不关心具体的值是多少
案例展示使用比较器排序对上述案例中Person进行排序要求先按age升序age相同则按name降序。
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;public class TestPerson {public static void main(String[] args) {//1.准备自定义比较器对象//匿名内部类形式ComparatorPerson comp new ComparatorPerson() {//重写比较算法先按age升序age相同则按name降序Overridepublic int compare(Person o1,Person o2){int r o1.getAge() - o2.getAge();if (r 0) {//注意比较字符串需使用compareTo()方法r o2.getName().compareTo(o1.getName());}return r;}};//2.实例化TreeSet传入自定义比较器对象SetPerson set new TreeSet(comp);//3.添加元素set.add(new Person(zs,21));set.add(new Person(ww,20));set.add(new Person(zs,21));set.add(new Person(tom,19));set.add(new Person(tom,23));set.add(new Person(jack,20));//4.遍历集合for (Person person : set) {System.out.println(person);}}
}运行结果
Person [nametom, age19]
Person [nameww, age20]
Person [namejack, age20]
Person [namezs, age21]
Person [nametom, age23]
注意如果同时使用自然排序和比较器排序比较器排序将覆盖自然排序。
对比项自然排序Comparable比较器排序Comparator实现位置元素类内部实现接口重写 compareTo元素类外部创建比较器重写 compare排序规则数量一个类只能有一种自然排序规则一个类可以有多个比较器实现不同规则优先级若同时传比较器自然排序会被覆盖传入比较器时优先用比较器规则适用场景元素有固定、单一排序规则如 Integer 数值需要临时、多样化排序如有时按年龄有时按姓名代码侵入性必须修改元素类代码让其实现 Comparable无需修改元素类外部单独定义规则1.4 LinkedHashSet LinkedHashSet 是 HashSet 的一个子类具有 HashSet 的高效性能和唯一性特性并且保持了元素的插入顺序其底层基于哈希表和链表实现。案例展示实例化一个LinkedHashSet集合对象存入多个String字符串观察是否唯一及顺序存储。
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;public class Test_LinkedHashSet {public static void main(String[] args) {//1.实例化LinkedHashSetSetString set new LinkedHashSet();//2.添加元素set.add(bbb);set.add(aaa);set.add(abc);set.add(bbc);set.add(abc);//3.迭代器遍历Iterator it set.iterator();while (it.hasNext()) {System.out.println(it.next());}}
}运行结果
bbb
aaa
abc
bbc1.5 Set 小结下节我们学习Map集合。