回顾总结13
集合
数组的不足之处
- 长度开始时必须指定,而且一旦指定,不能更改
- 保存的必须为同一类型的元素
- 使用数组进行增加、删除元素的示意代码
集合的优点
- 可以动态保存任意多个对象,使用比较方便
- 提供了一系列方便的操作对象的方法:add、remove、set、get
- 使用集合添加、删除新元素的示意代码
Collection
继承Iterable
单列集合
Iterator:迭代器
- 遍历Collection集合中的元素
- 所有实现了Collection接口的集合类都有一个iterator方法,用以返回一个实现了Iterator接口的对象,返回一个迭代器
- Iterator仅用于遍历集合,Iterator本身并不存放对象
常用方法
- add:添加单个元素
- remove:删除指定元素(可以通过下标删除;还可以直接删除对象,返回一个布尔值,是否删除成功
- contains:查找元素是否存在
- size:获取元素个数
- isEmpty:判断是否为空
- clear:清空
- addAll:添加多个元素
- containsAll:查找多个元素是否都存在
- removeAll:删除多个元素
- iterator:遍历集合(iterator方法返回的是一个新对象itertor,所以如果要遍历的话,不能简写成list.iterator().next()去输出,每一次调用的时候都会走一遍iterator方法生成一个新的iterator对象,重置指针,永远输出第一个数据。
应该使用list.iterator()方法返回一个lterator对象,并且接收它,每次用它来调用.next()来遍历集合。
使用while循环遍历,每次使用next()方法时,都要用hasNext()判断是否有下一条数据,否则最后一条会爆异常NoSuchElementException- 增强for循环的底层调用的就是迭代器iterator
List
继承Collection
特点
- List集合类中元素有序(添加顺序和取出顺序一致)
- List集合类中元素可重复
- List集合类中每个元素有其对应的顺序索引(有序就有索引,位置不会变动),支持索引
- List集合中的元素都对应一个整数型的序号记载其在容器中的位置,根据序号存取容器中的元素(有序就有索引,有索引就能取元素)
常用方法
- void add(int index ,Object ele):在index位置插入ele元素
- boolean addAll(int index ,Collection eles):在index位置插入集合eles中的所有元素
- Object get(int index):获取index位置的元素
- int indexOf(Object obj):返回obj在集合中首次出现的位置
- int lastIndexOf(Object obj):返回obj在集合中末次出现的位置
- Object remove(int index):移除指定index位置的元素,并返回此元素
- Object set(int index ,Object ele):设置指定index位置的元素为ele,相当于替换
- List subList(int fromIndex , int toIndex):返回从fronIndex到toIndex位置的子集合
ArrayList
线程不安全的
-
ArrayList存放数据是通过一个Object类型的数组elementData,因为是Object类型的,通过向下转型,可以存放所有类型的对象。
transient Object[] elementData;transient的意思是短暂的,表示该属性不会被序列化
-
ArrayList有两个构造器,一个是无参,初始容量为0,第一次增加元素时,扩容到10,然后1.5倍依次增加。一个是自定义初始容量,之后按1.5倍增加。
创建ArrayList流程
- 未指定容量,进入无参构造,创建一个空的elementData数组
- 增加元素,先判断有没有下一个空的容量,容量值为0的话,设置一个最小容量10,如果不为0的话,增加容量为原有的1.5倍,然后用copyOf进行数据的转移
Vector
线程安全的
- 存放数据也是一个对象数组,protected Object[] elementData
- Vector是线程同步的,线程安全,Vector类的操作方法带有synchronized修饰符
- 构造器同ArrayList,无参初始为10,然后2倍依次增加;自定义容量扩容时,2倍依次增加。
LinkedList
线程不安全的
底层是双向链表
每个Node节点含有三个属性,next:指向下一个节点;item:存放数据;prev:存放指向此节点的上一个节点信息
创建流程
未指定容量,无参构造,是空的,没有东西。当增加元素时,进入linkLast方法,创建节点,分配prev、item、next数据和first、last指针。LinkedList的大小用size表示,没有容量为空的说法,每次新增节点,然后增加size。
Set
特点:
- 无序(存储位置和添加顺序不一致)且没有索引
- 不允许重复元素,所以最多包含一个null
- 因为没有索引,所以遍历的时候不能用普通for循环遍历了,可以使用增强for循环和迭代器
TreeSet
里面有一个comparator的匿名对象,实现comparable接口的compareTo方法。来进行key值的对比,如果判定一样,key值不变,value值更新。
TreeSet增加元素时,其元素需要保证实现comparable接口才能加入进去。String类型已经实现comparator接口。
HashSet
底层是HashMap$Node
它存储是通过(数组+链表+红黑树)
new HashSet的过程就是new HashMap,里面什么也没做。
添加元素的时候,会发生很多操作。
-
add调用map.put方法,参数为(K,V)
-
接着调用putVal方法,这个方法会调用hash(key)方法返回key的hashCode的值经过算法得到的table序号,算法是(h = key.hashCode()) ^ (h >>> 16)
-
跳回putVal方法,先判断table数组是否为空,如果为空,就进入resize方法进行扩容,初始扩容为16,阈值因子为0.75。当存放了12个数据之后会进行下一次的扩容,每一次扩容大小为2倍。
有了容量,现在把元素加入HashSet中,先判断hash与数组容量进行算法得出来的数组位置,是否有数据。
-
没有就直接放进去。
-
如果存在数据,先判断hash是否相同,并且用equals判断key是否相同(这一步判断是否是相同数据,存在相同数据,直接返回),对第一个判断不同后,继续与链表后面相比较,如果都不同的话,存放在链表最后
-
扩容判断
当添加元素完成后,会增加size大小,如果size超过了阈值,会进行扩容。
如果一条链表超过8,之后进行一次判断,size是否大于64。
如果不满足,进行一次扩容,满足会把该链表转换成红黑树。
删除
remove方法是通过hashcode的值来查找删除对象的。
没重写hashcode方法时,改变对象的值不会导致hashcode变化,能正常找到位置并进行删除
重写hashcode方法后,改变对象的值会导致hashcode变化(它变化了,就不该在这个位置,但是现在他在这个位置,所以找不到它了,原来的hashcode被改变了),remove删除时会先找到hashcode,根据hashcode找该对象的位置,如果找到了了,再进行equals的比较。但是当我们改变值时,hashcode随之变化,更改后的hashcode会带领JVM找到另一个地方,进行比较,结果发现找不到人,没有想要删除的对象,导致删除失败。(找不到想要删除对象的hashcode值了)如果恰好有同样的对象放在这个地方,可以放进去,并且会被JVM视作此对象删除掉。
HashSet是根据hashcode找索引位置存放Node的,当hashcode被修改后,会根据新的hashcode找Node所在的索引位置,然后通过euqals进行比较,全部对上了,才能删除成功。
LinkedHashSet
底层是LinkedHashMap,维护了一个数组(hash)加双向链表
添加元素时,先求hash值,然后求索引,确定该元素在hashtable的位置,然后将元素加入到双向链表(存在相同的就不添加)。每一次都把最后一个元素的next指向新加入的元素
LinkedHashSet是能顺序插入,顺序遍历的
LinkedHashSet存储的数据不是节点Node,而是继承了HashMap.Node的静态内部类Entey,有before、next属性
Map
双列集合(Key-value)
特点
- Map和Collection并列存在,用于保存具有映射关系的数据:Key--Value
- Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
- Map中的key不允许重复
- Map中的value可以重复
- Map的key可以为null,value也可以为null,key为null也只能有一个,value为空可以有多个
- 常用String类作为Map的key
- key和value之间存在单向一对一关系,即通过指定的key,总能找到对象的value
核心k-v
把HashMap转化成EntrySet之后,等于Node转化成Entry,这个Entry只有k-v(k是用Set存储的(KeySet),v是用Collection存储的(Values))
简单记(Entry只有k-v,Node里有额外的hash和next等,为了方便遍历HashMap,会创建一个EntrySet,使用Entry指向Node实例,
- Entry是一个接口,里面有两个成员K,V
- Node是实现类,实现了Entry。
K和V是存储在Node里面的,但是Entry可以引用,这是多态的性质,父类引用指向子类实例。
常用方法
- put:添加
- remove:根据键key删除映射关系
- get:根据键获取值
- size:获取元素个数
- isEmpty:判断个数是否为0
- clear:清除
- containsKey:查找键是否存在
6大遍历方式
-
第一种
先取出所有的key,再通过key取出对应的value
//有一个HashMap引做map
Set keyset = map.keySet();
//(1)增强for循环
for(Object key : keyset){
sout(key + "-" + map.get(key));
}
//(2)迭代器
Itertor itertor = keyset.iterator();
while(iterator.hasNext()){
Object key = iterator.next();
sout(key + "-" + map.get(key));
}
-
第二种
把所有的values取出
Collection values = map.values(); //(3)增强for循环 for(Object value : values){ sout(value); } //(4)迭代器 Itertor itertor = values.iterator(); while(iterator.hasNext()){ Object value = iterator.next(); sout(value); } -
第三种
通过EntrySet获取k-v
//把map的Node值的地址放到entrySet的Entry里 Set entrySet = map.entrySet(); //(5)增强for for(Object entry : entrySet){ //把entrySet的entry取出来这个类型是Node //这个Node是内部类,取不到它的方法 //把Node转换成Map.Entry类型 Map.Entry m = (Map.Entry)entry; sout(m.get(key) + "-" + m.get(value)); } //(6)迭代器 Itertor itertor = entrySet.iterator(); while(iterator.hasNext()){ Object entry = iterator.next(); Map.Entey m = (Map.Entry)entry; sout(m.get(key) + "-" + m.get(value));
遍历方式练习
要求
public static void main(String[] args) {
Map hashMap = new HashMap();
hashMap.put(1,new Employee("孙悟空",18888,1));
hashMap.put(2,new Employee("唐僧",11888,2));
hashMap.put(3,new Employee("白龙马",25888,3));
// Set keySet = hashMap.keySet();
//1
// for (Object o : keySet) {
// Employee e = (Employee) hashMap.get(o);
// if(e.getSal() > 18000){
// System.out.println(e);
// }
// }
//2
// Iterator iterator = keySet.iterator();
// while(iterator.hasNext()){
// Employee e = (Employee) hashMap.get(iterator.next());
// if(e.getSal() > 18000) {
// System.out.println(e);
// }
// }
//3
Set entrySet = hashMap.entrySet();
for (Object obj : entrySet) {
Map.Entry entry = (Map.Entry)obj;
Employee e = (Employee) entry.getValue();
if(e.getSal() > 18000){
System.out.println(e);
}
}
//4
Iterator iterator = entrySet.iterator();
while(iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
Employee e = (Employee) entry.getValue();
if(e.getSal() > 18000){
System.out.println(e);
}
}
}
}
class Employee {
private String name;
private double sal;
private int id;
public Employee(String name, double sal, int id) {
this.name = name;
this.sal = sal;
this.id = id;
}
public double getSal() {
return sal;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", sal=" + sal +
", id=" + id +
'}';
}
HashMap
参考HashSet
底层是(数组+链表+红黑树)Map$Entry
使用频率最高的实现类
以HashMap$Node类型存储
不保证映射的顺序,底层是以hash表的方式存储的
HashMap没有实现同步,线程不安全
LinkedHashMap
TreeMap
Hashtable
特点
- 存放的是键值对K-V
- hashtable的键和值不能为null,会抛出NullPointerException
- hashtable使用方法和HashMap一样
- hashtable是线程安全的,HashMap是线程不安全的
底层是Hashtable$Entry[]数组
初始容量为11,临界因子为0.75 ,扩容机制为(*2+1)
Properties
集合使用总结
判断存储的类型(一组对象(单列)还是一组键值对(双列)
一组对象
Collection接口
允许重复
List
增删多
链表易于增删
LinkedList:底层维护了一个双向链表
改查多
数组易于改查
ArrayList:底层维护了一个Object类型的可变数组
不允许重复
Set
无序
HashSet:底层是HashMap,维护了一个哈希表(数组+链表+红黑树)
排序
TreeSet
存取顺序一致
LinkedHashSet:底层是数组+双向链表
一组键值对
键无序
HashMap:底层是哈希表(数组+链表+红黑树)
键排序
TreeMap
键存取顺序一致
LinkedHashMap
读取文件
Properties
Collections工具类
排序操作
均为static方法
- reserve(List):反转List中元素的排序
- shuffle(List):对List集合元素进行随机排序
- sort(List):对List中元素进行自然排序(升序)
- sort(List,Comparator):根据指定的Comparator排序对List集合元素进行排序
- swap:(List,int i,int j):将指定List集合中的i处元素和j处元素进行交换。
查找、替换
- Object max(Collection):根据元素的自然排序,返回给定集合中的最大元素(最后)
- Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
- Object min(Collection)
- Object min(Collection)
- int frequency(Collection,Object):返回指定集合中指定元素的出现次数
- void copy(List dest,List src):将src中的内容赋值到dest中
- 这个List分为容量大小,和数据大小。这里对比的是数据大小,如果新建一个List dest,只能设置容量大小,数据大小是为0的。
只有dest的数据数量比src数据数量大,才能进行copy。所以要保证dest有足够多的占位元素。
- 这个List分为容量大小,和数据大小。这里对比的是数据大小,如果新建一个List dest,只能设置容量大小,数据大小是为0的。
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List对象的所有旧值
集合作业
把HashMap里的value全部增加100
- 使用Entry遍历,直接使用entry.setValue方法
- 使用keySet,用Map实例的put方法去替换value。map.put(key,value+100)

浙公网安备 33010602011771号