首先总结一下集合的体系:
集合 的体系:
------------| Collection 单例集合的根接口
----------------| List 如果是实现了List接口的集合类,具备的特点: 有序,可重复。
-------------------| ArrayList 底层是维护了一个Object数组实现的。 特点: 查询速度快,增删慢。
-------------------| LinkedList 底层是使用了链表数据结构实现的, 特点: 查询速度慢,增删快。
-------------------| Vector(了解即可) 底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低。
----------------| Set 如果是实现了Set接口的集合类,具备的特点: 无序,不可重复。
-------------------| HashSet 底层是使用了哈希表来支持的,特点: 存取速度快.
-------------------| TreeSet 如果元素具备自然顺序 的特性,那么就按照元素自然顺序的特性进行排序存储。
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;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return age;
}
//案例 主要对象中姓名 年龄 和性别是相同的 就判断同一个对象使用set保存后体现唯一性
//根据性别 姓名 年龄
@Override
public 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);
}
@Override
public 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;
}
@Override
public String toString() {
return "Pet [name=" + name + ", color=" + color + ", age=" + age + "]";
}
//treeset比较方法 原理红黑二叉树数据结构
@Override
public 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;
}
@Override
public 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>() {
@Override
public 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);
}
}