集合框架和Iterator接口

简介

集合框架:用于存储数据的容器。

集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。

集合接口与实现分离

接口:表示集合的抽象数据类型。接口允许我们操作集合时不必关注具体实现,从而达到“多态”。

实现:集合接口的具体实现,是重用性很高的数据结构。

特点

  • 可以动态保存任意多个对象,使用比较方便
  • 提供了一系列操作对象的方法: add, remove, set, get

集合和数组的区别

  • 数组是固定长度的;集合可变长度的。
  • 数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
  • 数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。

数据结构:就是容器中存储数据的方式。

对于集合容器,有很多种。因为每一个容器的自身特点不同,其实原理在于每个容器的内部数据结构不同。

使用集合框架的好处

  1. 容量自增长;
  2. 提供了高性能的数据结构和算法,使编码更轻松,提高了程序速度和质量;
  3. 允许不同 API 之间的互操作,API之间可以来回传递集合;
  4. 可以方便地扩展或改写集合,提高代码复用性和可操作性。
  5. 通过使用JDK自带的集合类,可以降低代码维护和学习新API成本。

集合的框架体系

集合框架中的接口:

集合有两个基本接口: Collection 和 Map, Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。

  • Collection一次存一个元素,是单列集合;
  • Map一次存一对元素,是双列集合。Map存储的一对元素:键–值,键(key)与值(value)间有对应(映射)关系。

Iterator接口

Iterator用于集合元素的遍历的接口

Iterator接口拥有4个方法:

public interface Iterator<E>{//返回迭代中的下一个元素.如果已经到达了集合的末尾,将抛出一个NoSuchElementException的异常E next();//如果存在下一个可访问的元素,则返回true;boolean hasNext();//删除上一次访问的对象.这个方法必选紧跟在访问一个元素之后执行.若果上次访问之后集合已经发生了变化,//这个方法将抛出一个IllegalStateExceptionvoid remove();//对每个剩余元素执行给定的操作,直到所有元素都被处理或动作引发异常。 //如果指定了该顺序,则按迭代的顺序执行操作。 动作抛出的异常被转发给呼叫者。default void forEachRemaining(Consumer <? super E> action);
}

使用迭代器遍历集合元素

public class Test {public static void main(String[] args) {Collection c = new ArrayList();c.add("a01");c.add("a02");c.add("a03");System.out.println(c);//hasNext()保证next在到达集合末尾时停止运行 快捷键ititIterator iter = c.iterator();while (iter.hasNext()) {String s = (String) iter.next();System.out.println(s);}//foreach循环同样可以进行循环操作//编译器简单地将foreach循环转换成带有迭代器的循环//foreach循环可以处理任何实现了Iterable接口的对象for (Object o :c) {System.out.println(o);}}
}

对于java迭代器我们可以认为其位于两个元素之间.当调用next时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用.

使用Iterator迭代器进行删除集合元素

    Iterator iter = c.iterator();iter.next();iter.remove();

remove方法对next方法具有依赖性,调用remove前没有调用next僵尸不合法的,会抛出IllegalStateException

在执行remove操作时,同样先执行checkForComodification(),如果不相等会抛出ConcurrentModificationException异常,相等则会执行ArrayList的remove()方法,该方法会将modCount值加1,将expectedModCount=modCount,使之保持统一.

ListIterator接口

Iterator中没有add方法,提供了一个子接口ListIterator,只能用于各种List类型的访问.

常用API:

Modifier and Type Method and Description
void add(E e) 将指定的元素插入列表(可选操作)。
boolean hasNext() 返回 true如果遍历正向列表,列表迭代器有多个元素。
boolean hasPrevious() 返回 true如果遍历反向列表,列表迭代器有多个元素。
E next() 返回列表中的下一个元素,并且前进光标位置。
int nextIndex() 返回随后调用 next()返回的元素的索引。
E previous() 返回列表中的上一个元素,并向后移动光标位置。
int previousIndex() 返回由后续调用 previous()返回的元素的索引。
void remove() 从列表中删除由 next()previous()返回的最后一个元素(可选操作)。
void set(E e) 用 指定的元素替换由 next()previous()返回的最后一个元素(可选操作)。

Collection接口

Collection集合主要有List和Set两大接口, 他们实现的子类都是单列集合;

Collection接口没有直接实现的子类,是通过它的子接口Set和List来实现的;

  • List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。
  • Set:无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性。

List集合

List是元素有序并且可以重复的集合.

List中的每个元素拥有对应的整数型序号记载其在容器中的位置,支持通过序号存取容器中的元素.

List的主要实现:ArrayList, LinkedList, Vector.

List常用方法:

ArrayList、LinkedList、Vector 的区别

ArrayList LinkedList vector
底层实现 数组 双向链表 数组
同步性及效率 不同步,非线程安全,效率高,支持随机访问 不同步,非线程安全,效率高 同步,线程安全,效率低
特点 查询快,增删慢 查询慢,增删快 查询快,增删慢
默认容量 10 / 10
扩容机制 int newCapacity = oldCapacity + (oldCapacity >> 1);//1.5 倍 / 2 倍
  • LinkedList 不会出现扩容的问题,所以比较适合随机位置增、删。但是其基于链表实现,所以在定位时需要线性扫描,效率比较低。
  • 当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;
  • 当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。

通过Iterator遍历并操作元素

List可以通过for循环,增强for循环(foreach)以及迭代器进行遍历

public static void main(String[] args) {List a = new ArrayList();a.add("Amy");a.add("Carl");a.add("Erica");List b = new ArrayList();b.add("Bob");b.add("Doug");b.add("Frances");b.add("Gloria");ListIterator aIter = a.listIterator();Iterator bIter = b.iterator();//将b中的元素加入a中while (bIter.hasNext()) {if (aIter.hasNext()){aIter.next();}aIter.add(bIter.next());}System.out.println(a);//ABCDEFG//重置迭代器bIter = b.iterator();//迭代器每移动两次删除前一次的next返回的元素while (bIter.hasNext()) {bIter.next();if (bIter.hasNext()){bIter.next();bIter.remove();}}//foreach遍历for (Object o :b) {System.out.println(o);//BF}a.removeAll(b);//for循环遍历for (int i = 0; i < a.size(); i++) {System.out.println(a.get(i));//ACDEG}
}

对于ArrayList底层结构为数组的集合来说,在进行遍历并操作元素时尽量采用迭代器进行操作.

for循环遍历在集合元素发生变化时索引值变化引发的一些问题(连续重复值的删除导致漏删)

foreach循环为简化版迭代器,在使用时会调用迭代器的next方法,其中checkForComodification()方法对expectedModCount和modCount两值进行判断.modCount是指集合的修改次数,当进行add或者delete时,modCount会+1;expectedModCount是指集合的迭代器的版本号,初始值是modCount,但是当集合进行add或者delete操作时,modCount会+1,而expectedModCount不会改变.迭代器中的remove方法会将modCount的值赋予expectedModCount,使两值保持同步,不会抛出异常.

Set集合

Set集合元素无序(存入和取出的顺序不一定一致),没有索引, 并且没有重复对象。

Set的主要实现类:HashSet, TreeSet。

Set的常用方法

其中因为没有索引,所以没有get和set方法,hashCode是Set中的一个重要方法,在Set的底层实现中起到了至关重要的作用.

HashSet、TreeSet、LinkedHashSet的区别

HashSet TreeSet LinkedHashSet
底层实现 HashMap(哈希表即数组,链表和红黑树) 红黑树 LinkedHashMap(维护数组和双向链表)
重复性 不允许重复 不允许重复 不允许重复
有无序 无序 有序,支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。 有序,插入和取出顺序一致
时间复杂度 add(),remove(),contains()方法的时间复杂度是O(1) add(),remove(),contains()方法的 时间复杂度是O(logn) LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet,时间复杂度是 O(1)。
同步性 不同步,线程不安全 不同步,线程不安全 不同步,线程不安全
null值 允许null 不支持null值,会抛出 java.lang.NullPointerException 异常。因为TreeSet应用 compareTo() 方法于各个元素来比较他们,当比较null值时会抛出 NullPointerException异常。 允许null值
比较 equals() compareTo() equals()

Map接口

  • Map与Collection并列存在,用于保存具有映射关系的数据: Key-Value
  • Map中的Key和Value可以是任何引用类型数据,会封装到HashMap$Node对象中
  • Map中的Key不允许重复,Value可以重复
  • Key可以为null,Value也可以为null,但是须遵守第三条
  • Key和Value是单向的一对一关系(Key==>Value),指定Key一定能找到对应的Value
  • Map 的常用实现类:HashMap、TreeMap、HashTable、LinkedHashMap

Map接口常用方法

HashMap、HashTable、TreeMap的区别

HashMap HasTable TreeMap
底层实现 哈希表 哈希表 红黑树
同步性 不同步 同步 不同步
null值 键值对可以为null,但是Key值只能有一个null 不允许key、value 是 null value允许为null。
当未实现 Comparator 接口时,key 不可以为null
当实现 Comparator 接口时,若未对 null 情况进行判断,则可能抛 NullPointerException 异常。如果针对null情况实现了,可以存入,但是却不能正常使用get()访问,只能通过遍历去访问。
hash 使用hash(Object key)扰动函数对 key 的 hashCode 进行扰动后作为 hash 值 直接使用 key 的 hashCode() 返回值作为 hash 值
容量 容量为 2^4 且容量一定是 2^n 默认容量是11,不一定是 2^n
扩容 两倍,且哈希桶的下标使用 &运算代替了取模 2倍+1,取哈希桶下标是直接用模运算

HashMap

  • Hashmap接口基于哈希表的实现,是使用频率最高的用于键值对处理的数据类型。
  • 它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,特点是访问速度快,遍历顺序不确定,线程不安全
  • 可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap类。

HashTable

  • Hashtable和HashMap从存储结构和实现来讲有很多相似之处,不同的是它承自Dictionary类,而且是线程安全的,另外Hashtable不允许key和value为null,并发性不如ConcurrentHashMap。
  • Hashtable不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换。

LinkedHashMap

  • LinkedHashMap继承了HashMap,是Map接口的哈希表和链接列表实现,它维护着一个双重链接列表,此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。

TreeMap

  • TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺序),也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。

HashMap在JDK1.7和JDK1.8中有哪些不同

不同 JDK1.7 JDK1.8
存储结构 数组+链表 数组+链表+红黑树
初始化方式 单独函数: inflatable() 集成到了扩容函数: resize()
hash值计算方式 扰动处理 = 9次扰动 = 4次位运算 + 5次异或运算 扰动处理 = 2次扰动 = 1次位运算 + 1次异或运算
存放数据的规则 无冲突时,存放数组;冲突时,存放链表 无冲突时,存放数组;冲突 & 链表长度 < 8:存放单链表;冲突 & 链表长度 > 8&数组长度达到64:树化并存放红黑树
插入数据方式 头插法(先讲原位置的数据移到后1位,再插入数据到该位置) 尾插法(直接插入到链表尾部/红黑树)
扩容后存储位置的计算方式 全部按照原来方法进行计算(即hashCode ->> 扰动函数 ->> (h&length-1)) 按照扩容后的规律计算(即扩容后的位置=原位置 or 原位置 + 旧容量)

Collections工具类

Collections是一个集合工具类,方便对集合的操作,提供了一些系列的静态方法

静态方法演示:

public class Test {public static void main(String[] args) {List list = new ArrayList();list.add("a01");list.add("c02");list.add("k03");list.add("s04");list.add("e091");//逆向反转排序Collections.reverse(list);//随机排序Collections.shuffle(list);//根据元素的自然顺序对List元素升序排序Collections.sort(list);//交换对应位置元素Collections.swap(list,2,0);//根据指定的 Comparator 产生的顺序对 List 集合元素进行排序//按照元素的第三个字符的自然顺序降序Collections.sort(list, new Comparator() {@Overridepublic int compare(Object o1, Object o2) {return ((String)o2).charAt(2) - ((String)o1).charAt(2);}});//max方法默认返回最大的元素//此处是根据 Comparator 返回长度最大的元素System.out.println(Collections.max(list, new Comparator<Object>() {@Overridepublic int compare(Object o1, Object o2) {return ((String) o1).length() - ((String) o2).length();}}));//复制List到指定DestListList destlist = new ArrayList();//创建了一个和List大小相同的空数组,保证可以全部复制for (int i = 0; i < list.size(); i++) {destlist.add("");}Collections.copy(destlist,list);}/*将非同步集合转成同步集合的方法:Collections中的  XXX synchronizedXXX(XXX);  原理:定义一个类,将集合所有的方法加同一把锁后返回。List synchronizedList(list);Map synchronizedMap(map);*/
}

Arrays数组工具类

用于操作数组对象的工具类,里面都是静态方法。

数组 -> 集合:asList方法,将数组转换成list集合。

String[] arr ={"abc","kk","qq"};
List<String> list =Arrays.asList(arr);//将arr数组转成list集合。
  • 可以通过list集合中的方法来操作数组中的元素:isEmpty()、contains、indexOf、set;
  • 注意(局限性):数组是固定长度,不可以使用集合对象增加或者删除等,会改变数组长度的功能方法。比如add、remove、clear。(会报不支持操作异常UnsupportedOperationException);
  • 如果数组中存储的引用数据类型,直接作为集合的元素可以直接用集合方法操作。
  • 如果数组中存储的是基本数据类型,asList会将数组实体作为集合元素存在。

集合 -> 数组:用的是Collection接口中的toArray()方法;

List list = new ArrayList();
Object[] array = list.toArray();
  • 如果给toArray传递的指定类型的数据长度小于了集合的size,那么toArray方法,会自定再创建一个该类型的数据,长度为集合的size。
  • 如果传递的指定的类型的数组的长度大于了集合的size,那么toArray方法,就不会创建新数组,直接使用该数组即可,并将集合中的元素存储到数组中,其他为存储元素的位置默认值null。
  • 所以,在传递指定类型数组时,最好的方式就是指定的长度和size相等的数组。

用基本数据类型的数组转换ArrayList,ArrayList的size有问题

public class Test {public static void main(String[] args) {int[] a = {1,2,6,9,5};List ints = Arrays.asList(a);System.out.println("size:"+ints.size());//size:1Integer[] b = {1,2,6,9,5};List ints1 = Arrays.asList(b);System.out.println("size:"+ints1.size());//size:5}
}

asList方法接受的参数是一个泛型的变长参数,我们知道基本数据类型是无法泛型化的,也就是说基本类型是无法作为asList方法的参数的, 要想作为泛型参数就必须使用其所对应的包装类型。但是这个这个实例中为什么没有出错呢?因为该实例是将int 类型的数组当做其参数,而在Java中数组是一个对象,它是可以泛型化的。所以该例子是不会产生错误的。既然例子是将整个int 类型的数组当做泛型参数,那么经过asList转换就只有一个int 的列表了.

asList转换得到的ArrayList不是java.util.ArrayList

Integer[] b = {1,2,6,9,5};
List list = Arrays.asList(b);
//添加元素时抛出异常UnsupportedOperationException
list.add(10);

此处ArrayList是Arrays的内部类继承了AbstractList但是没有实现add方法,而是直接抛出UnsupportedOperationException异常.

Integer[] b = {1,2,6,9,5};
List list = new ArrayList(Arrays.asList(b));
//添加元素时抛出异常UnsupportedOperationException
list.add(10);

使用ArrayList将其转为list集合而非之前的Arrays的内部类ArrayList

整体框架图

参考文献

Java集合框架总结

Java集合框架最全详解

Java核心技术卷Ⅰ第九章集合

韩顺平笔记第14章集合

集合框架(java学习总结笔记)相关推荐

  1. java学习---新手笔记,多多包涵

    引用数据类型{ 类, 接口, 数组 } Java局部变量 局部变量声明在方法.构造方法或者语句块中: 局部变量在方法.构造方法.或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁: 访问修饰 ...

  2. java super object,java学习记录笔记--继承,super,Object类

    继承: Java中的继承是单继承的. 1.子类拥有父类的全部属性和方法. 可是属性和方法的修饰符不能使private. 2.能够复用父类的代码. 方法的重写须要满足的条件: a.返回值类型 b.方法名 ...

  3. 集合框架|Java集合框架基本使用

    大家好,我是程序猿小马,沪漂一族! 写文章就是对于平时的总结以及大家共同学习进步,早日码出各自的梦想

  4. java 学习心得笔记

    j2ee 模式 value object(值对象)用于把数据从某个对象/层传递到其他对 象/层的任意 java 对象. 通常不包含任何业务方法. 也许设计有公共属性,或者提供可以获取属性值的 get ...

  5. Java 学习多态笔记

    一. 多态同一个对象在不同时期表现的出不形态,要构成多态必须满足以下三个前提1.要有继承或实现2.有方法的重写3.有父类的引用指向对象eg:public class Animal {public St ...

  6. 2022年Java学习笔记目录

    一.2022年Java任务驱动课程 任务驱动,统摄知识点:2022年Java程序设计讲课笔记 二.2022年Java学习笔记 (一)踏上Java开发之旅 Java学习笔记1.1.1 搭建Java开发环 ...

  7. 集合框架学习笔记:Collection体系和Map体系、Collections工具类

    集合框架 Java是面向对象编程,万事万物皆"对象",为了方便对"对象"进行操作,需要对"对象"进行存储,而Java集合就是存储" ...

  8. Java集合与泛型学习笔记

    1:Java集合类 首先我们思考为什么出现集合类? 理由: 1面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象操作,就对对象进行储存,集合就是储存对象最常用的一种方式 2 数组和集合同 ...

  9. Java OOP 7 JAVA 集合框架

    Java OOP 第七章 JAVA 集合框架 文章目录 Java OOP 第七章 JAVA 集合框架 一.学习目标 二.数组存在的缺陷 三.Java集合框架 四.Collection接口 五.Coll ...

最新文章

  1. 序列模式挖掘、频繁项集与频繁序列
  2. jquery ajax下拉联动,jQuery Ajax MVC 下拉框联动
  3. SQL Server中查询所有的表、视图、列和存储过程
  4. pku 3159 Candies 差分约束
  5. 自定义View -- 刻度尺
  6. 将list转为json字符串
  7. 【C++面向对象】类的大小以及虚继承
  8. Solr学习笔记001---solr在windows下的安装及配置
  9. 面向对象 —— 类的分类
  10. php中array_flip数组翻转
  11. 什么是飞秒激光技术?
  12. 亿晟科技人脸识别门禁系统方案整体解决办法
  13. SAP 谈谈存货分析报表
  14. Python在cmd上打印彩色文字
  15. 曹胜欢,java那些事儿
  16. 如何给网站做SEO优化?
  17. VBA编程——范例一
  18. 传奇手游单职业服务器外网搭建架设一键端-2023
  19. 安装Pre-commit Hook npx mrm@2 lint-staged pre-commit不执行
  20. DAO 的去中心化程度判定:钟形曲线

热门文章

  1. 刷机介绍----超详细
  2. 2022-2028年中国工业副产石膏行业竞争策略研究及未来前景展望报告
  3. 作为一个专科大二学生真的应该有紧迫感了
  4. matlab ss2tf iu,常用Matlab控制系统处理函数 常用的控制系统处理函数
  5. 一只喵的西行记-13 堡主的魔法星球
  6. 【无标题】1343. 冰岛
  7. c语言 版本号,C语言版本学生信息管理系统
  8. 天池数据分析达人赛3:汽车产品聚类(含代码)
  9. [读书笔记—学习方法]《如何高效学习》- 斯科特·杨
  10. 视觉识别算法的延伸思考 ---- 如何更好的加深对视觉识别算法的理解