常用类库-集合

一. 类集概述

  1. 集合与数组的区别,缓存的管理,Collection 、List 、Set 接口的作用及相关的子类。

  2. 类集设置的目的

   普通的对象数组的最大问题在于数组中的元素个数是固定的,不能动态的扩充大小,所以最早的时候可以通过链表实现一个动态对象数组。

   但是这样做毕竟太复杂了,所以在 Java 中为了方便用户操作各个数据结构,所以引入了类集的概念,有时候就可以把类集称为 java 对数据结构的实现。

   类集中最大的几个操作接口:Collection(单值存储集合的最大接口,专门存储单个数据,例如数组,每个下标对应一个值)、

               Map(双值存储的最大接口,例如一个钥匙和一个锁)、

               Iterator(迭代器,对于所有集合进行迭代获取数据)

   这三个接口为以后要使用的最重点的接口。

   所有的类集操作的接口或类都在 java.util 包中。

二. 常见数据结构

  1. 栈

   栈:stack,又称堆栈, 栈(stack)是限定仅在表尾进行插入和删除操作的线性表。我们把允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。栈又称为先进后出的线性表 。

   特点:

  (1)先进后出

  (2)栈的入口、出口的都是栈的顶端位置。

  2. 队列

   队列:queue,简称队, 队列是一种特殊的线性表,是运算受到限制的一种线性表,只允许在表的一端进行插入,而在另一端进行删除元素的线性表。队尾(rear)是允许插入的一端。队头(front)是允许删除的一端。空队列是不含元素的空表。

   特点:

  (1)先进先出;

  (2)队列的入口、出口各占一侧。

  3. 数组

   数组:Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就像是一排出租屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到租房子的人。

   特点:

  (1)查找元素快:通过索引,可以快速访问指定位置的元素。

  (2)增删元素慢:指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。

            指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中。

  4. 链表

   链表:linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时i动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。我们常说的链表结构有单向链表与双向链表。

   特点:

  (1)查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素。

  (2)增删元素快:只需要修改连接下个元素的地址即可。

  5. 二叉树

   二叉树:binary tree ,是每个结点不超过2的有序树(tree) 。

   特点:查找元素快。

三. 链表和二叉树

  1. 什么是链表?

   链表 [Linked List]:链表是由一组不必相连(不必相连:可以连续也可以不连续)的内存结构(节点),按特定的顺序链接在一起的抽象数据类型。

   补充:

   抽象数据类型(Abstract Data Type [ADT]):表示数学中抽象出来的一些操作的集合。

   内存结构:内存中的结构,如:struct、特殊内存块...等等之类;

  2. 数组和链表的区别和优缺点:

   数组的优点:
    存取速度快
   数组的缺点:
    事先必须知道数组的长度
    插入删除元素很慢
    空间通常是有限制的
    需要大块连续的内存块
    插入删除元素的效率很低

   链表优点:
    空间没有限制
    插入删除元素很快
   链表缺点:
    存取速度很慢

  3. 链表共分几类?

   链表常用的有 3 类: 单链表、双向链表、循环链表。

   链表的核心操作集有 3 种:插入、删除、查找(遍历)

  4. 二叉树

   二叉树是树的一种,每个节点最多可具有两个子树,即结点的度最大为 2(结点度:结点拥有的子树数)。

   定义:当前根节点的左边全部比根节点小,当前根节点的右边全部比根节点大。

  5. 二叉树的种类

  (1)斜树

    所有结点都只有左子树,或者右子树

    

 

 

 

  (2)满二叉树

    所有的分支节点都具有左右节点

    

 

 

 

  (3)完全二叉树

    若设二叉树的深度为 h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h层所有的结点都连续集中在最左边,这就是完全二叉树。

    

 

 

 

  6. 二叉树的一些性质

  (1)二叉树第 i 层上的结点数目最多为 2^(i-1) (i≥1)

  (2)深度为 h 的二叉树至多有 2^h-1 个结点(h≥1)

  (3)包含 n 个结点的二叉树的高度至少为 log2 (n+1)

  (4)在任意一棵二叉树中,若终端结点的个数为 n0,度为 2 的结点数为 n2,则 n0=n2+1

  7. 二叉树的遍历方式

   二叉树的遍历方式,一般分为先序遍历,中序遍历,后序遍历。

  (1)先序遍历:先访问根节点,然后访问左节点,最后访问右节点(根->左->右)

  (2)中序遍历:先访问左节点,然后访问根节点,最后访问右节点(左->根->右)

  (3)后序遍历:先访问左节点,然后访问右节点,最后访问根节点(左->右->根)

  

 

 

   先序遍历(根-左-右):1-2-4-8-9-5-10-3-6-7

   中序遍历:(左-根-右):8-4-9-2-10-5-1-6-3-7

   后序遍历(左-右-根):8-9-4-10-5-2-6-7-3-1

四. Collection接口

  1. Collection常用功能

   Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法

   方法如下:

   (1)public boolean add(E e) : 把给定的对象添加到当前集合中 。

   (2)public void clear() :清空集合中所有的元素。

   (3)public boolean remove(E e) : 把给定的对象在当前集合中删除。

   (4)public boolean contains(E e) : 判断当前集合中是否包含给定的对象。

   (5)public boolean isEmpty() : 判断当前集合是否为空。

   (6)public int size() : 返回集合中元素的个数。

   (7)public Object[] toArray() : 把集合中的元素,存储到数组中。

五. List接口

  1.概述 

   在整个集合中 List 是 Collection 的子接口,里面的所有内容都是允许重复的。

  2. List接口特点:

   (1)它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。

   (2)它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。

   (3)集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。

  3. List接口中常用方法:

   (1)public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。

   (2)public E get(int index) :返回集合中指定位置的元素。

   (3)public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。

   (4)public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素。

  4. List的子类

   (1)ArrayList集合

     java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以 ArrayList 是最常用的集合。

     许多程序员开发时非常随意地使用ArrayList完成任何需求,并不严谨,这种用法是不提倡的。

      是新的类,是在 JDK 1.2 之后推出的 。性能较高,是采用了异步处理。支持 Iterator、ListIterator 输出。

   (2)Vector

     与 ArrayList 一样,Vector 本身也属于 List 接口的子类。此类与 ArrayList 类一样,都是 AbstractList 的子类。所以,此时的操作只要是 List 接口的子类就都按照 List 进行操作。

      是旧的类是在 JDK 1.0 的时候就定义的。性能较低,是采用了同步处理。除了支持 Iterator、ListIterator 输出,还支持Enumeration 输出。

   (3)LinkedList集合

     java.util.LinkedList 集合数据存储的结构是链表结构。方便元素添加、删除的集合。

     实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。这些方法我们作为了解即可:

     (1)public void addFirst(E e) :将指定元素插入此列表的开头。

     (2)public void addLast(E e) :将指定元素添加到此列表的结尾。

     (3)public E getFirst() :返回此列表的第一个元素。

     (4)public E getLast() :返回此列表的最后一个元素。

     (5)public E removeFirst() :移除并返回此列表的第一个元素。

     (6)public E removeLast() :移除并返回此列表的最后一个元素。

     (7)public E pop() :从此列表所表示的堆栈处弹出一个元素。

     (8)public void push(E e) :将元素推入此列表所表示的堆栈。

     (9)public boolean isEmpty() :如果列表不包含元素,则返回true。

  5. Iterator迭代器

   5.1. Iterator接口

    在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口java.util.Iterator 。 Iterator 接口也是Java集合中的一员,但它与 Collection 、 Map 接口有所不同, Collection 接口与 Map 接口主要用于存储元素,而 Iterator 主要用于迭代访问(即遍历)Collection 中的元素,因此 Iterator 对象也被称为迭代器。

    想要遍历Collection集合,那么就要获取该集合迭代器完成迭代操作,下面介绍一下获取迭代器的方法:

    (1)public Iterator iterator() : 获取集合对应的迭代器,用来遍历集合中的元素的。

 

    (2)public E next() :返回迭代的下一个元素。

    (3)public boolean hasNext() :如果仍有元素可以迭代,则返回 true。

    下面介绍一下迭代的概念:

    迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。

   5.2 迭代器的实现原理

    当遍历集合时,首先通过调用t集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。

   5.3 增强for

   增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中不能对集合中的元素进行增删操作。

    格式:  

    for(数据类型  变量名 : 集合or数组名){
      //写操作代码
    }

    它用于遍历Collection和数组。通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。

  6. Set接口

   java.util.Set 接口和 java.util.List 接口一样,同样继承自 Collection 接口,它与Collection 接口中的方法基本一致,并没有对 Collection 接口进行功能上的扩充,只是比Collection 接口更加严格了。与 List 接口不同的是, Set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。  

   Set 集合有多个子类,这里我们介绍其中的 java.util.HashSet 、 java.util.TreeSet 这两个集合。

   6.1 HashSet集合介绍

    java.util.HashSet 是 Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。 java.util.HashSet 底层的实现其实是一个 java.util.HashMap 支持。

    HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于: hashCode 与 equals 方法。

    HashSet 虽然是Set 接口子类,但是对于没有复写 Object 的 equals 和 hashCode 方法的对象,加入了 HashSet集合中也是不能去掉重复值的。

   6.2 LinkedHashSet

    我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?在HashSet下面有一个子类 java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结构。

   6.3 TreeSet与Comparable

    使用TreeSet创建集合时会根据传入的值进行排序,但是如果传入的是对象,则需要我们重写Comparable接口里面的compareTo方法

    例子:

     TreeSet<String> data = new TreeSet<>();      如果为对象:Person类里面有name和age两个属性          

     data.add("B");                  TreeSet<Person> data = new TreeSet<>();

     data.add("C");                  Person p1 = new Person("张三",18);

     data.add("D");                  Person p2 = new Person("李四",20);

     data.add("A");                  data.add(p1);

     for(String s:data){                  data.add(p2);

      System.out.print(s);                for(Person p:data){

     }                          System.out.print(p);

     运行结果为 A  B  C  D              }

                             此时需要在Person类里面重写Comparable接口里面的compareTo方法

    

     先继承Comparable接口,public class Person implements Comparable<Person>

     public int compareTo(Person o){

      //返回的数据:负数this小/零一样大/整数this大

      if(this.age > o.age){

       return 1;

      }else if(this.age == o.age){

       return 0;

      }

      return -1;

     }

     这时上面运行的结果为

     Person{name='张三',age=18}

     Person{name='李四',age=20}

     如果age相等则会只输出第一个,因为set集合不能出现重复的元素

六. Map

 1. 概述:

  Map集合存储的是一个个的键值对数据

  Map集合的键(key)不可重复

  Map 本身是一个接口,所以一般会使用以下的几个子类:HashMap、TreeMap、Hashtable

 2. HashMap

  Jdk1.8:

   哈希桶中的数据量大于8时,从链表转换为红黑二叉树;

   当哈希桶中的数据量减少到6时,从红黑二叉树转换为链表。

  散列因子:0.75,意思是当75%的桶存有数据时,对桶进行扩容,长度变为原长度的2倍。

  HashMap 本身是属于无序存放的

 3. HashMap、Hashtable、ConcurreHashMap的区别

   HashMap:线程不安全,效率高

   Hashtable:线程安全,效率低

  ConcurreHashMap:采用分段锁机制,保证线程安全,效率又比较高。

  TreeMap:要求对象所在的类必须实现 Comparable 接口。

  LinkedHashMap:保证HashMap有序

 4.散列表散列操作

  HashMap的实例有两个影响其性能的参数:初始容量和散列因子。初始容量默认为16,负载因子默认为0.75。

  在创建HashMap时如果要对初始容量和散列因子进行修改时,应该进行合理的修改

七. 内存泄露

  在java的集合中,判断两个对象是否相等的规则是:

  (1)判断两个对象的 hashCode 是否相等。如果不相等,认为两个对象也不相等,完毕;如果相等,转入 2

  (2)判断两个对象用 equals 运算是否相等。如果不相等,认为两个对象也不相等;如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)。

  当一个对象被存进 HashSet 集合后,就不能修改这个对象中的那些参与计算的哈希值的字段了,否则,对象被修改后的哈希值与最初存储进 HashSet 集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用作为的参数去 HashSet 集合中检索对象,也将返回找不到对象的结果,这也会导致无法从 HashSet 集合中删除当前对象,从而造成内存泄露。

八. JDK9集合新特性

  List、Set、Map

  of()不可修改的集合。

posted @   Luo_YB  阅读(110)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示