回顾总结13

集合

数组的不足之处

  1. 长度开始时必须指定,而且一旦指定,不能更改
  2. 保存的必须为同一类型的元素
  3. 使用数组进行增加、删除元素的示意代码

集合的优点

  1. 可以动态保存任意多个对象,使用比较方便
  2. 提供了一系列方便的操作对象的方法:add、remove、set、get
  3. 使用集合添加、删除新元素的示意代码

Collection

继承Iterable

单列集合

Iterator:迭代器

  1. 遍历Collection集合中的元素
  2. 所有实现了Collection接口的集合类都有一个iterator方法,用以返回一个实现了Iterator接口的对象,返回一个迭代器
  3. Iterator仅用于遍历集合,Iterator本身并不存放对象

常用方法

  1. add:添加单个元素
  2. remove:删除指定元素(可以通过下标删除;还可以直接删除对象,返回一个布尔值,是否删除成功
  3. contains:查找元素是否存在
  4. size:获取元素个数
  5. isEmpty:判断是否为空
  6. clear:清空
  7. addAll:添加多个元素
  8. containsAll:查找多个元素是否都存在
  9. removeAll:删除多个元素
  10. iterator:遍历集合(iterator方法返回的是一个新对象itertor,所以如果要遍历的话,不能简写成list.iterator().next()去输出,每一次调用的时候都会走一遍iterator方法生成一个新的iterator对象,重置指针,永远输出第一个数据。
    应该使用list.iterator()方法返回一个lterator对象,并且接收它,每次用它来调用.next()来遍历集合。
    使用while循环遍历,每次使用next()方法时,都要用hasNext()判断是否有下一条数据,否则最后一条会爆异常NoSuchElementException
    • 增强for循环的底层调用的就是迭代器iterator

List

继承Collection

特点
  1. List集合类中元素有序(添加顺序和取出顺序一致)
  2. List集合类中元素可重复
  3. List集合类中每个元素有其对应的顺序索引(有序就有索引,位置不会变动),支持索引
  4. List集合中的元素都对应一个整数型的序号记载其在容器中的位置,根据序号存取容器中的元素(有序就有索引,有索引就能取元素)
常用方法
  1. void add(int index ,Object ele):在index位置插入ele元素
  2. boolean addAll(int index ,Collection eles):在index位置插入集合eles中的所有元素
  3. Object get(int index):获取index位置的元素
  4. int indexOf(Object obj):返回obj在集合中首次出现的位置
  5. int lastIndexOf(Object obj):返回obj在集合中末次出现的位置
  6. Object remove(int index):移除指定index位置的元素,并返回此元素
  7. Object set(int index ,Object ele):设置指定index位置的元素为ele,相当于替换
  8. List subList(int fromIndex , int toIndex):返回从fronIndex到toIndex位置的子集合

ArrayList

线程不安全的

  1. ArrayList存放数据是通过一个Object类型的数组elementData,因为是Object类型的,通过向下转型,可以存放所有类型的对象。
    transient Object[] elementData;

    transient的意思是短暂的,表示该属性不会被序列化

  2. ArrayList有两个构造器,一个是无参,初始容量为0,第一次增加元素时,扩容到10,然后1.5倍依次增加。一个是自定义初始容量,之后按1.5倍增加。

创建ArrayList流程

  1. 未指定容量,进入无参构造,创建一个空的elementData数组
  2. 增加元素,先判断有没有下一个空的容量,容量值为0的话,设置一个最小容量10,如果不为0的话,增加容量为原有的1.5倍,然后用copyOf进行数据的转移

Vector

线程安全的

  1. 存放数据也是一个对象数组,protected Object[] elementData
  2. Vector是线程同步的,线程安全,Vector类的操作方法带有synchronized修饰符
  3. 构造器同ArrayList,无参初始为10,然后2倍依次增加;自定义容量扩容时,2倍依次增加。

LinkedList

线程不安全的

底层是双向链表

每个Node节点含有三个属性,next:指向下一个节点;item:存放数据;prev:存放指向此节点的上一个节点信息

创建流程

未指定容量,无参构造,是空的,没有东西。当增加元素时,进入linkLast方法,创建节点,分配prev、item、next数据和first、last指针。LinkedList的大小用size表示,没有容量为空的说法,每次新增节点,然后增加size。

Set

特点:

  1. 无序(存储位置和添加顺序不一致)且没有索引
  2. 不允许重复元素,所以最多包含一个null
  3. 因为没有索引,所以遍历的时候不能用普通for循环遍历了,可以使用增强for循环和迭代器

TreeSet

里面有一个comparator的匿名对象,实现comparable接口的compareTo方法。来进行key值的对比,如果判定一样,key值不变,value值更新。

TreeSet增加元素时,其元素需要保证实现comparable接口才能加入进去。String类型已经实现comparator接口。

HashSet

底层是HashMap$Node

它存储是通过(数组+链表+红黑树)

new HashSet的过程就是new HashMap,里面什么也没做。

添加元素的时候,会发生很多操作。

  1. add调用map.put方法,参数为(K,V)

  2. 接着调用putVal方法,这个方法会调用hash(key)方法返回key的hashCode的值经过算法得到的table序号,算法是(h = key.hashCode()) ^ (h >>> 16)

  3. 跳回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)

特点

  1. Map和Collection并列存在,用于保存具有映射关系的数据:Key--Value
  2. Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
  3. Map中的key不允许重复
  4. Map中的value可以重复
  5. Map的key可以为null,value也可以为null,key为null也只能有一个,value为空可以有多个
  6. 常用String类作为Map的key
  7. 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实例,

  1. Entry是一个接口,里面有两个成员K,V
  2. Node是实现类,实现了Entry。
    K和V是存储在Node里面的,但是Entry可以引用,这是多态的性质,父类引用指向子类实例。

常用方法

  1. put:添加
  2. remove:根据键key删除映射关系
  3. get:根据键获取值
  4. size:获取元素个数
  5. isEmpty:判断个数是否为0
  6. clear:清除
  7. containsKey:查找键是否存在

6大遍历方式

  1. 第一种

    先取出所有的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));
}
  1. 第二种

    把所有的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);
    }
    
  2. 第三种

    通过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

特点

  1. 存放的是键值对K-V
  2. hashtable的键和值不能为null,会抛出NullPointerException
  3. hashtable使用方法和HashMap一样
  4. 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方法

  1. reserve(List):反转List中元素的排序
  2. shuffle(List):对List集合元素进行随机排序
  3. sort(List):对List中元素进行自然排序(升序)
  4. sort(List,Comparator):根据指定的Comparator排序对List集合元素进行排序
  5. swap:(List,int i,int j):将指定List集合中的i处元素和j处元素进行交换。

查找、替换

  1. Object max(Collection):根据元素的自然排序,返回给定集合中的最大元素(最后)
  2. Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
  3. Object min(Collection)
  4. Object min(Collection)
  5. int frequency(Collection,Object):返回指定集合中指定元素的出现次数
  6. void copy(List dest,List src):将src中的内容赋值到dest中
    • 这个List分为容量大小,和数据大小。这里对比的是数据大小,如果新建一个List dest,只能设置容量大小,数据大小是为0的。
      只有dest的数据数量比src数据数量大,才能进行copy。所以要保证dest有足够多的占位元素。
  7. boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List对象的所有旧值

集合作业

把HashMap里的value全部增加100

  1. 使用Entry遍历,直接使用entry.setValue方法
  2. 使用keySet,用Map实例的put方法去替换value。map.put(key,value+100)
posted @ 2021-08-09 00:18  灰线  阅读(42)  评论(0)    收藏  举报