草庐IT

Collection单列集合总结

wanghycoder 2023-03-28 原文

这篇文章记录了Collection集合,List集合,Set集合

在文章第七点总结了两大系列集合的五种实现类的区别,有需要的小伙伴可以直接去查看

一、什么是集合

集合是Java中存储对象数据的一种容器

二、集合有什么特点

  1. 大小不固定,类型也可以不固定(通常需要泛型约束)
  2. 集合只能存储引用数据类型
  3. 集合适合对容器中的元素进行增删操作

三、体系结构

Collection单列集合,每个元素(数据)只包含一个值。

Map双列集合,每个元素包含两个值(键值对)。

四、Collection

1. 什么是Collection

官方的解释

  • Collection是集合层次结构中的根接口。 集合表示一组对象,称为其元素 。 有些集合允许重复元素而其他集合则不允许。 有些是有序的,有些是无序的。
  • JDK不提供此接口(Collection)的任何直接实现:它提供了更具体的子接口的实现,如 Set 和 List
  • 此接口通常用于传递集合并在需要最大通用性的情况下对其进行操作。

说的通俗一点就是

  • Collection是根接口,所有集合都来自Collection
  • jdk不提供该接口实现类对象,但提供了更具体的实现类
  • 就好比父类和子类,你可以用父类对象接收一个子类的实例化对象

   例如:Father f = new Sun(); // Sun类继承了Father类

2. Collection的体系结构

3. 常用方法

方法名称

说明

public boolean add(E e)

把给定的对象添加到当前集合中

public void clear()

清空集合中所有的元素

public boolean remove(Object o)

把给定的对象在当前集合中出现的第一个位置删除,如果删除失败返回false

public boolean contains(Object obj)

判断当前集合中是否包含给定的对象

public boolean isEmpty()

判断当前集合是否为空

public int size()

返回集合中元素的个数。

public Object[] toArray()

把集合中的元素,存储到数组中

4. 集合的遍历方式

4.1 迭代器

Iterator是单列集合专用的迭代方法,只能集合调用

Iterator中常用方法

  • next():返回迭代中的下一个元素
  • hasNext():如果迭代具有更多元素,则返回true
Collection<Integer> list = new ArrayList<>();
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
    Integer next = iterator.next();
    System.out.println(next);
}

注意事项

  1. 迭代器只能使用一次
  2. next()移动指针到下一个元素,如果没有抛异常
  3. hasNext()检查下一个元素是否为空,但不移动指针
  4. 迭代器迭代元素越界出现:NoSuchElementException

4.2 普通for

只适用于List系列集合,因为他有序

通过调用集合的get方法,根据索引取值

4.3 增强for

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(2);
//增强for
for (int i : list) {
    if (i == 3) {
        i = 5;//增强for中如果对取出的这个元素修改,将不会对集合产生影响
    }
    System.out.println(i);
}

4.4 Lambda迭代

// 使用lambda表达式集合的迭代 
colStr.forEach(new Consumer() { 
    @Override public void accept(String s) { 
        System.out.println(s); 
    } 
}); 
// 简化写法 
System.out.println("-------------------------"); 
colStr.forEach(s-> System.out.println(s)); 
System.out.println("-------------------------"); 
// 再次简化 
colStr.forEach(System.out::println);

五、List

Collection的子接口

1. 特点

有序,有索引(是独有的),可重复,可存储null值,此实现不同步,线程不安全

存储和取出顺序一致

2. 特有方法

方法名称

说明

注意

void add(int index, E element)

将给定的元素插入到指定位置

索引不能越界,否则报错

 

E get(int index)

返回该索引位置的元素,没找到返回-1

E set(int index, E element)

对给定位置的元素进行替换

E remove(int index)

删除指定位置的元素

int lastIndexOf(Object o)

返回特定元素在集合中最后一次出现的位置

没找到返回-1

int indexOf(Object o)

返回特定元素在集合中第一次出现的位置

ListIterator<E> listIterator()

List集合特有的迭代器

 

List<E> subList(int fromIndex, int toIndex)

根据开始索引和结束索引(左闭右开)返回一个新的集合,该集合是原集合的子集

 

ListIterator叫做列表迭代器,将在第3.2解释

3. 迭代方式

和Collection一样的:迭代器、增强for、Lambda表达式

List独有的:listIterator、普通for(因为有索引)

3.1 并发修改异常

迭代器在迭代集合,但是集合本身被修改,换而言之:就是在同一时刻只能有一个对象来操作集合,否则就会出现并发修改异常

下面两种情况会出现并发修改异常

  1. 迭代器和集合方法都会对集合进行操作

List<String> list = new ArrayList<>();
list.add("java");
list.add("css");
list.add("python");

while(stringListIterator.hasNext()){ 
    String ele = stringListIterator.next(); 
    if("css".equals(ele)){ 
        stringListIterator.remove();//允许 
        //list.remove("css");// 不允许 出现 ConcurrentModificationException 
    } 
    System.out.println(ele); 
}

  2. 增强for本身也是一个Iterator迭代器,同样不能使用

List<String> list = new ArrayList<>();
list.add("java");
list.add("css");
list.add("python");

for (String s : list) {
    if("css".equals(s)){
        list.remove("css");//不允许,并发修改异常
    }
    System.out.println(s);
}

不会出现并发修改异常

List<String> list = new ArrayList<>();
list.add("java");
list.add("css");
list.add("python");

for (int i= 0; i < list.size();i++){ 
    String ele = list.get(i); 
    if("css".equals(ele)){ 
        list.remove("css");// 允许 
    } 
} 
System.out.println(list);

并发修改异常总结

  1. 同一时间只能有一个对象操作集合
  2. 使用迭代器要保证集合不在改变
  3. 出现异常的原因:
    1. 迭代器在进行遍历过程中,如果对数组进行操作,会导致迭代器的实际修改值和集合的预期修改值不对应,就会出异常
    2. 迭代器是一次性的,如果对集合进行操作,没有及时更新迭代器就会引发异常
  4. 如何解决并发修改异常
    1. 使用普通for:用索引取值,同一时间只有一个对象对集合操作
    2. 使用列表迭代器ListIterator

3.2 ListIterator

  • ListIterator的两个遍历方法

boolean hasNext()

从前往后遍历

boolean hasPrevious()

从后往前遍历,前提是先得从前往后遍历一遍,让迭代器指针走到末尾

List<String> list = new ArrayList<>();
ListIterator<String> listIterator = list.listIterator();
  • ListIterator和Iterator的区别
    1. ListIterator每进行一次迭代都会把实际修改值重新赋值给预期修改值,但是Iterator不行
    2. ListIterator是List集合特有的,Iterator是所有集合都有的

4. 两个主要的接口实现类

4.1 特点

List的接口实现类,List的特点就是ArrayList、LinkedList的特点

4.2 ArrayList

  • 使用的是数组,默认容量为10
  • 一旦数组满了,则创建一个新的数组,新数组的容量是原数组的容量的1.5倍。并且会将原数组内容复制到新数组
  • 因为底层是数组,具有数组的特点:查询快,增删慢

  • 可存储null值
  • 此实现不同步,线程不安全

4.3 LinkedList

  • 底层是双向链表
  • 具有链表的特点:查询慢,增删快
  • 此实现不同步,线程不安全
  • 常用方法

六、Set

1. 特点

元素唯一,无序,没有索引,最多只能一个null

三个主要的接口实现类

HashSet、TreeSet、LinkedHashSet

2. HashSet

2.1 特点:无序(HashSet只是不保证有序,并不是保证无序),不重复,无索引,此实现不同步

2.2 底层实现:哈希表,是一种对增删改查性能都较好的结构

  • 哈希表组成

  jdk8之前:数组+链表

  jdk8之后:数组+链表+红黑树

  • 哈希值

  • 哈希值是jdk根据对象计算得出的内存地址,根据某个规则算出来的int类型数值
  • 对象可以通过调用hashCode()返回对象的哈希值
  • 同一个对象的哈希值是相同的
  • 在默认情况下,不同对象的哈希值是相同的(除非重写了hashCode方法

2.3 HashSet底层存储结构

  1. 当调用无参hashSet构造器,会默认创建一个长度为16的数组
  2. 添加元素,元素哈希值数组长度根据哈希算法计算元素存储位置
  3. 判断该位置是否为空,如果为空直接存数组
  4. 如果位置不为空,判断哈希值,如果不同直接存链表
  5. 如果哈希值相同,判断equals是否相同,如果不同直接存链表
  6. 如果都相同就不存
  • 版本差异

  jdk8之前:新元素占据旧元素位置,指向旧元素。当元素链表挂载元素过多会造成查询性能下降。

  jdk8之后:新元素挂在旧元素下面。当链表长度超过8时,自动将链表转换为红黑树,进一步提高性能

  • 元素去重原理(面试会问

  1. 判断hashcode值是否相同,如果不同,则不重复
  2. 如果hashcode相同,调用equals比较,如果为true,则重复。否则挂在元素下边
  3. 在类中可以重写equals和hashCode方法,进行自定义特征比较
//假设这是一个学生类,有name和age两个属性
//重写equals和hashCode方法
@Override 
public boolean equals(Object o) { 
    if (this == o) 
        return true; 
    if (o == null || getClass() != o.getClass()) 
        return false; 
    Student student = (Student) o; 
    return Objects.equals(name, student.name); //例如这里
    //可以自定义比较对象中的哪一个特征,比如就比较名字是否一样,不在乎年龄是否一样
} 
@Override 
public int hashCode() { 
    return Objects.hash(name); //例如这里
    //可以自定义要进行计算哈希的对象,比如只想判断名字哈希是否一样,
    //名字哈希一样就认为这俩对象哈希一样,不在乎年龄哈希是否一样
}

3. TreeSet

3.1 特点:默认自然升序排序,不重复,无索引,可排序

3.2 排序方式

  • 自然排序

  1. 必须实现Comparable接口,重写compareTo,定义排序规则
  2. Integer、String这些类默认已经实现了Comparable接口,可以直接去调用
  3. 英文按照字母顺序,中文按照Unicode码大小升序
  • 比较器排序(定制排序):

  创建集合时候就实现Comparator接口

  如何理解排序呢

  首先要知道这俩的区别

  • Comparable是比较接口,Comparator是比较器
  • 实现比较接口(Comparable)就意味着该类支持排序
  • 实现比较器(Comparator)就意味着该集合要使用自定义的比较方法
  • Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。

  通俗一点,用人话说就是:

  • 使用Comparable就是支持排序,意思是我这个类支持排序
  • 使用了Comparator就是比较器,不管类支不支持,想要排序就得按照我比较器的规矩排序

LinkedHashSet

  1. 特点:有序(存入和取出顺序一样),不重复,无索引
  2. 底层存储结构:哈希表和双向链表,双向链表用来记录存储的顺序

七、所有集合最全面总结

 
List
Set
实现类
ArrayList
LinkedList
HashSet
TreeSet
LinkedHashSet
顺序
有序
有序
无序
有序
有序
重复
可重复
可重复
不可重复
不可重复
不可重复
空值
允许多个null
允许多个null
最多一个null
最多一个null
最多一个null
索引
有索引
有索引
无索引
无索引
无索引
排序
存入顺序就是取出顺序
存入顺序就是取出顺序
不能排序
自然排序和比较器排序
存入顺序就是取出顺序
特点
查询快
增删首尾操作快
增删改查都快的五边形战士
唯一可以自定义排序
增删改查都快的五边形战士
底层
数组
链表
哈希表
红黑树
哈希表和双链表
凡是带list都可重复、有索引
凡是带set都不可重复、无索引
凡是带hash都是五边形战士,增删改查都快
只有HashSet无序、不能排序

八、集合工具类Collections

Collections 不属于集合,是用来操作集合的工具类

 

有关Collection单列集合总结的更多相关文章

  1. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  2. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  3. ruby-on-rails - rails 上的 ruby : radio buttons for collection select - 2

    我有一个集合选择:此方法的单选按钮是什么?谢谢 最佳答案 Rails3中没有这样的助手。在Rails4中,它是collection_radio_buttons. 关于ruby-on-rails-rails上的ruby:radiobuttonsforcollectionselect,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/18525986/

  4. ruby - 按数字(从大到大)然后按字母(字母顺序)对对象集合进行排序 - 2

    我正在构建一个小部件来显示奥运会的奖牌数。我有一个“国家”对象的集合,其中每个对象都有一个“名称”属性,以及奖牌计数的“金”、“银”、“铜”。列表应该排序:1.首先是奖牌总数2.如果奖牌相同,按类型分割(金>银>铜,即2金>1金+1银)3.如果奖牌和类型相同,则按字母顺序子排序我正在用ruby​​做这件事,但我想语言并不重要。我确实找到了一个解决方案,但如果感觉必须有更优雅的方法来实现它。这是我做的:使用加权奖牌总数创建一个虚拟属性。因此,如果他们有2个金牌和1个银牌,加权总数将为“3.020100”。1金1银1铜为“3.010101”由于我们希望将奖牌数排序为最高的,因此列表按降序排

  5. Simulink方法总结和避坑指南(一)——Simulink入门与基本调试方法 - 2

    文章目录一、项目场景二、基本模块原理与调试方法分析——信源部分:三、信号处理部分和显示部分:四、基本的通信链路搭建:四、特殊模块:interpretedMATLABfunction:五、总结和坑点提醒一、项目场景  最近一个任务是使用simulink搭建一个MIMO串扰消除的链路,并用实际收到的数据进行测试,在搭建的过程中也遇到了不少的问题(当然这比vivado里面的debug好不知道多少倍)。准备趁着这个机会,先以一个很基本的通信链路对simulink基础和相关的debug方法进行总结。  在本篇中,主要记录simulink的基本原理和基本的SISO通信传输链路(QPSK方式),计划在下篇记

  6. python - 用于从 Python 到 Ruby 查找集合的所有分区的翻译函数 - 2

    我有以下python函数来递归查找集合的所有分区:defpartitions(set_):ifnotset_:yield[]returnforiinxrange(2**len(set_)/2):parts=[set(),set()]foriteminset_:parts[i&1].add(item)i>>=1forbinpartitions(parts[1]):yield[parts[0]]+bforpinpartitions(["a","b","c","d"]):print(p)有人可以帮我把它翻译成ruby​​吗?这是我目前所拥有的:defpartitions(set)ifnots

  7. C# 的 LINQ 用于在 ruby​​ 中等效的集合操作 - 2

    我是ruby​​开发的新手,我目前正在使用rails2.3.11在ruby​​1.8.7中开发一个项目,我想知道这种语言是否有与C#的linq等效的集合操作,例如where子句。谢谢。 最佳答案 Ruby中Linq的where等价于find_all检查documentationfortheEnumerableModule用于其他功能。 关于C#的LINQ用于在ruby​​中等效的集合操作,我们在StackOverflow上找到一个类似的问题: https://

  8. ruby-on-rails - Rails 表单对象与 reform-rails 与集合不工作或验证 - 2

    我正在使用reform-railsgem为了在我的Rails项目中使用表单对象。我意识到表单对象对于我在下面使用的示例代码来说可能有点矫枉过正,但它仅用于演示目的。在我创建一个用户的表单中,与该用户记录关联的是两个user_emails。#models/user.rbclassUser请注意,我没有在User模型中使用accepts_nested_attributes_for:user_emails。在我看来,表单对象的要点之一是它可以帮助您摆脱使用accepts_nested_attributes_for,所以这就是为什么我试图在没有它的情况下这样做。我从thisvideo得到了这个

  9. ruby - @users 变量为空。忘记为 will_paginate 传递集合对象? - 2

    问题localhost:3000/users/不会显示我谦虚地进入,因为我是第一次尝试通过Rails教程。我在第10章,我已经花了5个小时解决这个问题。当我尝试访问localhost:3000/users/时出现错误(我相信这与factory_girl有关)解释了@users变量为空并且我忘记了为will_paginate传递一个集合对象。我目前在第10章第10.23节,每次运行时:$bundleexecrakedb:reset$bundleexecrakedb:populate$bundleexecrakedb:test:prepare我在解释时遇到错误rakeaborted!Fac

  10. ruby-on-rails - rails : render a collection of models using an specific html view - 2

    我有以下关于rails的简单问题。假设我有一个模型用户。在View中,如果我这样做:views/user/_user.html.erb中的文件View将为每个用户调用和打印。如何更改它以使用特定View?我需要这样的东西:User.all:template=>"user/_user_2ndview.html"%>有什么帮助吗?提前致谢 最佳答案 您可以使用collection选项:User.all,:partial=>"users/user2ndview",:as=>:user%>View必须放在views/users/_user2

随机推荐