Java基础篇--集合(collection)
在之前的文章中,已经发布了常见的面试题,这里我花了点时间整理了一下对应的解答,由于个人能力有限,不一定完全到位,如果有解答的不合理的地方还请指点,在此谢过。
本文主要描述的是java面试中几乎必问的集合内容,java的集合是jdk里面重要的内容,也是我们平时开发过程中最常用到的,所以无论是否为了准备面试,我们都要掌握好集合相关的知识。既然是重点,那就意味着集合类在java面试中的题目会非常多,尤其是hashmap,由于其设计精美,细节优化突出,常常是面试中集合的首选,所以我会把hashmap单独使用一篇文章来记录。
能简单说明一下你了解的集合么?
Java的集合分为两大类,collection和map。Collection是一组数据集合类型,可以理解为动态数组。其下包含list和set两个大类,List和set的最大区别是是否可以有重复元素,list是一组有序的可重复的数组,set是一组无序的不可重复的数组。Map是存入键值对,是一种key-value的形式。Map底下有两个大的实现类treemap和hashmap。具体看下图为集合类中常用的集合图,在介绍的时候,我们一般介绍常用的就行。
说说ArrayList、linkedlist、vector的区别?
其实三者都是collection接口下面的,都是动态数组。具体的差异点如下表:
ArrayList |
Linkedlist |
Vector |
|
底层实现 |
数组 |
链表 |
数组 |
线程安全 |
不安全 |
不安全 |
安全 |
使用频次 |
最高 |
较高 |
不使用 |
扩容 |
增加0.5倍 |
链表,没有扩容概念 |
增加1倍 |
Vector是早期jdk实现的线程安全的集合,其实现基本是在ArrayList的方法上加上了锁同步,导致性能下降,现在基本已经使用concurrent系列替换了。ArrayList和linkedlist的核心区别在于底层实现,ArrayList基于数组的实现存在扩容机制,同时数组可以随机访问0(1),如果是尾部添加元素的话也是o(1)。如果是中间某个位置添加元素的话,arraylist调用的是系统拷贝函数(System.arraycopy),会把后面的内容一次性全部往后挪一位,所以时间复杂度也是o(1),当然了删除也类似,这样添加和删除也基本实现了o(1),而linkedlist的优势在于随机位置的删除和添加,但是它在找到哪个位置的时候,是线性的,所以基本上linkedlist在访问和删除上已经没有什么优势了,扩容可能是它的唯一优势。没有什么特殊情况,我们一般都是使用arraylist,也很少使用linkedlist和vector。
说说hashset和treeset的区别?
其实这两者底层是hashmap和treemap的延伸,所以两种在区别上和hashmap和treemap一致。Hashset是以hash表为主要的存储结构,treeset底层是以红黑树为主要结构存储的。Hashset是以key的hashcode值和equals方法来确定顺序的,而treeset是通过Comparable(外部比较器)和Comparator(内部比较器)来指定顺序的。
如何在循环中安全的删除一个ArrayList的数据?
这是一个基本的操作了,直接给出正确的删除方法哈,如下:
public static void main(String[] args) throws Exception {List<String> list = new ArrayList<>();list.add("1");list.add("1");//使用for循环删除 删不全,删除不了,不可取for (int i =0;i<list.size();i++){//删除之后,size为1,i也为1,所以直接退出循环if (list.get(i).equals("1")){list.remove(i);//删除一个之后,size变为1}}//----------------------------------------List<String> list1 = new ArrayList<>();list1.add("1");list1.add("1");//1.8之前 使用迭代器删除 可以删除Iterator<String> iterator = list1.iterator();while (iterator.hasNext()){if (iterator.next().equals("1")){iterator.remove();}}//-------------------------------------------------List<String> list2 = new ArrayList<>();list2.add("1");list2.add("1");//1.8 版本之后 使用removeIf 可以删除list2.removeIf(s -> s.equals("1"));//底层实现就是迭代器}
Jdk1.8之前使用迭代器,1.8之后使用removeif函数。
说说你理解的fail-fast和fail-safe?
fail-fast是java一种快速判断是否存在多线程操作集合的一种机制。在使用迭代器对集合进行遍历过程中,一旦发现容器的数据被修改,就会抛出concurrentModificationException异常导致遍历失败。常见于hashmap和ArrayList的实现中。我们看下ListItr是怎么判断是否有修改。
private class Itr implements Iterator<E> {int expectedModCount = modCount;//初始值相等//快速判断主要在判断修改的数据和期待修改的是否一致final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}}
expectedModCount在迭代器中除了将modCount的值赋值之外,没有其他的修改,那就意味着如果要不等,那就是modCount的值已经修改了,而modCount 的值修改意味着其他线程在调用list的add或者remove的操作。
Fail-safe是基于集合的克隆进行处理的,当容器的值修改之后,克隆的集合并不会受到影响。在concurrent包中基本都是fail-safe的。这个是一个cow(copy on write)原理的应用。其优点是不会触发concurrentModificationException,但是其遍历的是当时集合的一个快照,如果数据同时在这个时候添加就无法遍历了。
说说ArrayList的扩容机制?
直接上源码分析一下:
//入参:扩容之后的最小值private void grow(int minCapacity) {// 原来的容量int oldCapacity = elementData.length;//新的容量是原来的1.5倍,这里右移1位类似除以2.jdk源码有很多位运算int newCapacity = oldCapacity + (oldCapacity >> 1);//1.5倍后比最小值还小,直接变成最小值if (newCapacity - minCapacity < 0)newCapacity = minCapacity;// 是否大于定义的最大值,如果大于就是整型的最大值,否则就是MAX_ARRAY_SIZEif (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// 数据拷贝,使用系统拷贝函数elementData = Arrays.copyOf(elementData, newCapacity);}
从源码上分析,扩容经过了几步判断:直接是原来的1.5 -》和入参比较-》和maxARRAY比较。
说说hashset是怎么保证元素唯一的?
这个我们还是直接从源码入手进行分析,我们先看下添加一个元素的流程。
public boolean add(E e) {return map.put(e, PRESENT)==null;//如果存在,返回oldvalue,不存在,返回null}//底层是hashmap,我们看下hashmap的实现,value是一个固定的objectpublic V put(K key, V value) {return putVal(hash(key), key, value, false, true);}final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {//...//判断是否存在,hash 值和equals的方法都要相等if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;//... }
从上面的流程看出,如果hash和equals都相等的话,那就认为是存在了。这个会在 hashmap中重点说明一下putval方法。
comparable 和 Comparator的区别是什么?
Comparator在包java.util下,而Comparable在包java.lang下。Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序。Comparble是一个对象支持的比较需要实现的接口,比如string,Byte都有实现这个接口。当一个对象定义的比较方法无法满足要求时,这个时候,我们可以考虑实现comparator接口,这就是两种的区别所在。
下面我们举个例子来说明一下:
public static void main(String[] args) throws Exception {Test test1 = new Test(1,2);Test test2 = new Test(2,1);Test[] testArray = new Test[]{test1,test2};Arrays.sort(testArray);//结果顺序test1,test2Arrays.sort(testArray,new ComparatorTest());//结果顺序test2,test1}//定义新的比较函数,不用去修改类public static class ComparatorTest implements Comparator<Test>{@Overridepublic int compare(Test o1, Test o2) {return o1.b.compareTo(o2.b);}}//定义类的比较函数public static class Test implements Comparable<Test>{private Integer a;private Integer b;Test(int a,int b){this.a = a;this.b = b;}@Overridepublic int compareTo(Test o) {return this.a.compareTo(o.a);}}
在上面的例子中,定义一个test类,定义类的同时定义了comparable接口,实现类内比较。又定义了一个ComparatorTest类,用于那些类无法满足的比较器。
本文介绍的集合侧重点在集合的collection,下一节我们会重点介绍map,尤其是hashmap。如果有时间的话,建议看下jdk源码的集合类,如果有问题的话,可以看下公众号里面的源码解析或者留言一起探讨哈。
本文的内容就这么多,如果你觉得对你的学习和面试有些帮助,帮忙点个赞或者转发一下哈,谢谢。
想要了解更多java内容(包含大厂面试题和题解)可以关注公众号,也可以在公众号留言,帮忙内推阿里、腾讯等互联网大厂哈
Java基础篇--集合(collection)相关推荐
- 《Java 后端面试经》Java 基础篇
<Java 后端面试经>专栏文章索引: <Java 后端面试经>Java 基础篇 <Java 后端面试经>Java EE 篇 <Java 后端面试经>数 ...
- Thinking in java基础之集合框架
Thinking in java基础之集合框架 大家都知道我的习惯,先上图说话. 集合简介(容器) 把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合,例如这里有20个苹果,我们把每一个苹果当成 ...
- java把map值放入vector_Thinking in java基础之集合框架
Thinking in java基础之集合框架 大家都知道我的习惯,先上图说话. 集合简介(容器) 把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合,例如这里有20个苹果,我们把每一个苹果当成 ...
- 菜鸟学习笔记:Java基础篇6(数组、字符串)
菜鸟学习笔记:Java常用类(数组.字符串) 数组 概述 数组的定义 二维数组 数组查找和排序 查找 排序 数组运用--字符串 不可变字符序列(String) 可变字符序列(StringBuilder ...
- 菜鸟学习笔记:Java基础篇2(变量、运算符、流程控制语句、方法)
菜鸟学习笔记:Java基础篇2 变量 基本概念 变量作用域 final关键字 运算符 算术运算符 比较运算符 逻辑运算符 位运算符 赋值运算符 条件运算符 运算符优先级 Java三种流程控制语句 顺序 ...
- Java基础篇--设计模式
目录 前言 设计模式 创建型模式 单例模式 工厂方法模式 抽象工厂模式 建造者模式 原型模式 结构型模式 适配器模式 桥接模式 组合模式 装饰模式 外观模式 亨元模式 代理模式 行为型模式: 访问者模 ...
- java基础篇---第一天
今日开始在心中正式开始在培训班开始培训.一下是在培训的过程中发现自己在自学过的过程中发现的问题.这篇是java基础篇. 第一天 : 1)配置java环境变量 1.在系统变量中新建JAVA_HOME:j ...
- 【程序员养成之路】Java基础篇 8-流进流出的IO流(二)
以下内容若有误,欢迎私信我或在下方留言,谢谢^_− 目录 IO流(二) 1.特殊操作流 1.1 标准流 1.2 打印流 1.3 对象序列化流 1.4 Properties 拓展1:比较字节流和字节缓冲 ...
- Java基础篇 学习笔记
List item Java基础篇 学习笔记 java基础篇 第1章 计算机.程序和java概述 学习笔记 1.1什么是计算机 简单来说:计算机就是 ' 存储 ' 和 ' 处理 ' 数据的电子设备. ...
- 你所需要的java基础篇深入解析大汇总
java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...
最新文章
- oracle 学习小结11
- LeetCode Unique Binary Search Trees(dp)
- 【转】一个安全测试的CheckList
- html 日期判断周几,javascript怎么根据日期判断星期几?
- 从需求出发来看关系模型与非关系模型–时代的变革
- android java项目源码_Android项目源码本站第三个知乎app项目
- Arpg战斗系统-技能学习篇
- 苹果发布蓝牙耳机新固件,耳机Find My功能越发普及
- An internal error occurred during: svn错误
- 工控机安装服务器系统,工控机驱动安装步骤及流程说明
- 安卓仿苹果音量调节_Android实现音量调节的方法
- GBase UP是做什么的
- 关于卸载流氓软件的通用办法
- DOS(bat) 字符串替换原理
- android 加速度计算公式,android – 计算参考真北的加速度
- Kinect openni 驱动
- DevCloud加持下的青软,让教育“智”上云端
- 判断一棵树是否是另一棵树的子树
- rhsca10.29
- CNAA广告企业认证