Java(6)集合
一、Java集合框架概述
1、什么是集合
- 集合框架:用于存储数据的容器。
- 数组、集合等存储数据的结构,叫Java容器。
- 此时的存储,是指内存层面的存储,不涉及持久化的存储。
- 任何集合框架都包含三大块的内容:对外的接口、接口的实现、对集合运算的算法。
2、集合的特点
数组的特点/缺点:
- 长度固定。一旦初始化,长度不能修改。
- 类型确定。类型严格(算是一个好处),当然要想可以放多种类型的数据,也可以声明为Object类型。
- 方法有限。添加、删除元素效率低;获取元素个数不方便。
- 元素有序可重。对于无序、不重复的元素,不能满足。
集合的特点/优点
- 容量自增长。
3、集合的体系
- Collection接口和Map接口是所有集合框架的父接口。
- Collection接口继承树

说明:
- List接口:存储有序、可重复的数据。“动态数组”
- Set接口:存储无序、不可重复的数据。“数学中的集合”
- Map接口继承树

说明:
- Map接口:双列集合,用于存储成对的数据(key-value)。“数学中的函数”
二、Collection接口中的方法(15个)
1、说明
- 因为Collection接口是List、Set、Queue接口的父接口,所以定义在Collection接口的中方法可以用于操作子接口的实现类的对象。
2、15个方法
| 方法 | 描述 |
|---|---|
| add(Object obj) | 添加元素 |
| addAll(Collection c) | 添加另一个集合中所以元素 |
| size() | 元素个数 |
| clear() | 清空集合 |
| isEmpty() | 是否为空 |
| contains(Object obj) | 包含某个元素 |
| containsAll(Collection c) | 包含某个集合中所有元素 |
| remove(Object obj) | 删除元素 |
| removeAll(Collection c) | 差集 |
| retainAll(Collection c) | 交集 |
| equals(Object obj) | 判断集合是否相等 |
| toArray() | 转换为数组 |
| toArray(T[] a) | |
| hashCode() | 求集合的哈希值 |
| iterator() | 返回迭代器对象 |
注意事项:
想Collection接口的实现类对象中添加数据obj时,要求obj所在类重写equals()。
数组--->集合:Arrays.asList()
List arr1 = Arrays.asList(new int[]{123, 456});
System.out.println(arr1.size());//1
List arr2 = Arrays.asList(new Integer[]{123, 456});
System.out.println(arr2.size());//2
asList中是整型时,用int,默认会把数组当场一个对象。
3、Iterator迭代器接口
- Iterator是什么?
- Iterator对象成为迭代器,是设计模式的一种。主要用于遍历集合中的元素。
- 迭代器模式:提供一种方法访问一个容器(container)对象中各个元 素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。
- Iterator接口中方法
- hasNext()
- next()
- remove()遍历过程中移除某元素
- Iterator可以删除集合的元素,但是是遍历过程中通过迭代器对象的 remove方 法,不是集合对象的remove方法。
- 如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法, 再调用remove都会报IllegalStateException
- 怎么用Iterator遍历集合
//用集合中的iterator方法得到迭代器对象
Iterator iterator = coll.iterator();
//遍历集合
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//当然我们也可以用foreach来遍历,其实foreach本质也是调用了迭代器。
Iterator原理
- 得到的迭代器对象,默认指针指向第一个元素的前面
- hasNext()来判断下一位是否有元素。(在调用it.next()方法之前必须要调用it.hasNext()进行检测。若不调用,且 下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常)
- next():两个作用:①指针下移②取出指针指向的元素
注意
- 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合 的第一个元素之前。因此下面这种写法不正确
while (coll.iterator().hasNext()){
System.out.println(coll.iterator().next());
}
三、List接口
1、List接口概述
- List接口是Collection的子接口
- List被称为“动态数组”,是因为数组的局限性而代替数组的一种容器。
- 存储的元素有序、可重复。每个元素都有对应的顺序索引。
- 实现类有三个:ArrayList、LinkedList、Vector
2、ArrayList、LinkedList、Vector的异同(面试题)
- 同
- 三个类都是List接口的实现类,因此存储数据都是有序可重复的。
- 异
| 实现类 | 地位 | since | 线程安全否 | 底层 | 应用场景 |
|---|---|---|---|---|---|
| ArrayList | 主要实现类 | 1.2 | 线程不安全、效率高 | Object[] | 遍历、查找 |
| LinkedList | 1.2 | 双向链表 | 频繁插入、删除 | ||
| Vector | 古老实现类 | 1.0 | 线程安全、效率低 | Object[] |
3、源码分析(加分项)
ArrayList源码分析-----JDK7
- 创建:调用空参构造器时,底层创建一个长度为10的Object[]数组elementData
- 扩容:默认扩容为原来的1.5倍(使用移位操作),并将原来数组中的数据复制到新的数组中
- 结论:开发中使用带参构造器指定容量:
ArrayList list = new ArrayList(int capacity)
ArrayList源码分析-----JDK8
- 创建:调用空参构造器时,底层创建一个Object[]数组elementData,初始化为空{}
- 扩容:同JDK7
- 对比:jdk7中的ArrayList的对象的创建类似于单例的饿汉式,而jdk8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存。
LinkedList源码分析
- 创建:调用空参构造器时,内部声明了Node类型的first和last属性,默认值为null
- 添加:将数据封装在Node中,创建Node对象
Vector源码分析
- 创建:调用空参构造器时,底层创建一个长度为10的Object[]数组elementData
- 扩容:默认扩容为原来的2倍,并将原来数组中的数据复制到新的数组中
4、List常用方法
List除了从Collection集合继承的方法外,还有一些独有的、根据索引来操作集合元素的方法。
总结的简化版(常用的、便于记忆的总结)
| 常用方法的作用 | 方法名 |
|---|---|
| 增 | add(Object obj) |
| 删 | remove(Object obj)、remove(int index) |
| 改 | set(int index, Object obj) |
| 查 | get(int index) |
| 插 | add(int index, Object obj) |
| 长度 | size() |
| 遍历 | ①、Iterator迭代器 ②、增强for循环 ③、普通for循环 |
- 区分List中的remove方法
- list.remove(2):删除索引为2的,因为有remove(int index)的方法,直接匹配上不用自动装箱就能匹配,name何必自动装箱呢?
- list.remove(new Integer(2)):删除数据2,匹配的是remove(Object obj)的方法
四、Set接口
1、Set接口概述
- Set接口是Collection的子接口。
- Set中没有额外的方法
- Set中的元素不可重复,判断是否相等用的是equals()方法
- 实现类有HashSet、LinkedHashSet、TreeSet
2、HashSet、LinkedHashSet、TreeSet的异同
- HashSet:是Set接口的主要实现类;线程不安全;可以存储null值;
- LinkedHashSet:是HashSet的子类;可以按照添加顺序遍历,遍历效率高;
- TreeSet:可以按照添加对象的指定属性排序
- 要求1:添加的对象类型相同
- 要求2:对象的类要实现Comparable接口来进行自然排序,或者,实现Comparator接口来进行定制排序
- 自然排序中,比较两个对象是否相同的标准为(是否可添加“相同对象”):compareTo()返回0.不再是equals().
- 定制排序中,比较两个对象是否相同的标准为:compare()返回0.不再是equals().
3、理解无序、可重复
- 无序
- 指的是存储在底层数组的数据,并不是按照数组索引的顺序添加的,而是根据数据的哈希值决定的。
- 无序性,不等于随机性
- 不可重复
- 相同的元素只能添加一个。元素按照equals()判断,不能返回true。
4、添加元素的过程(以HashSet为例)
添加过程并不会单独考察,但是对于理解HashMap有很大帮助
我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素:
- 如果此位置上没有其他元素,则元素a添加成功。 --->情况1
- 如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
- 如果hash值不相同,则元素a添加成功。--->情况2
- 如果hash值相同,进而需要调用元素a所在类的equals()方法:
- equals()返回true,元素a添加失败
- equals()返回false,则元素a添加成功。--->情况3
对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储
- jdk 7 :元素a放到数组中,指向原来的元素。
- jdk 8 :原来的元素在数组中,指向元素a
- 总结:七上八下
HashSet底层:数组+链表的结构。
5、重写hashCode()和equals()方法
要求:向Set(主要指:HashSet、LinkedHashSet)中添加的数据,其所在的类一定要重写hashCode()和equals()
重写要求:重写的hashCode()和equals()尽可能保持一致性:相等的对象必须具有相等的散列码
重写两个方法的小技巧:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。
6、面试题
在List内去除重复数字值,要求尽量简单
- 可以用Set实现
//程序的输出结果
HashSet set = new HashSet();
Person p1 = new Person(1001,"AA");
Person p2 = new Person(1002,"BB"); set.add(p1);
set.add(p2);
p1.name = "CC";
set.remove(p1);
System.out.println(set);//[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}]
/*
存放p1、p2时,根据p1和p2的属性算出了hashCode来确定存放位置
p1的name改为CC后,再删除p1--->根据此时p1的属性算hashCode来找set中和p1相同的元素,此时算出来的hashCode大概率不是p1的位置,相当于没有找到,所以删除并没有成功。
*/ set.add(new Person(1001,"CC"));
System.out.println(set); //[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}]
/*
存放新建的p,是根据1001和CC来算hashCode,此时数组中这个位置空的,所以存放成功
*/
set.add(new Person(1001,"AA"));
System.out.println(set);//[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}]
/*
存放新建的p,先hashCode后和p1是一样的,再equals发现不一样,加到链表上,存放成功
*/
五、Map接口
1、Map接口概述
- Map接口继承树

- Map接口:
- 存储key-value的键值对,类似于数学中的函数
- Map实现类对比
| Map实现类 | 底层实现 | 线程 | 地位 | 特点 |
|---|---|---|---|---|
| HashMap | JDK7及以前:数组+链表 JDK8:数组+链表+红黑树 |
线程不安全 | 主要实现类 | 可以存储null的k-v |
| LinkedHashMap | 同上 | 同上 | 同上 | 可按照添加顺序遍历 |
| TreeMap | --- | --- | --- | 可排序遍历 |
| Hashtable | --- | 线程安全 | 古老实现类 | 不可存储null的k-v |
| Properties | --- | --- | --- | 常用来处理配置文件 |
2、面试题
HashMap的底层实现原理★★★★★(见下面第四点)
HashMap和Hashtable的异同
CurrentHashMap和Hashtable的异同(暂时不学)
3、Map结构的理解

Map中的key:无序的、不可重复的,使用Set存储所有的key ---> key所在的类要重写equals()和hashCode() (以HashMap为例);当然如果是LinkedHashMap还要实现排序接口
Map中的value:无序的、可重复的,使用Collection存储所有的value --->value所在的类要重写equals()
一个键值对:key-value构成了一个Entry对象。
Map中的entry:无序的、不可重复的,使用Set存储所有的entry
四、 HashMap的底层实现原理★★★★★(高频面试题)
1、JDK7
HashMap map = new HashMap():底层创建一个长度为16的数组Entry[] table。map.put(key1, value1)- 调用key1所在类的hashCode()方法计算key1的哈希值,用哈希值在计算得到在Entry[]数组中的存放位置
- 如果此位置为空,添加成功------>情况1
- 如果此位置不为空,比较key1和已经存在的数据的哈希值
- 如果key1的哈希值和已经存在的数据的哈希值不同,添加成功------>情况2
- 如果key1的哈希值和已经存在的某一个数据(key2,value2)的哈希值相同,继续调用key1所在类的equals()方法,传入参数key2进行比较
- 如果equals()返回值为false,添加成功------>情况3
- 如果equals()返回值为true,用value1替换value2
- 调用key1所在类的hashCode()方法计算key1的哈希值,用哈希值在计算得到在Entry[]数组中的存放位置
扩容:(当超出临界值且要添加数据的位置不为空时)默认扩容为原来的2倍,并复制数据到新数组
2、JDK8与JDK7的不同之处
HashMap map = new HashMap()时,底层没有直接创建数组,而是在首次put()时创建- 数组是Node[]类型,而非Entry[]类型
- JDK7底层是:数组+链表;而JDK8底层是:数组+链表+红黑树
- 形成链表时,七上八下(jdk7:新的元素指向旧的元素。jdk8:旧的元素指向新的元素)
- 当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 > 64时,此时此索引位置上的所数据改为使用红黑树存储。
3、LinkedHashMap底层实现原理
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;//能够记录添加的元素的先后顺序
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
六、Map接口常用方法
1、添加、删除、修改操作:
Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中void putAll(Map m):将m中的所有key-value对存放到当前map中Object remove(Object key):移除指定key的key-value对,并返回value
void clear():清空当前map中的所有数据
2、 元素查询的操作:
Object get(Object key):获取指定key对应的valueboolean containsKey(Object key):是否包含指定的keyboolean containsValue(Object value):是否包含指定的valueint size():返回map中key-value对的个数boolean isEmpty():判断当前map是否为空boolean equals(Object obj):判断当前map和参数对象obj是否相等
3、元视图操作的方法:
Set keySet():返回所有key构成的Set集合Collection values():返回所有value构成的Collection集合Set entrySet():返回所有key-value对构成的Set集合
4、总结常用方法:
- 添加:
put(Object key,Object value) - 删除:
remove(Object key) - 修改:
put(Object key,Object value) - 查询:
get(Object key) - 长度:
size() - 遍历:
keySet() / values() / entrySet()
七、Properties
1、配置文件
默认存放路径为当前工程下
创建配置文件的方式
- 右键工程名--->new--->File:这时要写上
.properties,如jdbc.properties - 右键工程名--->new--->Resource Bundle:这时秩序写名称就会自动补全后缀
- 右键工程名--->new--->File:这时要写上
存取数据时,建议使用
setProperty(String key,String value)方法和getProperty(String key)方法
八、Collections工具类
1、Collections概述
- Collections是一个操作Set、List、Map等集合的工具类
- Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作, 还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
2、Collections常用方法
排序操作
- 排序操作都是针对List来讲的,因为Map本身无序,何谈排序
- 返回值都是void,说明对List本身做了修改
| 方法 | 解释 |
|---|---|
| reverse(List) | 反转List中的元素 |
| shuffle(List) | 随机排序 |
| sort(List) | 自然排序 |
| Sort(List, Comparator) | 定制排序 |
| swap(List, int i, int j) | 交换 |
查询、替换
| 方法 | 解释 |
|---|---|
| Object max/min(Collection) | 返回自然排序的最大、小值 |
| Object max/min(Collection, Comparator) | 返回定制排序的最大、小值 |
| int frequency(Collection, Object) | 返回某集合中某元素的出现次数 |
| void copy(List dest, List src) | 复制 |
| boolean replaceAll(List list, Object oldVal, Object newVal) | 替换 |
- void copy(List dest, List src)中,新List容量不能小于旧List,因此要用
List dest = Arrays.asList(new Object[list.size()]);来创建
3、Collection和Collections的区别(面试题)
Java(6)集合的更多相关文章
- 【Java】集合_学习笔记
一.集合 1.集合类也称容器类,主要负责保存.盛装其他数据. 2.集合可以保存数量不确定的数据,保存具有映射关系的数据(也称关联数组). 3.Java5后提供一些多线程安全的集合类,放在java.ut ...
- java的集合框架最全详解
java的集合框架最全详解(图) 前言:数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编程中,数据结构是用类来描述的,并且包含有对该数据结构操作 ...
- 谈谈Java的集合组件
让我们一起谈谈Java的集合组件 我们在使用Java的时候,都会遇到并使用到Java的集合.在这里通过自己的理解和网上的资源对Java的集合方面的使用做一个简单的讲解和总结. Java主要分为3个集合 ...
- java.util 集合框架集合
java的集合框架为程序提供了一种处理对象组的标准方式.设计了一系列标准泛型接口: ⑴Collection ()接口,扩展了Iterable接口,位于集合层次结构的顶部,因此所有的集合都实现Colle ...
- Java基础——集合框架
Java的集合框架是Java中很重要的一环,Java平台提供了一个全新的集合框架.“集合框架”主要由一组用来操作对象的接口组成.不同接口描述一组不同数据类型.Java平台的完整集合框架如下图所示: 上 ...
- Java学习-集合(转)
在编写java程序中,我们最常用的除了八种基本数据类型,String对象外还有一个集合类,在我们的的程序中到处充斥着集合类的身影!java中集合大家族的成员实在是太丰富了,有常用的ArrayList. ...
- java的集合框架之一
java是一套很成熟的东西,很多商用的东西都喜欢用它,用的人多,稳定.不过一般也不怎么说起它,因为太常见了,私下里说,写java应用层得就像农民工,每一处都是搭积木,根据设计师的东西如何优雅地搭好积木 ...
- 浅谈Java的集合框架
浅谈Java的集合框架 一. 初识集合 重所周知,Java有四大集合框架群,Set.List.Queue和Map.四种集合的关注点不同,Set 关注事物的唯一性,List 关注事物的索引列表,Q ...
- Java之集合初探(一)
一.集合概述.区别 集合是一种容器,数组也是一种容器 在Java编程中,装各种各样的对象(引用类型)的叫做容器. 为什么出现集合类? 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的 ...
- Java面向对象 集合(下)
Java面向对象 集合(下) 知识概要: (1)Map集合的体系结构 (2)Map集合的方法 (3)HashMap TreeMap (4)集合框架中的常用工具类 ( ...
随机推荐
- centos 下安装redis 通过shell脚本
#! /bin/bash echo -e "开始安装redis服务\n" download_url=http://download.redis.io/releases/redi ...
- Codeforces Round 662 赛后解题报告(A-E2)
Codeforces Round 662 赛后解题报告 梦幻开局到1400+的悲惨故事 A. Rainbow Dash, Fluttershy and Chess Coloring 这个题很简单,我们 ...
- Spring Boot注解与资源文件配置
date: 2018-11-18 16:57:17 updated: 2018-11-18 16:57:17 1.不需要多余的配置文件信息 application.properties mybatis ...
- 腾讯云服务器简单配置web项目
如图:目前域名备案工作完成,需要将主页展示出来, 域名解析就不讲了,超级简单, 如果不理解可以加群交流,这里主要讲一下通过Apache 开启服务(80端口)对项目进行展示 1. 首先安装Apache ...
- Java数据结构-01顺序表
一.定义 线性表是一种线性结构,它是具有相同类型的n(n≥0)个数据元素组成的有限序列. 二.存储分类 1.顺序存储: ①简述:是指将线性表中的各个元素依次存放在一组地址连续的存储单元中,通常将这种方 ...
- 牛客1029A 袜子分配
题面传送门 没学过数论的蒟蒻第一次做出数学题, 这是一种乱搞的复杂做法 先来看个简单的问题, 数字1-10取1个,问包含1的方案有多少种.显然,每一个数字取到的概率是同样的, 方案数为 , su ...
- WrapperClass
* 测试包装类的基本用法: * 包装类就是把基本属性也变成对象,方便有时候用: * 八种基本属性,其他类型类似于integer,除了int-integer和char-character:其他都是原样: ...
- Appium常用操作之「微信滑屏、触屏操作」
坚持原创输出,点击蓝字关注我吧 作者:清菡 博客:oschina.云+社区.知乎等各大平台都有. 目录 一.滑屏操作 1.访问之后,马上就滑屏可以吗? 2.连续实现 2 次滑屏 3.代码 二.模拟触屏 ...
- .netcore实现jwt身份验证
前言 http协议本身是一种无状态的协议.所以客户端的每次请求,服务端是不清楚其身份的,需要客户端每次都要将身份信息传入,服务进行验证,才能达到安全验证的目的. 传统的Web用户验证:1.客户端传入用 ...
- Spring Cloud Alibaba 之 user服务
项目技术选型 Spring Boot Spring MVC MyBatis + 通用Mapper (官网信息https://mapperhelper.github.io/docs/) Spring C ...