代码编织梦想

1.集合分为两组:单列集合(单个的对象)、双列集合(以键值对的方式存在)
2.Collection接口有两个重要的子接口List、Set,他们的实现子类都是单列集合
    1)有些可以存放重复的元素,有些不可以存放
    2)List有序,Set无序
    3)通过子接口Set和List实现的
3.Map接口的实现子类是双列集合,存放的K-V
4.List集合的特点:
    1.添加和取出的顺序一致且可以重复
    2.List集合每个元素都有其对应顺序索引,支持索引取出
5.ArrayList底层源码分析
    1.ArrayList中维护了一个Object类型的数组elementData
    2.当创建ArrayList对象时,如果使用的是无参构造,
    则初始elementData容量为0
        第一次添加,则扩容elementData为10,
        如果需要再次扩容,则扩容elementData为1.5倍
    3.如果使用指定大小的构造器,则初始化elementData容量为指定大小,
    如果需要扩容,则直接扩容elementData为1.5倍
6.Vector的基本介绍
    1.Vector底层也是一个对象数组
    2.Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized
        安全且效率不高
7.LinkedList的全面说明
    1.LinkedList底层实现了双向链表和双端队列的特点
    2.LinkedList中维护了两个属性first和last分别指向首节点和尾节点
    3.每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过pre指向前一个,通过next指向后一个节点。最终实现双向链表
    4.LinkedList的元素的添加和删除功能不是通过数组完成的,相对来说效率较高
8.    ArrayList和LinkedList(都是线程不安全的)
    1.如果我们改查的操作多,选择ArrayList
    2.如果我们增删的操作多,选择LinkedList
    3.在程序中,大部分都是查询,因此大部分情况下会选择ArrayList
9.set接口的基本介绍
    1.无序(添加和取出的顺序不一致)且取出的顺序是固定的,没有索引
    2.不允许重复元素,最多包含一个null
    3.JDK API中set的接口实现类:AbstractSet,
    ConcurrentSkipListSet, 
    CopyOnWriteArraySet, EnumSet, HashSet, 
    JobStateReasons, LinkedHashSet, TreeSet
    4.set的接口遍历方式:迭代器、增强for,不能使用索引的方式来获取
10.HashSet的特点
    1.HashSet实现了Set接口
    2.HashSet实际上是HashMap,HashMap的底层是:数组+链表+红黑树
    3.HashSet可以存放null,但是只能有一个null,即元素不能重复
    4.HashSet不保证存放元素的顺序和取出顺序一致
    5.不能有重复的元素/对象
    6.经典面试题
        set.add(new String("kk"));//ok
        set.add(new String("kk"));//加入不了
    7.HashSet的底层原理
        1.HashSet底层是HashMap
        2.添加一个元素时,先得到hash值会转成->索引值
        3.找到存储数据表table,看到这个索引位置是否已经有元素存放
        4.如果没有,直接加入
        5.如果有,调用equals比较,如果相同,就放弃添加,如果不同则添加到最后
        6.在Java8中,如果有一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8)
            并且table的大小>=MIN_TREEIFY_CAPACITY(默认64)就会进树化(红黑树)
11.对HashSet的源码解读
    1.执行HashSet()
     public HashSet() {
        map = new HashMap<>();
    }
    2.执行add()
     public boolean add(E e) {
        return map.put(e, PRESENT)==null;//PRESENT起到占位的目的,
    }
    3.执行put(),该方法会执行hash(key)得到key对应的hash值,与hash算法得到的值有区别
    public V put(K key, V value) {//value=PRESENT起到占位的目的,
        return putVal(hash(key), key, value, false, true);
    }
    4.执行
     final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;//定义了辅助性的变量
        //table就是HashMap的一个数组,类型是Node[]
        //if语句表示如果当前table是null,或者 大小=0,就进行一次扩容,到16
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        //(1)根据key得到的hash去计算key应该存放到table表的哪个索引位置
        //并把这个位置的对象赋给P
        //(2)判断P是否为null
        //(2.1)如果p为null,就表示没有存放元素,就创建一个Node
        //(2.2)就放在该位置tab[i]=newNode(hash, key, value, null)
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            //如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样
            //并且满足 下面条件之一:
            //(1)准备加入的key和P指向的Node节点的key是同一个对象
            //(2)P指向的Node节点的key的equals()和准备加入的key比较后相同
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }
12.HashSet底层扩容机制和树化
    1.HashSet底层是HashMap,第一次添加时table数组扩容到16,临界值
        (threshold)16*加载因子 16*0.75=12
    2.如果table数组使用到了临界值12,就会扩容到16*2=32,新的临界值
        就是32*0.75=24,依次类推
    3.在Java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认值8),
        并且table的大小>=MIN_TREEIFY_CAPACITY(默认64)就会进树化(红黑树),
        否则任然采用数组扩容机制
13.LinkedHashSet说明
    1.在LinkedHashSet底层是一个LinkedHashMap维护了一个数组和双向链表
    2.每个节点都有before和after属性,这样可以形成双向链表
    3.在添加元素时先求,hash值。在求索引,确定该元素在table位置,如果已经存在不添加
    4.同时确保插入顺序和遍历顺序的一致性,且元素不能重复
    
    
14.Map,接口实现类的特点,使用实现类HashMap
    1.Map和Collection并列存在,用于保存具有映射关系的数据Key-Value(双列元素)
    2.Map中的Key和Value可以是任何引用类型的数据,会封装到HashMap$Node对象中
    3.Map中的key不允许重复,当有相同的K,就等价于替换
    4.Map中的value是可以重复的
    5.Map中的Key和Value都可以为空,Key为空只能有一个Value为空可以有多个
    6.常用String作为Key,其他类型也可以
15.HashMap特点
    1.K-V最后存放在是HashMap$Node node=newNode(hash,key,value,null)
    2.K-V为了方便程序员的遍历,还会创建EntrySet集合,该集合存放元素的类型
        Entry,而一个Entry对象就有k,v
    3.entrySet中,定义的类型是Map.Entry,但是实际上存放的还是HashMap$Node
        因为Node实现了Map.Entry
    4.当把HashMap$Node对象存放到entrySet就方便遍历,entrySet提供
    了两个重要的方法,getKey();getValue
16.Map接口的常用方法
    remove:根据键删除映射关系
    get:根据键获取值
    size:获取元素个数
    isEmpty:判断个数是否为 0
    clear:清除 k-v
    containsKey:查找键是否存在
17.map遍历的六大方式
    public class MapFor {
        public static void main(String[] args) {
            Map map = new HashMap();
            map.put("刘令博", null);//OK
            map.put(null, "刘亦菲");//OK
            map.put("鹿晗", "关晓彤");//OK
            //第一组:通过key取出value值
            Set set = map.keySet();
            //        (1)增强for
            for (Object key : set) {
                System.out.println(key+"=="+map.get(key));
            }
            //(2)迭代器
            Iterator iterator = set.iterator();
            while (iterator.hasNext()){
                Object next = iterator.next();
                System.out.println(next+"--"+map.get(next));
            }
            //第二组把所有的value取出来
            Collection values = map.values();
            //        (1)增强for
            for (Object value : values) {
                System.out.println(value);
            }

            //        (2)迭代器
            Iterator iterator1 = values.iterator();
            while (iterator1.hasNext()){
                System.out.println(iterator1.next());
            }
            //第三组 :通过EntrySet  
            Set entrySet = map.entrySet();
            //1.增强for
            for (Object entry : entrySet) {
                Map.Entry m=(Map.Entry)entry;
                System.out.println(m.getKey()+"**"+m.getValue());
            }
            //2.迭代器
            Iterator iterator2 = entrySet.iterator();
            while(iterator2.hasNext()){
                Object next = iterator2.next();
                Map.Entry m=(Map.Entry)next;
                System.out.println(m.getKey()+"&"+m.getValue());
            }
        }
    }
18.HashMap小结
    1.Map接口的常用实现类:HashMap、Hashtable和properties
    2.HashMap经常使用
    3.HashMap以键值对的方式存取
    4.HashMap中的key不允许重复,当有相同的K,就等价于替换
    5.HashMap与HashSet一样,不保证映射顺序,因为底层是以hash表
    的方式存储的
    6.HashMap没有实现线程同步机制,因此线程不安全,方法没有做到同步互斥
19.HashMap底层机制及源码剖析
    1.HashMap底层维护了Node类型的数组table,默认为null
    2.当创建对象时,将加载因子初始化为0.75
    3.当添加k-v,如果k重复直接替换之前value的值;如果不相等判断是连败哦还是树
    做出相应的处理
    4.第一次添加,table的容量为16,临界值为12
    5.再次扩容时table的值是原来的2倍,临界值为原来的两倍
    6.在Java8中,一条链表的元素超过8个并且table的大小>=64,会进行树化
20.HashTable的基本介绍
    1.存放的元素是键值对
    2.hashtable的键和值都不能为空,否则会抛出异常,key相同时还是会替换
    3.hashTable使用方法基本上和HashMap一样
    4.hashTable是线程安全的(synchronized),hashMap是线程不安全的
21.HashTable的底层
    1.底层有数组Hashtable$Entry[]初始化大小11
    2.临界值threshold 8=11*0.75
    3.扩容:是原来大小的两倍+1
22.集合选型规则
    1.判断存储的类型(单例、双列)
    2.一组对象[单列]Collection接口
        允许重复:List
                增删多:LinkedList(底层维护了一个双向链表)
                改查多:ArrayList(底层维护了Object类型的可变数组)
        不允许重复:Set
            无序:HashSet(底层是HashMap,维护了一个哈希表(数组+链表+红黑树))
            有序:TreeSet
            插入和取出一致:LinkedHashSet,维护数组+双向链表
    3.一组键值对:Map
        键无序:HashMap(底层:哈希表jdk 7:数组+链表,jdk8:数组+链表+红黑树)
        键排序:TreeMap
        键的插入和取出顺序一致:LinkedHashMap
        读取文件:properties
23.TreeSet底层
    /*
        * 1.构造器把传入的底层对象,给到底层的TreeMap
        * 2.在底层加入 treeSet.add("b");
        *if (cpr != null) {//crp就是匿名内部类对象
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);动态绑定compare
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else//如果相等这个数据加入不了
                    return t.setValue(value);
            } while (t != null);
        }
        *
        * */
        //比较的是字符串的长度,如果长度相同则加入失败
        ((String)o1).length()-((String)o2).length()
24.TreeSet源码解读
    public class TreeMap_ {
    public static void main(String[] args) {
        //默认无序指的是元素取出和添加的顺序不一致
        /*TreeMap treeMap = new TreeMap();*/
        TreeMap treeMap = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length()-((String)o2).length();
            }
        });

        treeMap.put("ea","ds");
        treeMap.put("asd","da");
        treeMap.put("bfff","db");
        treeMap.put("cregg","dc");
        treeMap.put("egrgre","de");
        treeMap.put("ww","ds");//不是替换,直接加入不了

        /*
        * 解读源码:
        * 1.执行构造器 把传入的实现了 Comparator的匿名内部类(对象)传给了TreeMap的comparator
        * public TreeMap(Comparator<? super K> comparator) {
            this.comparator = comparator;
            }

           2.调用put方法
           2.1第一次添加
           *  Entry<K,V> t = root;
            if (t == null) {
                compare(key, key); // type (and possibly null) check    检测是否为空

                root = new Entry<>(key, value, null);
                size = 1;
                modCount++;
                return null;
            }
            2.2以后添加启用比较器
            * //决定具体的位置
            * if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }

         */
        System.out.println(treeMap);
    }
}
25.Collections工具类
    1.Collections是一个操作Set、List、Map等集合的工具类
    2.Collections中提供了一系列静态方法对集合元素进行排序查询
    3.排序常用的方法
    reverse(List):反转 List 中元素的顺
    shuffle(List):对 List 集合元素进行随机排序
    sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
    swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
    4.查找替换常用的方法
    /*1) Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
        2) Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
        3)Object min(Collection)
                4)Object min(Collection,Comparator)
        5)int frequency(Collection,Object):返回指定集合中指定元素的出现次数
        6)void copy(List destList src):将src中的内容复制到dest中
        7)boolean replaceAll(List list,Object oldValObject newVal)使用新值 替换 List 对象的所有旧值*/

    
    
    
    
    
    
    
    

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_57219176/article/details/129827037

JAVA集合知识点总结-爱代码爱编程

前言:有老师总结真好,照着老师的打一遍理解下,以后能在看。 概念: 集合概念: 保存和盛装数据的容器,将许多元素组合成一个单一单元的容器对象。集合框架: 表示和操作集合的体系,包括接口、实现类,集合框架的结构图。接口:Iterable、Iterator、Collection、List、Queue、Set、Map;类:Ar

java集合(重要知识点汇总)超详细_小柴耶的博客-爱代码爱编程

目录 1.1.1集合的引出 1.1.2数组的disadvantage 1.1.3集合的advantage 1.2.1集合的框架结构 1.3.1Collection接口和常用方法 1.3.2Collection 接口常用方法,以实现子类 ArrayList 来演示. CollectionMethod.java 1.4.1 Collection

集合知识点总结(java)_java集合知识点总结-爱代码爱编程

● 集合概念 ● 集合 API ● List 接口及实现类 ● List接口集合迭代 ● Set 接口 ● Set 接口集合迭代 ● Map 接口 ● Collections类 1.集合概念 数组(容器):创建一个指定长度的数组,使用数组来存储多

python集合知识点总结_反差集-爱代码爱编程

文章目录 集合(set)一、创建集合1.空集合:set()或{}2.使用花括号内以逗号分隔元素的方式3.使用集合推导式,类似列表推导式4.使用类型构造器:set(基本数据类型) 二、添加1.add