Java-集合框架(List集合ArrayList,LinkedList,HashSet,TreeSet,Map,HashMap及其原理)

集合框架的概念

        Java集合框架(Java Collections Framework简称JCF)是为表示和操作集合,而规定的一种统一的标准的体系结构。集合框架包含三大块内容:对外的接口、接口的实现和对集合运算的算法。

        集合就是用于存储对象的容器。 只要是对象类型就可以存进集合框架中。集合的长度是可变的。 集合中不可以存储基本数据类型的值

Java-集合框架(List集合ArrayList,LinkedList,HashSet,TreeSet,Map,HashMap及其原理)_第1张图片

集合与数组的区别(为什么要使用集合)

        数组和集合相比,数组的缺点是它长度是固定的,没有办法动态扩展。

        而集合存储数据时是没有长度限制的,是可以动态扩展的。集合容器因为内部的数据结构不同,有多种不同的容器对象。这些容器对象不断的向上抽取,就形成了集合框架。

集合的架构

Java-集合框架(List集合ArrayList,LinkedList,HashSet,TreeSet,Map,HashMap及其原理)_第2张图片

 List-集合

特点

  • List集合是有序集合: 数据的添加和存储次序一致
  • List集合可以存储重复的数据
  • List集合中的数据可以通过下标访问

Java-集合框架(List集合ArrayList,LinkedList,HashSet,TreeSet,Map,HashMap及其原理)_第3张图片

一、Array-List

ArrayList的特点:

特点:

  • 实现了List接口
  • 可以动态扩容(我们只管存,长度不够,底层会自动的扩容)
  • 通过下标可以快速访问数据
  • 查找快,插入删除慢
  • ArrayList底层是数组,对数组做了封装
  • 可以存储任意类型的数据,包括null
  • 数据按照存储次序排列
  • 数据可以重复
  • 多线程访问时不安全

1.创建集合对象

首先导入:

(1)import java.util.ArrayList;(2)import java.util.List;

创建一个List对象:

创建一个集合对象,可以指定集合容器的长度也可以不指定,如果指定那么默认长度为10;

List 集合名 =new ArrayList();//没有定义长度默认为10的集合

List 集合名=new ArrayList(5);//定义一个长度为5的集合

List list =new ArrayList();
List list =new ArrayList(5);

2.向集合中添加元素

List-Array中可以添加任意类型的数据;

(1)单个元素的添加:

集合名.add(需要添加的元素);

list.add("你好集合");//添加字符串数据
list.add(2);//添加整型
list.add(3.14);//添加浮点数
list.add(true);//添加布尔型

(2)根据指定下标位置来添加元素

集合名.add(下标位置,元素);

向指定位置添加完元素后,后面的元素会向后移位

list.add(0,001);//向集合中下标为0的位置添加元素001

(3)向集合中添加多个元素(创建一个新集合把新集合添加到需要添加的集合中)

集合名.add(要添加的集合名);默认添加到最后

List list1=new ArrayList();//创建一个新集合
list1.add("a");//向新集合中添加元素
list1.add("b");
list.addAll(list1);//将新集合添加到原集合中

3.删除集合中的元素

(1)删除指定位置的元素(根据下标位置删除)

集合名.remove(下标位置);

list.remove(2);//删除集合中下标位置为2的元素

(2)清空集合中所有的元素

集合名.clear();

list.clear();//清空名字为list的集合中的所有元素

4.集合中元素的修改操作

修改指定位置的元素(根据下标位置进行修改)

集合名.set(下标位置,修改后的内容);

list.set(1,"蜜汁小汉堡");//将list集合中下标位置为1的内容改为"蜜汁小汉堡"

5.集合中的查询操作

(1)查询指定位置的元素(根据下标位置查询)

集合名.get(下标位置);  //注意要记得接收

Object o1=list.get(2);//定义一个Objiect类型的o1用来接收查询到的集合中下标为2的元素的数据
System.out.println(o1);//打印输出o1

(2)获取当前集合中元素的个数

集合名.size();

int num1=list.size();//定义一个整型num1用来接收集合的长度
System.out.println(num1);//打印num1

 (3)查询判断集合中是否有这个元素

集合名.contains(要查找的元素);

如果找到会返回true;

boolean b1=list.contains("001");//定义一个布尔类型用于接收返回值,查询内容为001的元素
System.out.println(b1);

(4)查找集合中的内容并返回它第一次出现的位置

集合名.index(查询内容);

如果找到返回第一次出现的位置,如果找不到返回-1;

6.集合的循环遍历

(1)for循环遍历

        //for循环遍历的集合的内容
        for(int i=0;i

(2)for each循环遍历

   for(Object o3:list){//:前用于接收,:后是要遍历的集合
            System.out.println(o3);
        }

 7.Array-list的实现

通过对ArrayList方法的底层代码分析:底层就是对数组的操作。
ArrayList的底层就是基于数组实现的。

二、LinkedList

LinkedList: 具有List的特征,底层以链表结构实现,可以进行头尾元素的添加删除

LinkedlList底层是双向链表的结构,它增加和删除效率很高,但是它的查询效率低。

查询效率低的原因是因为它把集合对半分成两份在前一份和后一份中一个一个查找.

LinkedList的常见方法:它的方法和ArrayList中的方法比较相似,它有自己特有的方法:

addFirst(),addLast(),getFirst(),getLast()

1.创建LinkedList集合

       LinkedList 集合名字 = new LinkedList();

 LinkedList linkedList =new LinkedList();//创建一个名字linkedList的集合

2.添加到头部(也就是集合中第一个位置)

集合名字.addFirst(内容);

 linkedList.addFirst("张三");//向集合中第一个位置添加张三这个数据

 3.添加到尾部(也就是集合中最后一个位置)

集合名字.addLast(内容);

linkedList.addLast("李四");//向集合最后一个位置添加元素"李四"

 4.查询集合中第一个元素和查询集合中最后一个元素

查询第一个元素:集合名字.getFirst();

查询最后一个元素:集合名字.getLast();

  linkedList.getFirst();
  linkedList.getLast();

5.删除集合中的第一个元素和删除集合中的最后一个元素

删除第一个元素:集合名字.removeFirst();

删除最后一个元素:集合名字.removeLast();

  linkedList.removeFirst();
  linkedList.removeLast();

6.查询集合中是否有数据(集合是否为空)

集合名.isEmpty();

结果是true/false记得要用布尔类型接收;

 boolean empty = linkedList.isEmpty();//判断是否为空

7.LinkedList的底层源码和其原理

Java-集合框架(List集合ArrayList,LinkedList,HashSet,TreeSet,Map,HashMap及其原理)_第4张图片

 pre集合中上一个元素的信息;

next集合中下一个元素的信息;

三、Set集合

Java-集合框架(List集合ArrayList,LinkedList,HashSet,TreeSet,Map,HashMap及其原理)_第5张图片

Set接口特点

  • Set接口是无序的
  • Set接口中的数据不允许重复
  • Set接口无法通过下标访问数据
  • 查找慢,插入删除快(底层数据结构是哈希表和红黑树)
  • Set集合使用equals()和hashCode()方法实现元素去重

HashSet集合

HashSet特点:

  • HashSet是Set接口的实现类
  • 线程不安全

1.创建HashSet对象

(1) HashSet 集合名字 = new HashSet(初始容器大小);

(2)HashSet 集合名字 = new HashSet(初始容器大小,负载因子f);

HashSet集合可以初始定义容器大小也可不定义容器大小

HashSet有负载因子;

负载因子:当容器达到一定值时容器会自扩充,那个值就是负载因子

负载因子如果不写默认是达到75%(0.75)时会自动动态扩充容器;

HashSet hashSet=new HashSet();//定义一个HashSet集合没有指定初始容器大小和负载因子
HashSet hashSet1=new HashSet(15);//定义一个HashSet集合给定初始容器大小为15没有负载因子;
HashSet hashSet2=new HashSet(15,0.75f);//定义一个HashSet集合给定初始大小为15给定负载因子为0.75(75%);

1.添加元素

(1)添加单个元素:集合名字.add(内容);

(2)添加多个元素:集合名字.addAll(另一个集合名);

添加多个元素只能是通过创建另一个HashSet集合将另一个集合的元素添加到本集合中;

 hashSet.add("张三");//向集合中添加"张三"这个数据;
 hashSet.addAll(hashSet1);//向集合中添加另一个集合的数据;

2.删除元素

(1)删除单个元素:集合名字.remove(要删除的数据);

(2)清空集合中的所有数据:集合名字.clear();

 hashSet.remove("张三");//删除集合中张三这个元素
 hashSet.clear();//清空集合中所有元素

3.查询元素是否在集合中和判断集合是否为空

(1)查询元素是否在集合中:集合名字.contains(要查询的内容);

判断的结果是true/false要用boolean 接收;

(2)判断集合是否为空:集合名字.isEmpty();

判断的结果是true/false要用boolean 接收;

boolean b1=hashSet.contains("张三");//查询张三是否在集合中,如果在返回true否则false
boolean b2=hashSet.isEmpty();//判断集合是否为空

4.HashSet的遍历

(1)for each的遍历

for(Object o:hashSet){
            System.out.println(o);
        }

(2)通过迭代器来遍历

 //迭代器遍历
        Iterator iterator = hashSet.iterator();//获取迭代器对象 有序:有下标
        while (iterator.hasNext()){//判断是否指定能够移动
            Object next = iterator.next();//指定移动并获取当前的元素
            System.out.println(next);
        }

迭代器:

迭代器(iterator)有时又称游标(cursor)是程序设计的软件设计模式,可在容器对象(container,例如链表或数组)上遍访的接口,设计人员无需关心容器对象的内存分配的实现细节。

HashSet类中没有提供根据集合索引获取索引对应的值的⽅法,

因此遍历HashSet时需要使⽤Iterator迭代器。Iterator的主要⽅法如下

Java-集合框架(List集合ArrayList,LinkedList,HashSet,TreeSet,Map,HashMap及其原理)_第6张图片

hasNext():判断指针是否能够移动,能够移动返回true否则返回false;

next():指针移动并货期指定所在位置的元素;

TreeSet集合

TreeSet中的方法和HashSet中的方法一模一样 只是他们的实现不一样。
TreeSet 基于TreeMap 实现。TreeSet可以实现有序集合,但是有序性需要通过比较器实现。

TreesSet特点:

  • 有序
  • 不重复
  • 添加、删除、判断元素存在性效率比较高 
  • 线程不安全

TreeSet基于二叉树,它是一个有序得集合,要求里面得元素必须实现Comparable接口。 按照该接口得方法进行排序以及去重。

TreeSet对元素进行排序的方式:

1) 如果是基本数据类型和String类型,无需其它操作,可以直接进行排序。

2) 对象类型元素排序,需要实现Comparable接口,并覆盖其compareTo方法。

3) 自己定义实现了Comparator接口的排序类,并将其传给TreeSet,实现自定义的排序规则。

例子(eg):

   @Override
 public int compareTo(Object o) {
System.out.println("===调用Student 的 compareTo===");
 // 判断要比较的目标类型和当前类型是否一致
if(!(o instanceof Student)){
            return -1;
        }
// 目标数据属于当前类型
 Student s = (Student) o;
if(this.age>s.age){
            return 1;
}else if(this.age

创建TreeSet

创建TreeSet时一定要为其指定排序规则即重写Comparator接口实现接口;

TreeSet 集合名字=new TreeSet(你定义的排序规则);

四、Map接口及其实现类

Map接口特点:

  • 以键值对方式存储数据(Collection是单值集合)
  • 键不能重复,键重复时,后面的数据会覆盖前面的数据
  • 可以存储null
  • 键值对数据无序

 Java-集合框架(List集合ArrayList,LinkedList,HashSet,TreeSet,Map,HashMap及其原理)_第7张图片

map中得每个元素属于键值对模式。 如果往map中添加元素时 需要添加key 和 value. 它也属于一个接口,该接口常见得实现类有: HashMap.

Java-集合框架(List集合ArrayList,LinkedList,HashSet,TreeSet,Map,HashMap及其原理)_第8张图片

 HashMap实现类

HashMap实现了Map接口,拥有Map接口的基本特点。HashMap线程不安全,效率高。HashMap的底层是由哈希表、链表加红黑树构成的。

1.HashMap的创建

(1)创建无初始容器大小无负载因子的HashMap:Map 集合名字=new HashMap();容器默认大小为16

(2)创建有初始容器大小无负载因子的HashMap:Map 集合名字=new HashMap(容器初始大小);

(3)创建有初始容器大小有负载因子的HashMap:Map 集合名字=new HashMap(容器初始大小,负载因子f);

 Map map=new HashMap();
 Map map1=new HashMap(15);
 Map map2=new HashMap(15,0.75f);

2.HashMap的添加操作

添加操作时要添加key和value;键不允许重复必须唯一;

(1)单个键值对的添加:集合名字.put(键,值);

(2)多个键值对的添加(即添加另一个HashMap集合):集合名字.putAll(要添加的HashMap);

(3)判断添加,如果指定得key存在,则不放入map中,如果不存在则放入map中:

集合名字.putIfAbsent(键,值);

map.put("name","张三");//添加一个键为name值为"张三"
map.putAll(map1);//向map中添加集合map1
map.putIfAbsent("age",19);//判断是否有age这个键如果没有就添加如果有就不添加

 如果键已经存在我再添加同一个键的值,后一个会把前一个给覆盖即:键相同时,后面覆盖前面的;

3.HashMap的修改操作

集合名字.replace(键,值);替换name键里的元素

map.replace("name","李四");//修改map中name键的元素为李四

4.HashMap的查询操作

(1)判断集合中是否存在指定的key

集合名字.containsKey(键key);如果存在返回true否则返回false

(2)根据指定的key获取对应的value值

集合名字.get(键key)
(3)返回该map中所有的key

集合名字.keySet()

 boolean b1=map.containsKey("name");//判断map中是否有name键,返回值类型为boolean
 Object o1=map.get("sex");//根据sex键返回map中所有的value值,返回类型为Object
 Set s1=map.keySet();//返回map集合中所有的键,返回类型为Set;

5.HashMap的遍历

for each循环遍历

// 遍历键的集合
        for(Object key : set){
            // 输出所有键 
           // map.get(key):获取对应键的值
            System.out.println(key+" "+map.get(key)); 
       }
/ 遍历map
        for(Object obj : map.keySet()){
            System.out.println(obj+" "+map.get(obj));
        }

6.HashMap的底层原理(重要)

JDK1.7 和 JDK1.8它们是有区别的。
   JDK1.7使用得数据结构: 数组+链表  而且链表插入模式为头部插入(造成死循环)。
   jdk1.8使用得数据结构: 数组+链表+红黑树 而且链表得插入模式为尾部插入。

(1) map.put(key,value)实现原理

第一步:首先将k,v封装到Node对象当中(节点)。

Node节点中存储的是键,值,和下一个元素的地址;

第二步:它的底层会调用K的hashCode()方法得出hash值。

第三步:通过哈希表函数/哈希算法,将hash值转换成数组的下标(即哈希值16%得到一个0~15之间的数为下标),下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equals。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。

(2) map.get(key) 实现原理

第一步:先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。

第二步:通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。重点理解如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着参数K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。

你可能感兴趣的:(java,idea)