Java集合知识详解

目录

1.什么是集合

1.集合

2.数组存储多个数据方面的缺点:即集合存储的优势

3.集合的选用方法

2.集合框架的两大接口

3.Collection之List接口

 1.ArrayList

2.LinkedList

3.Vector

4.ArrayList和LinkedList对比

5.ArrayList的源码

4.Collection之Set接口

1.HashSet  

2.LinkedHashSet

3.TreeSet

4.如何理解Set的无序、不可重复特性(以HashSet为例)

5.TreeSet的比较实现

 6.HashSet 、LinkedHashSet、TreeSet的异同

5.Map

1.HashMap

1.原理

        解决哈希冲突的方法:

        HashMap添加键值对的原理:

        HashMap扩容问题:

2.HashMap和HashSet对比

3.HashMap和Hashtable对比

4.HashMap和TreeMap对比

5.HashMap多线程下存在的问题

1)环形链表问题

2)数据覆盖问题

 6.HashMap的遍历方式

2.LinkedHashMap

3.TreeMap

4.Hashtable

5.Properties

6.ConcorrentHashMap

底层结构


1.什么是集合

1.集合

        Java集合,是对多个数据进行存储的结构,简称java容器

2.数组存储多个数据方面的缺点:即集合存储的优势

      1).初始化后,其长度无法修改;集合可以动态扩容

      2).数组中提供的方法极其有限,对于增删改查操作不方便;集合提供了多种操作方法

      3).数组是不支持泛型的,集合支持泛型;

      4).数组对于无序、不可重复的需求,不能满足;集合中的Set接口就能够满足这一点

3.集合的选用方法

1)只存放元素值:使用Collection接口实现

        保证元素唯一:选择Set接口下的TreeSet或者HashSet

        不保证元素唯一:先择List接口下的ArrayList或LinkedList

2)存放键值对:使用Map接口实现

        需要排序:使用TreeMap

        不需要排序:使用HashMap

2.集合框架的两大接口

1. Collection接口:单列集合,存储一个一个的对象

        List接口:存储有序的、可重复的数据;主要实现类:ArrayList,LinkedList,Vector

        Set接口:存储无序的、不可重复的数据;主要实现类:HashSet,LinkedHashSet,TreeSet

2.Map接口:双列集合,存储一对(key-value)的数据

        主要实现类:HashMap,LinkedHashMap,TreeMap,Hashtable,Properties

3.Collection之List接口

 1.ArrayList

底层实现:底层使用的是Object[ ]数组

是否可以添加null:可以添加null(慎用,可能报NullPointerException:空指针异常)

是否线程安全:线程不安全

继承与实现:继承了AbstarctList,实现了List、RandomAccess、Cloneable、Serializable

        RandomAccess:表示ArrayList支持随机访问,根据元素索引就能获取元素

        Cloneable:能够进行浅拷贝与深拷贝

        Serializable:能够实现序列化与反序列化

public class ArrayList<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
}

ArrayList扩容机制

        使用无参数构造器创建ArrayList对象时,初始化为一个空数组,当开始使用add()方法后,数组容量赋值为10;当数组已满继续添加元素时,调用grow()方法进行扩容,grow方法中将新的数组容量变为原来的1.5倍,并将原来数组的数据复制到新数组中

2.LinkedList

底层实现:底层是双向链表

是否线程安全:线程不安全

3.Vector

底层实现:底层使用的是Object[ ]数组

是否线程安全:线程安全

4.ArrayList和LinkedList对比

底层结构:

        ArrayList:底层是Object[]数组

        LinkedList:底层是双向链表

是否线程安全:

        都是线程不安全

是否支持随机访问:

        ArrayList:继承了RandomAccess,支持随机访问;LinkedList:不支持

适用场景:   

        ArrayList:适合查找元素,不适合插入、删除操作

                插入和删除的时间复杂度:

                        头部插入/删除、指定位置插入/删除:时间复杂度O(n)

                        尾部插入/删除:时间复杂度O(1)

        LinkedList:对于频繁的插入、删除操作,效率比ArrayList高

                插入和删除的时间复杂度:

                        头部插入/删除、尾部插入/删除:时间复杂度O(1)

                        指定位置插入/删除:时间复杂度O(n)

实用性:一般使用LinkedList的场景都可以用ArrayList代替,性能会更好,所以LinkedList用的很少

4.Collection之Set接口

1.HashSet  

        set接口的主要实现类;是线程不安全的;可以存储null值;

2.LinkedHashSet

        作为HashSet的子类,遍历内部数据时,可以按照添加的顺序遍历

3.TreeSet

        可以按照添加的对象指定属性,进行排序

4.如何理解Set的无序、不可重复特性(以HashSet为例)

        无序性:不等于随机性;存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定,添加时是无序的

      不可重复性:保证添加的元素按照equals()判断时,不能返回true;即相同的元素只能添加一个。

5.TreeSet的比较实现

        1.向TreeSet中添加的数据,要求是相同类的对象,不能添加不同类的对象。

        2.两种排序方式:Comparable接口、Comparator接口

        3.自然排序中,比较两个对象是否相同的标准为compareTo()方法返回0;不再是equals()方法

        4.定制排序中,比较两个对象是否相同的标准是compare()返回0,不再是equals()方法
代码示例

    //Comparable 自然排序
public class Person implements Comparable {
    @Override
    public int compareTo(Object o) {
        if (o instanceof Person){
            Person oo = (Person)o;
            return this.age - (oo.getAge());
        }else {
            throw new RuntimeException("输入的类型不一致");
        }
    }
}
    //comparator:定制排序
     Set set3 = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Person && o2 instanceof Person){
                    Person oo1 = (Person)o1;
                    Person oo2 = (Person)o2;
                    return oo1.getName().compareTo(oo2.getName());
                }else{
                    throw new RuntimeException("输入的类型不一致。");
                }
            }
        });

 6.HashSet 、LinkedHashSet、TreeSet的异同

相同点:都实现了set接口;都是线程不安全的

不同点:

        底层结构:

                HashSet:底层是哈希表

                LinkedHashSet:链表+哈希表

                TreeSet:红黑树

        功能:

                HashSet:底层能够存取null值

                LinkedHashSet:能够保证元素按照添加的顺序遍历,且元素的添加与取出满足FIFO

                TreeSet:能够实现指定规则排序

5.Map

1.HashMap

1.原理

        线程是否安全:线程不安全,效率高;可以存储null的key和value。

        底层:jdk7之前:数组+链表

                   jdk8:数组+链表+红黑树

        解决哈希冲突的方法:

        jdk1.8之后,HashMap解决哈希冲突时,需要满足两个条件才将链表转为红黑树:链表长度大于阈值(默认为8);数组长度大于64(若小于64,则先进行扩容而不是转为红黑树)

        HashMap添加键值对的原理:

HashMap被实例化后,底层创建长度为16的一维数组Entry[ ] table。

        调用put(key1,value1)后,会先调用key1所在类的hashCode()方法计算key1的哈希值,此哈希值经过计算后得到Entry数组在底层的存放位置:

                若此位置为空,则key1-value1添加成功

                若此位置不为空,则比较key1和该位置元素(假设为key2-value2)的哈希值:

                        若key1的哈希值和该元素key2哈希值不相同,则key1-value1添加成功

                        若key1的哈希值和该元素key2哈希值相同,则比较key1所在类的equals(key2)方法

                                若equals()返回false,则key1-value1添加成功

                                若equals返回true,则value1将value2进行替换

        HashMap扩容问题:

         HashMap默认初始化大小为16,每次扩容容量转为原来的2倍;若是创建时指定初始容量,则会扩充为2的幂次方;

        2的幂次方的由来:

        Hash值是一个很大的值,大概有40亿的映射空间;但这个值不内存中存放不下,因此需要进行一定的运算才能得到对应的数组下标,计算方法是  hash & (n-1)(n代表数组长度);而这个方法得到的结果,和对2的幂次方取余是一样的,只是和 “&” 相比, “%”效率更高

2.HashMap和HashSet对比

存储对象:

        HashMap存储的为键值对,是双列集合;是因为HashMap实现的是Map接口

        HashSet存储的为单列集合;是因为HashSet实现的是Collection接口下的Set接口

哈希值计算:

        HashMap基于键计算哈希值

        HashSet基于存储对象计算哈希值

3.HashMap和Hashtable对比

底层结构:

        HashMap底层是数组+链表+红黑树;

        Hashtable底层是数组+链表;

是否线程安全:

        HashMap线程不安全,Hashtable是线程安全的;

        因此HashMap的效率高于Hashtable

是否能存Null值:

        HashMap可以存储为null的键与值,但是为null的键只能有一个,为null的value可以有多个;        Hashtable不能存储为null的键和值

扩容机制:

        HashMap默认初始化大小为16,每次扩容容量转为原来的2倍;

        Hashtable默认初始化大小为11,每次扩容转为原来的2n+1倍;

4.HashMap和TreeMap对比

底层结构:

        HashMap底层是数组+链表+红黑树;

        TreeMap底层是红黑树

实现接口:

        HashMap和TreeMap都继承了AbstractMap;

        TreeMap比HashMap多实现了一个NavigableMap,而NavigableMap又继承了SortedMap;因此TreeMap能够对集合元素根据key排序(默认按照升序排列)

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
}


public class TreeMap<K,V> extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable{
}

5.HashMap多线程下存在的问题

1)环形链表问题

jdk1.7:若产生哈希冲突,对比equals()方法不同后,将新元素存入数组中,旧元素作为链表存在,新元素指向旧元素,这就是头插法;若在多线程情况下,若多个线程同时put()出现哈希冲突,很有可能造成链表的环形链表情况,即多线程下:由于使用头插法存入元素,元素A与元素B相互指向

jdk1.8:此时采用尾插法,插入的元素都放在链表末尾,指向前一个元素,避免了环形链表问题

建议:在多线程环境下,使用ConcurrentHashMap

2)数据覆盖问题

在多线程环境下,若线程A和线程B同时put(),并且发生了哈希冲突,线程A执行哈希冲突判断和可能会被挂起,线程B此时完成插入操作,随后线程A继续执行,但A已经进行了哈希判断,所以直接插入,此时A的数据会覆盖B数据

 6.HashMap的遍历方式

        1.Iterator迭代器遍历:分为EntrySet 和 KeySet方式

        2.For Each遍历:分为EntrySet 和 KeySet方式

        3.Lambda表达式遍历

        4.Stream API遍历

一般采用EntrySet遍历

详细可以参考:

HashMap 的 7 种遍历方式与性能分析!「修正篇」 (qq.com)

2.LinkedHashMap

        保证在遍历map元素时,可以按照添加的顺序实现遍历。

        原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。

                   对于频繁的遍历操作,效率高于HashMap

3.TreeMap

        可以按照添加的key- value进行排序,实现排序遍历。此时考虑key的自然排序或定制排序。底层使用红黑树。

4.Hashtable

        作为古老的实现类;线程安全的,效率低;不能存储null的key和value

5.Properties

        常用来处理配置文件;key和value都是String类型

6.ConcorrentHashMap

底层结构

        jdk1.7以前:Segment数组加链表,每个Segment数组结构有一个HashEntry数组,每一个HashEntry数组都可以构成链表结构;与此同时,对Segment数组进行分段加锁,在多线程情况下可以访问不同的Segment分段数组,从而实现线程安全

        jdk1.8:使用Node数组+链表+红黑树,不再采用Segment分段锁,而是synchronized锁定链表或红黑树的首节点,从而实现线程安全。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java入门基础知识是学习和理解Java编程语言的基础概念和语法规则。下面是一些常见的基础知识点: 1. Java环境安装:首先需要安装Java开发工具包(JDK),它包含了Java编译器和运行时环境。 2. Java语言特点:Java是一种面向对象的编程语言,具有简单、可移植、面向对象、安全、高性能等特点。 3. Java程序结构:一个Java程序由一个或多个类组成,每个类包含方法和属性。Java程序从main()方法开始执行。 4. 数据类型:Java提供了基本数据类型(如整数、浮点数、字符、布尔等)和引用数据类型(如类、数组、接口等)。 5. 变量和常量:变量是用于存储数据的内存位置,常量是固定不变的值。在Java中,使用关键字来声明变量和常量。 6. 运算符:Java提供了各种运算符,例如算术运算符、赋值运算符、比较运算符、逻辑运算符等。 7. 控制流程:Java提供了条件语句(如if-else、switch-case)、循环语句(如for、while、do-while)和跳转语句(如break、continue)来控制程序的执行流程。 8. 数组:数组是一种存储相同类型数据的集合,可以通过索引访问数组中的元素。 9. 方法:方法是一段可重用的代码块,用于执行特定的任务。Java中可以定义自己的方法,也可以使用已经存在的方法。 10. 异常处理:Java提供了异常处理机制来处理程序运行过程中发生的异常情况,可以使用try-catch语句块来捕获和处理异常。 以上是Java入门基础知识的一些主要内容,希望对你有所帮助。如果有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值