一、HashSet
Set接口下有一个 HashSet 实现类,HashSet的底层是用 HashMap 实现的( 看了 HashMap后再回来看HashSet的实现 ),因此,查询效率高。由于采用Hashcode算法直接确定元素的内存地址,增删效率也高。
HashSet 接口中的元素 无序不可重复 ,不包含重复元素,最多包含一个 null,元素没有顺序 。
1. 无序
元素的存储顺序,不由存放顺序而定,容器有自己的一套存放顺序的规则。
2.遍历
不能用普通for循环遍历,因为Set集合的元素是没有下标的,不可以通过下标获取
System.out.println("======增强for循环=====");
for (String str:set){
System.out.println(str);
}
System.out.println("-------迭代器遍历------");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
3.不可重复
添加元素之前,就已经经过了判断。判断是否相等先走 hashCode 方法,如果hashCode方法返回值相同,再走 equals 方法进一步比较.如果不想让属性相同的javaBean对象存储在hashSet中,javaBean类应重写HashCode和equals方法。
二、Map接口
Map只是一个接口,其中提供了Map的规范,即各种方法的定义
Object put(Object key, Object value); //添加元素
Object get(Object key); //根据key获取value
Object remove(Object key); //根据key删除一个元素
boolean containsKey(Object key); //判断map中是否有该key
boolean containsValue(Object value);//判断map中是否有该value
int size(); //查看元素的个数
boolean isEmpty(); //判断元素是否为空
void putAll(Map t); //将一个map添加到另一个map中
void clear();//情况map
注意:如果存入的键值对中key相同,那么后面的会覆盖掉前面的当数据存放到Map之后,我们是无法控制存放数据的顺序的
1.hashMap的使用
//Map接口的特点,key不允许重复,值可以重复,而且key是无序的
//创建集合对象
HashMap hm=new HashMap();
//(1)添加元素
hm.put("hello", 123);//123自动装箱成Integer类,集合不允许出现基本数据类型
hm.put("world", 456);
hm.put("hello", 1000);//集合去添加元素的时候它的键(key)是不允许重复的,如果重复将进行键的覆盖
hm.put("java", 1000);//值可以重复(1000)
System.out.println("集合中元素的个数:"+hm.size());
System.out.println("集合是否为空:"+hm.isEmpty());
System.out.println(hm);
System.out.println(hm.remove("world"));//先输出后移除,只移除了键world,456还在
System.out.println(hm);
//判断
//containsKey判断这个键是否存在
System.out.println(hm.containsKey("java")+"\t"+hm.containsKey("world"));
//containsValue判断这个值是否存在
System.out.println(hm.containsValue(1000)+"\t"+hm.containsValue(2000));
//获取元素,根据键去获取值
System.out.println(hm.get("java")+"\t"+hm.get("world"));
//获取所有键(key)的集合
Set set=hm.keySet();
//遍历所有键的内容
for(Object obj:set){
System.out.println(obj);
}
//获取所有值(value)的集合
System.out.println("\n---------------------- ");
Collection coll=hm.values();
//遍历所有值的类型
for(Object obj:coll){
System.out.println(coll);
}
//获取所有key-value关系的集合
Set entrySet=hm.entrySet();
for(Object obj:entrySet){
System.out.println(obj);
}
HashMap中存储数据的特点:
- 存储的元素是以K-V的形式存在的
- map集合中 key 必须要唯一,如果添加了相同的键值对(键相同)会发生覆盖
- map集合中元素(键值对)是无序的,和Set集合类似
2.HashMap与Hashtable的区别
/**
* HashMap与Hashtable
* 区别:
* (1)版本不同 HashMap JDK1.2 Hashtable JDK1.0
* (2)HashMap继续了AbstractMap,实现了Map接口,Hashtable继承了Dictionary实现Map接口
* (3)HashMap允许null值和null键,但是null作为key只允许以一个,Hashtable非null的键和值
* (4)HashMap是线程不同步的(效率高,安全性低),Hashtable是线程同步的(效率低,安全性高)
*/
遍历HashMap
Map<String, String> map = new HashMap<>();
map.put("1","一,壹,Ⅰ");
map.put("2","二,贰,Ⅱ");
map.put("3","三,叁,Ⅲ");
//遍历map集合
Set<Entry<String, Integer>> entries = map.entrySet();
//迭代器
System.out.println("=========迭代器===============");
Iterator<Entry<String, Integer>> iterator = entries.iterator();
while (iterator.hasNext()){
Entry<String, Integer> entry = iterator.next();
System.out.println(entry.getKey()+"-->"+entry.getValue());
}
//增强for循环
System.out.println("=========增强for循环===============");
for (Entry<String,Integer> entry:entries){
System.out.println(entry.getKey()+"-->"+entry.getValue());
}
//keySet
System.out.println("========KeySet===========");
Set<String> keys = map.keySet();
for (String key:keys){
System.out.println(key+"-->"+map.get(key));
}
注意: 如果存入的键值对中key相同,那么后面的会覆盖掉前面的当数据存放到Map之后,我们是无法控制存放数据的顺序的
3. hashMap底层原理
1.哈希表的结构和特点
hashtable 也叫散列表
特点:快 很快 神奇的快
结构:结构有多种
最流行、最容易理解:顺序表+链表
主结构:顺序表
每个顺序表的节点在单独引出一个链表
2.哈希表是如何添加数据的
1.计算哈希码(调用 hashCode(),结果是一个 int 值,整数的哈
希码取自身即可)
2.计算在哈希表中的存储位置 y=k(x)=x%11 x:哈希码 k(x)
函数 y:在哈希表中的存储位置
3.如何减少冲突
因此,一般情况下,装填因子取经验值 0.5
4.哈希函数的选择
直接定址法 平方取中法 折叠法 除留取余法(y = x%11)查询相关资料
JDK1.8 开始,当链表的个数>=8 时,就会将链表转为红黑树,
目的是为了减少查询比较的次数。
表象看集合里面数据的特征:
List(ArrayList,LinkedList):单个数据,数据是可以重复的,而且可以指定位置
Set:单个数据,数据是不可以重复,而且是无序的(不由用户来指定位置|顺序)
Map:成键值对的数据,数据是没有顺序的,键是不可以重复的
hashCode在Set和Map集合中判断对象是否重复(相同)
equals也是用来判断对象是否相同(重复)List,Set,Map
三、迭代器
所有实现了Collection接口的容器类都有一个 iterator 方法用以返回一个实现了Iterator接口的对象。
Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作。
Iterator接口定义了如下方法:
1.Iterator
boolean hasNext(); //判断是否有元素没有被遍历
Object next(); //返回游标当前位置的元素并将游标移动到下一个位置
void remove(); //删除游标左面的元素,在执行完next之后该 ,操作只能执行一次
Iterator<Student> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
2.ListIterator
相比于Iterator,collection.listIterator([index])方法可以给定index使指针指向具体的位置,listIterator多了hasPrevious()、previous()等方法完成集合的倒叙遍历。
ListIterator<Student> listIterator = list.listIterator(list.size());
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
四、Collections工具类
void sort(List) //对List容器内的元素排序,排序的规则是按照升序进行排序。
void shuffle(List) //对List容器内的元素进行随机排列
void reverse(List) //对List容器内的元素进行逆续排列
void fill(List, Object) //用一个特定的对象重写整个List容器
int binarySearch(List, Object)//对于顺序的List容器,采用折半查找的方法查找 特定对象
上述中collections工具类中的某些方法用于对集合中的对象进行排序
问题:上述方法根据什么确定集合中对象大小顺序?
所有可以“排序”的类都实现了 java.lang.Comparable 接口, Comparable 接口中只有一个方法 public int compareTo(Object obj)
1.Comparable接口
返回 0 表示 this == obj
返回正数表示 this > obj
返回负数表示 this < obj
实现了Comparable 接口的类通过实现 comparaTo 方法从而确定该类对象的排序方式。
//使用工具类对集合进行排序
public class CollectionTest {
public static void main(String[] args) {
List<Student> list=new ArrayList<>();
Student student=new Student(18,"张三",55.5);
Student student2=new Student(18,"李四",44.4);
Student student3=new Student(20,"王五",66.6);
list.add(student2);
list.add(student);
list.add(student3);
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}
//实现Comparable接口,重写compareTo方法,确定比较规则
public class Student implements Comparable<Student>{
private int age;
private String name;
private double weight;
public Student(int age, String name, double weight) {
this.age = age;
this.name = name;
this.weight = weight;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", weight=" + weight +
'}';
}
@Override
public int compareTo(Student o) {
// 0 1(没变) -1(倒序)
//如果年龄不能,则按年龄排序;若年龄相等,则按体重排序
if (this.age==o.age){
return (this.weight < o.weight) ? -1 : ((this.weight == o.weight) ? 0 : 1);
}else {
return (this.age < o.age) ? -1 : ((this.age == o.age) ? 0 : 1);
}
}
}
2.Comparator接口
除了javaBean类实现comparable接口并重新compareTo方法之外,也可以定义一个类去实现Comparator接口并重写起compare方法。然后在对集合排序时,给定自定义的比较类
//比较器
class MyCor implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
//按照年龄排序
return o1.getAge()-o2.getAge();
}
}
public static void main(String[] args) {
List<Student> list=new ArrayList<>();
Student student=new Student(17,"张三",55.5);
Student student2=new Student(18,"李四",44.4);
Student student3=new Student(20,"王五",66.6);
list.add(student2);
list.add(student);
list.add(student3);
//对集合排序时,给定具体的比较器对象
Collections.sort(list,new MyCor());
System.out.println(list);
}