全面了解Java集合

简介: 追根溯源全面上手集合(建议反复观看)

前言

设计集合的作者真的是太伟大了,就拿一个简简单单的add()方法,背后的动作在深入了解之后你会强烈感受到了人类的智慧

一.集合VS数组

数组完成定义并启动后,类型确定,长度固定。适合元素的个数和类型确定的业务情景,不适合进行CRUD的操作,就像一个铁盒子放的东西数量是固定的
在这里插入图片描述

集合的大小不固定,启动后可以动态改变,因此适合做数据个数不确定且需要增删元素的场景,集合就像一个气球,想变大就吹气!
在这里插入图片描述**

二.集合体系特点

**Collection单列集合:每个元素(数据)只包含一个值
==注==:set接口的实现子类也有存在两个值的(键值对[K-V]只不过其中的V是一个静态常量PRESENT)实际起作用的还是对象K(key)所以就把他也算作单列了
Map双列集合:每个元素包含两个值(键值对k-v)**
在这里插入图片描述

三.Collection单列集合

Collection这个接口有很多实现类,每一个类也包含了很多内部方法,主流的是List、Set这两个系列
以下是几个常用的实现类
在这里插入图片描述

性能对比(🏁)

**ArrayList:数据结构是数组,查询快,增删慢,线程不安全,效率高,存取顺序一致可重复
LinkedList:数据结构是链表,查询慢,增删快,线程不安全,效率高,存取顺序一致可重复
Vector(很少用):数据结构是数组,查询快,增删慢,线程安全,效率低,存取顺序一致可重复
HashSet:数据结构是哈希表,查询快,增删慢,线程不安全,效率高,存取顺序不一致不可重复
LinkedHashSet:数据结构是链表+哈希表,查询快,增删慢,线程不安全,效率高,存取顺序一致不可重复
TreeSet:数据结构是二叉树,查询快,增删慢,线程不安全,效率高,存取顺序不一致不可重复**

1.List系列常用API

List集合类中元素添加顺序和取出顺序一致、且可重复,List集合中的每个元素都有其对应的顺序索引
List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
以ArrayList为例演示一下List接口实现类的常用方法

**1.add(E e):在集合末尾新增一个元素
2.add(int index, E element):在指定位置添加元素
3.get(int index):获取指定位置的元素
4.remove(int index) :删除指定位置的元素
5.remove(Object o): 删除指定元素
6.indexOf(Object o) :查询指定元素的位置 lastIndexOf也一样,只是从尾部开始遍历
7.set(int index, E element): 设置指定位置的元素值
8.retainAll(Collection<?> c) :求两个集合的交集
9.subList(int fromlndex, int tolndex) :获取【x,y)区间元素
10.set(int index, Object ele) :设置指定位置元素
11.indexOf(Object obj):返回元素在集合中首次出现的位置
12.lastIndexOf(Object obj):返回元素在当前集合中末次出现的位置**
........
  ArrayList col = new ArrayList();
  col.add("懒羊羊");  //添加单个元素
  col.add(100);  //col.add(new Integer(100))     
  col.remove("懒羊羊"); //删除指定元素
  col.remove(0); //删除第一个元素(索引)             
  System.out.println(col.size());  //获取元素个数
  System.out.println(col.isEmpty()); //看是否为空 
  col.clear();//清空
        
  ArrayList c1 = new ArrayList();
  c1.add("AA");
  col.addAll(c1); //把集合c1存进集合col
      
  ArrayList c2 = new ArrayList();
  c2.add("CC");
  c2.add("AA~");
  col.containsAll(c2); //查找col里是否有c2
  col.removeAll(c2);  //删除多个元素 删除col中的c2集合
  col returnlist=col.subList(0,2); //获取区间元素
  col.set(1, "喜羊羊");//设置指定位置元素
  col.indexOf("懒羊羊");//返回懒羊羊在集合中首次出现的位置
  col.lastIndexOf("懒羊羊");//返回懒羊羊在当前集合中末次出现的位置

==注==:每一个接口实现类的方法非常多,感兴趣可以自己去看看

2.Set系列常用API

和List系列集合一样,set系列集合也是Collection接口的实现类,所以用法和上述差不太多
==注==:set接口的实现类的对象(Set接口对象),不能存放重复的元素,可以添加一个null,set接口对象存放数据是无序(即添加的顺序和取出的顺序不一致)
内部方法大部分都一样,只不过不能使用索引来操作集合元素,因为set接口对象存放数据无序

   HashSet hs = new HashSet();
   hs.add(null);
   hs.add("懒羊羊");//添加单个元素
   hs.remove("懒羊羊"); //删除指定元素
   hs.remove(0); //删除第一个元素
   System.out.println(hs.size());  //获取元素个数
   System.out.println(hs.isEmpty()); //看是否为空 
   hs.clear();//清空

   HashSet c1 = new HashSet();
   c1.add("AA");
   hs.addAll(c1); //把集合c1存进集合hs

   HashSet c2 = new HashSet();
   c2.add("CC");
   c2.add("AA~");
   hs.containsAll(c2); //查找hs里是否有c2
   hs.removeAll(c2);  //删除多个元素 删除hs中的c2集合

四.Map双列集合

Map与Collection并列存在,用于保存具有映射关系的数据:Key-Value,Map接口也有很多实现类,HashMap较为典型,下图是一部分实现类
在这里插入图片描述
HashMap:数据结构是哈希表,查询快,线程不安全,无序不重复
LinkedHashMap:数据结构是哈希表+链表,查询快,线程不安全,有序不重复

1.Map系列常用API

Map 中的 key和 value可以是==任何引用类型的数据==,会封装到HashMap$Node对象中,Map中的key不允许重复,value可以重复
Map的key可以为null, value也可以为null,注意key为null, 只能有一个,value为null可以有多个一般用String类作为Map的key
注:key和 value 之间存在==单向一对一==关系,即通过指定的key总能找到对应的value

**1.put(key,value):通过k-v添加元素
2.replace(3, "小灰灰"):在指定元素key的数据替换为新的value
3.clear():清空元素
4.isEmpty():判断是否为空返回boolean类型
5.put(new Object(),"灰太狼"):k-v中的K可以存放对象
6.get(key):用于获取指定K的元素
7.remove(key):删除指定元素**
Map map = new HashMap();
map.put( "1","懒羊羊");//通过k-v添加元素
map.put( "2","慢羊羊");//k-v
map.put("1","沸羊羊");//当有相同的k,就等价于替换
map.put( "3","美羊羊");//k-v
map.put(null, null); //可添加null
map.put(null,"喜羊羊");//通过相同的null等价替换
map.replace(3, "小灰灰");//在指定元素key的数据替换为新的value
map.get(3);//获取k为3的元素
map.size();//获取集合大小
map.clear();//清空元素
map.isEmpty(); //判断是否为空返回boolean类型
map.put(new Object(),"灰太狼");  //k-v

五.集合的遍历方式

集合的遍历就是一个一个的把容器中的元素访问一遍

1.迭代器遍历(🏁)

迭代器在Java中的代表是Iterator,有时又称光标(cursor)是程序设计的软件设计模式,迭代器是集合的专用遍历方式
1.首先要获得迭代器:

Collection col = new ArrayList();
Iterator m= col.iterator(); //获得集合对象col的迭代器 m

2.其次遍历集合:

while (m.hasNext()) {//使用while循环遍历 判断是否还有数据
     Object obj =m.next(); //动态绑定 取决于运行类型(什么样的对象)
     System.out.println(obj);//打印集合中的元素
}

完成迭代器遍历集合
==注==:如果要在当前基础上再次遍历还需要重新获取一下迭代器

2.增强for循环遍历

增强for循环遍历的本质还是利用迭代器

Collection col = new ArrayList();
for (Object o : col) {
            System.out.println(o);
        }

3.Lambda表达式遍历

从JDK8开始产生的新技术Lambda表达式遍历,是一种==更简单,更直接==的遍历集合的方式

Collection col = new ArrayList();
col.forEach(s ->{
   System.out.println(s);
});

4.Map遍历特例

1.遍历Map时,可以通过Key来遍历,首先要做的是取出所有的key,然后通过key得到value
具体操作:Collection keys = map.keySet();然后通过迭代器,增强for循环进行遍历,因为存在.get(key)方法,所以遍历过程中可以通过此方法得到集合中的所有元素
可以使用Collection的遍历方法本质也==是多态的体现==
在这里插入图片描述

2.第二种方式通过values遍历
具体操作:Collection values = map.values();同样也可以使用迭代器,增强for循环
注:遍历集合取出的是value
本质也是values()方法实现了Set接口,Set接口继承了Collection接口(==体现多态性==
在这里插入图片描述
3.第三种则是通过EntrySet获取k-v的方式遍历
具体操作:

Collection es = map.entrySet();
for (object entry : es) {
      Map.Entry m = (Map.Entry) entry;//将entry转型成成Map.Entry才能使用下面两个方法 
    system.out.println(m.getKey() + "" + m.getValue());
}

也可以选择迭代器遍历

六.集合存储对象过程

1.ArrayList集合底层原理(🏳️‍🌈)

ArrayList底层是基于数组实现的:
根据索引定位元素快,增删需要做元素的移位操作。第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组。
通过ArrayList的内部方法.add()来解读源码:

1.当创建ArrayList对象时,如果使用的是无参构造器,首先创建空的elementData数组 在这里插入图片描述
在这里插入图片描述
2.执行add()向空数组扩容 在这里插入图片描述
这个方法里包含了很多动作它先通过ensureCapacityInternal()判断是否要扩容
在这里插入图片描述
再通过calculateCapacity()判断elementData是否为空数组,若是则返回10,并将空数组扩容至为空间为10 在这里插入图片描述

3.当执行的add操作大于当前容量(10)则与当前空间大小比较并执行grow()方法进行扩容 在这里插入图片描述
4.前面我们知道初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍,注意没有拷贝数祖前里面的元素都是null
在这里插入图片描述

2.LinkedList集合底层原理(🏳️‍🌈)

原码解读:

1.首先也是通过构造器创建一个大小为0的链表,并且头尾都指向null 在这里插入图片描述
2.当执行add()添加操作时调用linkLast()方法 在这里插入图片描述
使用linkLast()将新的节点加入到双向链表尾部,也就是last指向“1”这个节点
在这里插入图片描述
同理也使用Linkedfirst()让first指向“1”这个节点

最后完成了add(1)的操作 将1添加到双向链表中
在这里插入图片描述

感想

我真是好后悔没把数据结构学到位
写到这里:==懒羊羊寿命-2年==

相关文章
|
3月前
|
Java 大数据 API
Java Stream API:现代集合处理与函数式编程
Java Stream API:现代集合处理与函数式编程
278 100
|
3月前
|
Java API 数据处理
Java Stream API:现代集合处理新方式
Java Stream API:现代集合处理新方式
308 101
|
3月前
|
算法 Java
50道java集合面试题
50道 java 集合面试题
|
2月前
|
存储 算法 安全
Java集合框架:理解类型多样性与限制
总之,在 Java 题材中正确地应对多样化与约束条件要求开发人员深入理解面向对象原则、范式编程思想以及JVM工作机理等核心知识点。通过精心设计与周密规划能够有效地利用 Java 高级特征打造出既健壮又灵活易维护系统软件产品。
112 7
|
5月前
|
Oracle Java 关系型数据库
掌握Java Stream API:高效集合处理的利器
掌握Java Stream API:高效集合处理的利器
416 80
|
5月前
|
安全 Java API
Java 8 Stream API:高效集合处理的利器
Java 8 Stream API:高效集合处理的利器
316 83
|
4月前
|
存储 缓存 安全
Java集合框架(二):Set接口与哈希表原理
本文深入解析Java中Set集合的工作原理及其实现机制,涵盖HashSet、LinkedHashSet和TreeSet三大实现类。从Set接口的特性出发,对比List理解去重机制,并详解哈希表原理、hashCode与equals方法的作用。进一步剖析HashSet的底层HashMap实现、LinkedHashSet的双向链表维护顺序特性,以及TreeSet基于红黑树的排序功能。文章还包含性能对比、自定义对象去重、集合运算实战和线程安全方案,帮助读者全面掌握Set的应用与选择策略。
306 23
|
3月前
|
存储 Java Go
对比Java学习Go——函数、集合和OOP
Go语言的函数支持声明与调用,具备多返回值、命名返回值等特性,结合`func`关键字与类型后置语法,使函数定义简洁直观。函数可作为一等公民传递、赋值或作为参数,支持匿名函数与闭包。Go通过组合与接口实现面向对象编程,结构体定义数据,方法定义行为,接口实现多态,体现了Go语言的简洁与高效设计。
|
4月前
|
安全 Java 开发者
Java集合框架:详解Deque接口的栈操作方法全集
理解和掌握这些方法对于实现像浏览器后退功能这样的栈操作来说至关重要,它们能够帮助开发者编写既高效又稳定的应用程序。此外,在多线程环境中想保证线程安全,可以考虑使用ConcurrentLinkedDeque,它是Deque的线程安全版本,尽管它并未直接实现栈操作的方法,但是Deque的接口方法可以相对应地使用。
296 12
|
4月前
|
存储 缓存 安全
Java集合框架(三):Map体系与ConcurrentHashMap
本文深入解析Java中Map接口体系及其实现类,包括HashMap、ConcurrentHashMap等的工作原理与线程安全机制。内容涵盖哈希冲突解决、扩容策略、并发优化,以及不同Map实现的适用场景,助你掌握高并发编程核心技巧。