Set
Set 集合,元素是无序的,而且不能重复的。
重点掌握 HashSet 实现类的使用。
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class SetDemo {
public static void main(String[] args) {
Set s1=new HashSet<>();s1.add("ddd");s1.clear();s1.remove("ddd");Iterator i1 = s1.iterator();}
}
HashSet
HashSet的特点:
-
添加的元素是无序的。
-
HashSet 不是同步的,如果多个线程同时访问一个 HashSet,比如在修改时,一定要手动通过代码来保证同步,也就是保证安全。
-
集合元素值可以是 null。
一些基本的用法:
import java.util.HashSet;
import java.util.Iterator;public class HashSetDemo {
public static void main(String[] args) {
//hashset 存储数据唯一(不可重复) 无序HashSet<String> hs=new HashSet<String>();hs.add("张三");hs.add("张三");System.out.println(hs);System.out.println(hs.size());//遍历 foreach 迭代器for (String string : hs) {
System.out.println("foreach:"+string);}//Iterator<String> i1=hs.iterator();while(i1.hasNext()) {
System.out.println("迭代器:"+i1.next());}}
}
另外,我们从下面的代码可以看出一些hashset的特性,在这里,我们想要让hashset存储数据时不重复存储(因为每new一个对象,其索引不一样,且hash值也不同,即使我们new出的两个对象包含同样的信息,hashset依然会判定为两个不同的对象),我们做两个操作:
-
重写
public boolean equals(Object obj)
方法 -
重写
public int hashCode()
方法
这么做的原因是:
往 HashSet 集合中添加一个元素的时候,默认调用 hashCode() 方法得到该对象的 hashCode 值,用于决定该对象在 HashSet 中存放的位置。
如果两个元素,通过 equals() 方法比较返回 true,但 hashCode() 返回的值不一样,说明两个元素是不 一样的,则允许添加。
所以,HashSet 集合判断两个元素是否相等,就是通过 equals() 方法还有 hashCode 值也一起比较。将来,如果有需要自定义一些判断方法,则可以模仿这里的操作方式。
import java.util.HashSet;//人类
public class Person{
String name;int age;String sex;public Person(String name, int age, String sex) {
super();this.name = name;this.age = age;this.sex = sex;}@Overridepublic int hashCode() {
// TODO Auto-generated method stubreturn age;}//案例 主要对象中姓名 年龄 和性别是相同的 就判断同一个对象使用set保存后体现唯一性//根据性别 姓名 年龄@Overridepublic boolean equals(Object obj) {
Person p1=(Person) obj;if(this.sex.equals(p1.sex)) {
if(this.name.equals(p1.name)) {
if(this.age==p1.age) {
return true;}}}return false;}//alt +Shift+s 弹出窗口 public static void main(String[] args) {
//需求 使用hashset集合 存储4个person对象 并打印输出出来 哈希吗值也有关系HashSet<Person> phSet=new HashSet<Person>();Person zhangsan=new Person("张三", 18, "男");Person zhangsan2=new Person("张三", 18, "男");Person lisi=new Person("李四", 18, "男");Person wangwu=new Person("王五", 18, "男");Person qianliu=new Person("钱六", 18, "男");phSet.add(zhangsan);phSet.add(lisi);phSet.add(wangwu);phSet.add(qianliu);phSet.add(zhangsan2);System.out.println(phSet);}@Overridepublic String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";}
}
LinkedHashSet
LinkedHashSet 从名字上看,跟“链式”有关,它也是根据元素的 hashCode 值来决定元素的存储位置, 但还多使用链表来维护元素的顺序。
访问它的时候,会根据元素的添加顺序来访问集合中的元素,有个好处,访问时的性能会很好。
因为是链式的结构,在插入数据的时候,性能略差于 HashSet,插入元素时不建议使用。
import java.util.LinkedHashSet;public class LinkedHashSetDemo {
public static void main(String[] args) {
//无序 唯一的//链表结构与哈希吗值都有关系//与hashset相比 访问快 插入慢//方法同 hashset一样用LinkedHashSet<String> lhs =new LinkedHashSet<String>();lhs.add("张三");lhs.add("张三");lhs.add("张三");lhs.add("张三");lhs.add("张三");System.out.println(lhs);
// lhs.remove("zhangsan");}
}
public class TreeSetTest {
public static void main(String[] args) {
TreeSet nums = new TreeSet(); // 向 TreeSet 中添加对象 nums.add(5); nums.add(2); nums.add(10); nums.add(-9); // 输出集合元素,看到集合元素已经处于排序状态 // 并没有按添加的先后顺序进行排列System.out.println(nums);// 输出集合里的第一个元素 System.out.println(nums.first()); // 输出-9 // 输出集合里的最后一个元素 System.out.println(nums.last()); // 输出10 // 返回小于4的子集,不包含4 (左闭右开)System.out.println(nums.headSet(4)); // 输出[-9, 2] // 返回大于5的子集,如果Set中包含5,子集中还包含5 (左闭右开)System.out.println(nums.tailSet(5)); // 输出 [5, 10] // 返回大于等于-3,小于4的子集。 // -3 < x < 4 System.out.println(nums.subSet(-3, 4)); // 输出[2] }
}
TreeSet
不同于hashset是根据哈希值来存储元素,TrerSet借助了红黑树来存储对象,虽然不可索引,但是内部依然是按顺序排列的。
TreeSet 可保证元素处于排序的状态,所以 TreeSet 采用的是红黑树的数据结构来存储集合元素的。
排序规则有:自然排序(默认)和定制排序。
import java.util.TreeSet;public class TreeSetDemo {
public static void main(String[] args) {
//存储红黑二叉树数据结构 会对数进行排序存储TreeSet ts=new TreeSet();ts.add(222);ts.add(13);ts.add(2);ts.add(33);ts.add(4);ts.add(1);System.out.println(ts);System.out.println("最高的"+ts.last());System.out.println("最小的"+ts.first());System.out.println("检索最小元素返回并删除"+ts.pollFirst());System.out.println("检索最大元素返回并删除"+ts.pollLast());System.out.println(ts);//遍历 foreach 迭代器}
}
TreeSet 会调用 compareTo(Object obj) 方法来比较元素之间的大小关系,按升序进行排列。
此方法属于 Comparable 接口,将返回一个整数值,实现该接口的类就可以用返回值来比较大小。
Comparable 接口,主要提供了比较大小的标准,有些将来会碰到的常用类:BigDecimal、 BigInteger、Character、Boolean、String 、Date、Time 等。 当我们在Treeset中插入一个我们自己写的对象的时候会报错,其原因就是TreeSet利用compareTo(Object obj) 方法来比较元素之间的大小,所以我们需要将我们要比较的对象实现Comparable 接口。
当 TreeSet 添加元素时,会调用 compareTo() 方法先去比较大小和根据红黑树去查找位置,如果通过
compareTo() 方法比较相等,就不能再添加了,所以下面的代码Set中只有一个元素。
下面是我们要放入TreeSet的对象,我们实现了Comparable<T>方法:
import java.util.Comparator;public class Pet implements Comparable<Pet>{
String name;String color;int age;public Pet(String name, String color, int age) {
super();this.name = name;this.color = color;this.age = age;}@Overridepublic String toString() {
return "Pet [name=" + name + ", color=" + color + ", age=" + age + "]";}//treeset比较方法 原理红黑二叉树数据结构@Overridepublic int compareTo(Pet o) {
return 0;}
}
import java.util.TreeSet;public class TreeSetDemo2 {
public static void main(String[] args) {
TreeSet<Pet> ts=new TreeSet<Pet>();ts.add(new Pet("妮妮", "白色", 18));ts.add(new Pet("妮妮", "白色", 18));System.out.println(ts);}
}
同时呢,如果想要实现我们自定义的排序方式,可以利用内部类的方法来实现:
import java.util.Comparator;
import java.util.TreeSet;public class Pet2 {
int age;public Pet2(int age) {
super();this.age = age;}@Overridepublic String toString() {
return "Pet2 [age=" + age + "]";}//public static void main(String[] args) {
// TreeSet<Pet2> treeSet=new TreeSet<Pet2>();
// treeSet.add(new Pet2(18));
// treeSet.add(new Pet2(17));
// treeSet.add(new Pet2(2));
// System.out.println(treeSet);//方式2 定制排序TreeSet<Pet2> t2=new TreeSet<Pet2>(new Comparator<Pet2>() {
@Overridepublic int compare(Pet2 o1, Pet2 o2) {
// TODO Auto-generated method stub//比较return o1.age>o2.age?-1:o1.age<o2.age?1:0;}});//降序t2.add(new Pet2(18));t2.add(new Pet2(1));t2.add(new Pet2(23));System.out.println(t2);}}