今天我们就来简单了解一下java中的集合。用过的朋友都知道,用过。比如常用的List,还有Set和Map,List和Set都是用来存储单列数据的集合,它们的父接口都是Collection。List的特点是存储的值是有序的,并且允许重复。Set的特点是存储的元素是唯一的、不可重复的、无序的。Map的特点是用来存储一个双列数据的集合。存储的数据乱序,key不能重复,value可以重复。接下来,我们就把它们拆开来详细说说。List接口(通常有些面试官会问这样一个基础问题:List是一个接口还是一个类?你怎么看?有经验的朋友肯定能一下子回答完,但是一些刚开始学习的新手同学可能会有一些犹豫,那我这次就告诉你,小白看到有人问你这样的问题,小白也不会犹豫。)首先我们要明确:我们java中的集合是分为单列Collection的而双列集合,单列集合的顶层接口是:Collection,双列集合的顶层接口是:Map和List是属于单列集合Collection的子接口,而List接口的实现类如下:(所以List是接口不是类,通过下面可以详细了解List接口的实现类):1.ArrayList(List接口的实现类):底层数据结构是数组,查询快,增删改慢,因为众所周知ArrayList的底层数据结构是数组。向ArrayList添加元素时,可能会引起List的扩容,因为ArrayList底层是数组结构,但是数组不支持动态扩容,所以ArrayList的扩容机制是新建数组,迁移旧的数组数据到新的。Array,然后添加新的元素,这样的过程是ArrayList添加元素慢的核心原因。ArrayList删除元素时,底层是删除从索引位置到最后一个索引位置末尾的所有元素,一个一个向前复制一个索引位置,然后将最后一个索引位置元素置为null。简单的说,假设我现在要删除这个集合中0索引位置的元素,我删除0索引位置以上的元素后,我并没有直接将这个位置的元素置为null,而是将集合中的所有元素都置为null1个索引位置到最后一个索引位置都需要经过一个索引位置一个一个向前复制的过程,直到最后一个索引元素被向前复制,将结束位置的空元素复制为null,这样也就是说,在删除一个元素的时候,会影响其他索引位置的元素的位置,所以也会降低删除元素的效率。(ArrayList集合删除元素后在其他索引位置改变元素移动位置的过程)了解了增删慢的原因后,其实大家对查询快的原因也就有了很好的理解。ArrayList底层是在查询元素时访问数组元素。进行查询。数组(Array)是线性表(线性表是一种数据像线一样排列的结构,每个线性表上的数据最多有前后两个方向)数据结构。它使用一组连续的内存空间来存储一组相同类型的数据。并且在声明数组的时候,会在内存中申请一块连续相邻的内存空间。通过索引访问数组元素时,可以直接通过数组地址值和偏移量计算出要查找元素的内存地址,所以数组支持通过索引直接访问元素,效率很高。数组中的元素是带下标的,所以可以根据下标快速找到要查询的元素(使用get()方法可以直接获取数组对应下标中的值)。2、LinkedList(List接口的实现类):底层数据结构是链表,查询慢,增删快。使用get()方法可以直接取数组对应下标中的值,只能遍历总数,然后循环下标取值,所以如果LinkedList链表尺寸较大,则for循环次数会增加增加会导致遍历时间变长,查询变慢(但如果在编码过程中仍然需要考虑使用LinkedList,可以使用getFirst()和getLast()方法来查询时减少for循环次数,提高查询速度)。LinkedList添加元素快的主要原因是LinkedList使用add(Ee)直接添加元素或者add(intindex,Ee)在指定位置添加元素。这两种方法插入元素,效率相对ArrayList要高一些,因为ArrayList在添加元素的时候可能需要扩充和复制元素,增加了开销,而LinkedList只是在指定位置断开链接,增加新的节点,所以系统整个添加过程只做了两件事,添加一个新的节点,然后保存该节点与前一个节点的引用关系。简单的说就是新建一个环节,所以效率高。删除元素时,也会按照remove(Objecto)删除元素或者remove(intindex)删除指定位置元素这两种方法删除元素,所以简单来说,删除效率主要是因为只需要某个链接被删除,然后只链接新元素而不修改列表中剩余的元素。3、Vector(List接口的实现类):底层数据结构是一个数组。只是因为它的底层是数组,所以它的特点和ArrayList一样,查询快,增删慢。关于这一点,可以参考上面ArrayList的解释。Set接口也是单列集合Collection的子接口。接下来我们继续看它的实现类!1、HashSet(Set接口的实现类):底层数据结构为哈希表,基于HashMap实现。底层使用HashMap来存储元素。HashSet是为了提高查询效率,就是查询某个值是否存在时,ArrayList需要遍历获取某个值的位置,而HashSet可以通过HashCode快速定位,HashSet根据哈希算法进行对象访问,而且访问速度非常快。当HashSet中的元素个数超过数组原来的大小时,就会扩容,而哈希表其实主要依赖hashcode()和equals()这两个方法。简单的说,先用hashcode()判断hashcode值是否相同,如果相同则执行equals()检查它们的返回值是否相同,如果返回true,则表示两个元素重复,然后不添加,如果return为false,则直接添加到集合中。如果hashcode值不一样,可以直接加入集合。以上就是对HashSet的特点的简单介绍。2、LinkedHashSet(Set接口的实现类):底层数据结构为链表+哈希表。链表保证了元素的顺序,哈希表保证了元素的唯一性。LinkedHashSet是基于LinkedHashMapList的有序去重集,LinkedHashSet中的元素是不重复的;LinkedHashSet中的元素是有序的,保持相加的顺序;LinkedHashSet可以存储空值;不知道大家在平时的工作中是不是经常用到这个容器。反正我基本没用过,所以只是个人根据他的特点做的简单介绍。3、TreeSet(Set接口的实现类):底层数据结构是一棵红黑树,特点是元素唯一且有序,通过自然排序和比较器排序来保证,根据返回值是否为判断0元素是否唯一。TreeSet是一个有序的Set集合,所以它支持add、remove、get等方法。TreeSet不支持快速随机遍历,只能通过迭代器遍历。如果要在TreeSet中存储自定义类的对象进行排序,必须实现Comparable接口,或者实现一个比较器,在类上实现Comparable,重写compareTo()方法,在方法中定义比较算法,返回正或根据大小关系负数或零。使用TreeSet存储对象时,add()方法会自动调用compareTo()方法进行比较,并根据比较结果以二叉树的形式存储。我只是写了一个排序。你可以粗略的看一下。这是排序的运行结果图。遍历两次是因为使用了两种不同的遍历方式。接下来,该说说双列集合Map了。你可以看看他的实现类有哪些。1、HashMap(Map接口的实现类):底层数据结构为数组+链表,基于哈希表实现Map接口。并允许使用空值和空键,它们以键值存储的形式存在。每个键值对也称为一个条目。数据根据key的hashCode值存储。大多数情况下,可以直接定位到它的值。keykey最多允许一个空记录,可以有多个值为空的记录。HashMap的实现不是同步的,也就是说它不是线程安全的。HashMap由数组+链表+红黑树组成(JDK1.8后,增加了红黑树部分,当链表长度超过阈值(8)时,链表会转为一个红黑树)。对于HashMap,面试官经常会问HashSet和HashMap的区别?其实对于这个问题,大家也可以通过上面HashSet的解释来总结一下。相同点:1.数据通过Hash散列算法分配,2.非线程安全,3.数据查询无Sequential;区别:1.继承的父类不同2.设置单键,而hashmap可以存储键值对3.hashmap可以存储不同的值但hashset不支持同值数据。以上就是对HashMap的特点的简单介绍。如果想看懂源码的解释,可以自行学习。以上只是简单的介绍。2、LinkedHashMap(Map接口的实现类):LinkedHashMap继承了HashMap类。默认情况下,使用entryset得到的集合的顺序与节点的插入顺序是一致的。除了hashmap的逻辑,我们都知道LinkedHashMap还维护了一个双向链表。在创建要插入的Entry时,我们要知道LinkedHashMap中的Entry类继承了HashMap中的Node类,新添加了这个entry。两个指针属性是before和after,分别指向前后插入的节点。同时LinkedHashMap中多了3个参数,head,tail,accessOrder。双向链表默认按照插入的顺序排列。最先插入的节点(也就是最老的节点)为head,最新插入的节点为tail。accessOrder参数表示双向链表的排列顺序是按照节点的插入顺序还是访问顺序。默认为false,即插入顺序,true代表访问顺序。当排列方式为按访问顺序排列时,如果调用get或put方法且key存在,则调用afterNodeAccess方法将最近访问的节点移动到双向队列的尾部。其实我们最需要知道的是LinkedHashMap可以通过底层唯一双向链表的支持来保存元素之间的顺序,比如插入顺序或者访问顺序,而HashMap无法维护这个顺序,因为它没有双向链表的支持,所以它的访问是随机的,和HashMap一样,它仍然是通过数组存储元素。3、TreeMap(Map接口的实现类):是一个有序的key-value集合,主要通过红黑树实现。它最大的特点就是遍历的时候是有顺序的,按照key的排序规则。TreeMap继承了AbstractMap(因为TreeMap继承自AbstractMap,是一个Map,即key-value集合),实现了三个接口:NavigableMap、Cloneable、Serializable。其中,AbstractMap表示TreeMap是一个支持key-value集合的Map,NavigableMap表示支持一系列的导航方式(比如返回一个有序的key集合),有一个导航方式返回最接近的匹配项为给定的搜索目标。.又因为它是基于红黑树的,所以包含了几个重要的成员变量:root(root是红黑数的根节点)、size(红黑数中的节点数)、comparator(comparator,red对黑色数排序时,按照Entry中的key排序)。当然在面试的过程中,面试官可能会问你这样的问题,比如:TreeMap和HashMap有什么区别?基于这个问题,我们可以给大家做一个简单的总结。相同点:都是线程不安全的;增、删、改、查操作;插入节点时,key重复后旧值会被覆盖。区别:底层数据结构不同。HashMap是基于数组+链表+红黑树的数据结构,TreeMap是基于红黑树的数据结构;HashMap是无序的,TreeMap是有序的;HashMap允许存储null,TreeMap的key不允许存储null,但value可以为null;TreeMap要求key必须实现Comparable接口,或者在初始化时传入Comparator比较器。好了,以上就是小编为大家简单总结的java合集,希望对大家有所帮助!主要图片向您展示了具体的java集合。可以作为继续学习的参考!
