HashSet的底层实际上是一个HashMap,而HashMap的数据结构为哈希表/散列表
所以先讲解什么是哈希表/散列表?
哈希表是:数组和单向链表的结合
哈希表本质是一个数组,只不过这数组中每个元素又是单向链表
Set集合:HashSet
1.HashSet底层实际上是一个HasMap,HashMap底层采用了哈希表数据结构。
2.哈希表又叫散列表,哈希表是一个数组,这个数组中每一个元素是一个单向链表。每个单向链表都有一个独一无的hash值,代表数组的下标。在某个单向链表中的每一个节点上的hash值是相等的。hash值实际上是key调用hashCode方法,再通过“hash function”转换成的值、
3.如何向哈希表中添加元素:
先调用被存储的key的hashCode方法,经过某个算法得出hash值,如果在这个哈希表中不存在这个hash值,则直接加入元素。如果该hash值已经存在,继续调用key之间的equals方法,如果equals方法返回false,则将该元素添加。如果equals方法返回true,则放弃添加该元素
4.HashSet其实是HashMap中的key部分。HashSet有什么特点,和HashMap中的key应该具有向同的特点
5.(HashSet的底层实际上是HashMap)HashMap和HashSet 始化容量为16,加载因子为0.75。加载因子(当数组内元素达到总容量的75%时开始扩容)
import java.util.*;
public class HashSetTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Set n1 = new HashSet();
n1.add(1);
n1.add(1);
n1.add(new Object());
n1.add(100);
n1.add(100);
n1.add(85);
Iterator it = n1.iterator();
while(it.hasNext())
{
System.out.println(it.next());
//输出结果为1 100 85 java.lang.Object@34c45dca
//可以看到Set集合的特点,无序不可重复
}
}
}
关于往Set集合中存储的元素,该元素的hasCode和equals方法
HashMap中有一个put方法,put(key,value) key是无序不可重复的,一下程序的employee相当于是key。
注意:在没有重写emplyee内部的hashcode方法之前,如果新建了两个员工对象,两个对象内部存储的姓名以及编号即使相同,也都会添加到Set集合内部(因为两个不同的对象在没有重写hashcode方法之前,得到的hash值是不同的,所以会存储进去)
再注意:当hashcode得出的值相同时,就通过equals比较内容,内部不同再添加。
以上可得需要比对两个指标,来判断是否能加入,hashcode返回的值不同,加在数组的不同位置,hashcode返回的值相同,但是equals比对后不同的,加载同一hashcode位置上单向链表下,两者都不同,则不添加
得出结论:需要重写employee内部的hashcode方法
import java.util.*;
public class HashSetTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建集合
Set s = new HashSet();
//创建几个员工实例
Employee e1 = new Employee( "1001","jack");
Employee e2 = new Employee("1002","jack");
Employee e3 = new Employee("2001","bob");
Employee e4 = new Employee("3001","tom");
//添加元素
s.add(e1);
s.add(e2);
s.add(e3);
s.add(e4);
//查看元素个数
System.out.println(s.size());
System.out.println("1001".hashCode());
System.out.println("1100".hashCode());
}
}
//根据业务逻辑得知:该公司员工编号是:1000 - 9999
//写一个员工类
class Employee{
String no;
String name;
Employee(String no,String name){
this.no = no;
this.name = name;
}
public boolean equals(Object e) {
if(this == e) {
return true;
}else if(((Employee)e).name.equals(name)&&((Employee)e).no.equals(no))
{
return true;
}
return false;
}
//重写hashcode方法,这里有疑问,就是没有能够实现重写hashcode后使得1000-1999分在数组的同一位置下
public int hashCode() {
return no.hashCode();
}
}
java.util.Set;
java.util.SortedSet;)
java.util.TreeSet;
SortedSet:1.是个接口,TreeSet实现了这个接口
特点:无序不可重复,但是存进去的元素可以按照元素大小顺序自动排列(从小到大)
mport java.util.*;
public class SortrdSetTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Set s = new TreeSet();
s.add(117);
s.add(12);
s.add(10);
s.add(12);
s.add(100);
s.add(15);
s.add(9);
Iterator it = s.iterator();
while(it.hasNext()) {
System.out.println(it.next());
//输出结果为9 10 12 15 100 117
//可以看到他的特点无序不重复,并能够按照从小到大排列
}
//日期也会按照从小到大的顺序排列
//同时注意下日期的使用,回顾之前的知识
//日期Date
String st1 = "2008-08-08";
String st2 = "2009-09-09";
String st3 = "2005-05-05";
String st4 = "2013-04-08";
SimpleDateFormat f1 = new SimpleDateFormat("yyyy-MM-dd");
Date t1 = f1.parse(st1);
Date t2 = f1.parse(st2);
Date t3 = f1.parse(st3);
Date t4 = f1.parse(st4);
Set time = new TreeSet();
time.add(t1);
time.add(t2);
time.add(t3);
time.add(t4);
Iterator it2 = time.iterator();
while(it2.hasNext()) {
System.out.println(f1.format(it2.next()));
}
}
}
SortedSet是如何实现排序的,(总结,是通过comparable的返回值进行排序的,程序员只需要重写comparable方法,然后SortedSet会通过comparable的返回值来进行排序,升序和倒序由自己返回值来决定,具体示例看程序)
(问题:具体底层拿到返回值后如何排序,是通过二叉树实现,后面再深入研究)
如果不在自己新创建的类里实现comparable这个接口,是无法在SortedSet集合里面进行比较的
故要自己创建的类里实现comparable接口,一个接口要实现,就要实现里面所有的方法
import java.util.*;
public class SortedTest2 {
public static void main(String[] args) {
SortedSet n1 = new TreeSet();
User u1 = new User(10);
User u2 = new User(12);
User u3 = new User(9);
User u4 = new User(15);
User u5 = new User(10);
User u6 = new User(21);
n1.add(u1);
n1.add(u2);
n1.add(u3);
n1.add(u4);
n1.add(u5);
n1.add(u6);
Iterator it = n1.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
class User{
int age;
User(int age){
this.age = age;
}
//重写toStrin方法
public String toString() {
return "use is age:"+this.age+"";
}
//以年龄为标准来进行排序,以下程序是以升序排除了,按照返回值比自身age小返回一个负数
public int compareTo(Object o) {
//这行代码是模仿,Integer类型写的,以年龄为排序的标准
return (this.age<((User)o).age)? -1:(this.age==((User)o).age)? 0:1;
}
}
通过创建比较器,来完成比较
还有匿名内部类的使用下·
//让SortedSet集合排序的另外一种方式,构造比较器comparator
import java.util.*;
public class SortedTest3 {
public static void main(String[] args) {
//创建TreeSet,在创建的时候就把比较器传进去
SortedSet s1 = new TreeSet(new SortedComparator());
//还可以通过匿名内部类的方法,匿名内部类很久没用过了,顺便回忆
//写了匿名内部类,不能重复使用,只能使用在创建的S1对象内部
SortedSet s1 = new TreeSet(new Comparator() {
public int compare(Object o1, Object o2) {
return (((User) o1).age < ((User) o2).age) ? -1 : (((User) o1).age == ((User) o2).age) ? 0 : 1;
}
});
User u1 = new User(10);
User u2 = new User(7);
User u3 = new User(16);
User u4 = new User(5);
s1.add(u1);
s1.add(u2);
s1.add(u3);
s1.add(u4);
Iterator it = s1.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
class User {
int age;
User(int age){
this.age = age;
}
}
class SortedComparator implements Comparator{
public int compare(Object o1, Object o2) {
return (((User)o1).age<((User)o2).age)?-1:(((User)o1).age==((User)o2).age)?0:1;
}
}