在之前的文章中,已经发布了常见的面试题,这里我花了点时间整理了一下对应的解答,由于个人能力有限,不一定完全到位,如果有解答的不合理的地方还请指点,在此谢过。

本文主要描述的是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)相关推荐

  1. 《Java 后端面试经》Java 基础篇

    <Java 后端面试经>专栏文章索引: <Java 后端面试经>Java 基础篇 <Java 后端面试经>Java EE 篇 <Java 后端面试经>数 ...

  2. Thinking in java基础之集合框架

    Thinking in java基础之集合框架 大家都知道我的习惯,先上图说话. 集合简介(容器) 把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合,例如这里有20个苹果,我们把每一个苹果当成 ...

  3. java把map值放入vector_Thinking in java基础之集合框架

    Thinking in java基础之集合框架 大家都知道我的习惯,先上图说话. 集合简介(容器) 把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合,例如这里有20个苹果,我们把每一个苹果当成 ...

  4. 菜鸟学习笔记:Java基础篇6(数组、字符串)

    菜鸟学习笔记:Java常用类(数组.字符串) 数组 概述 数组的定义 二维数组 数组查找和排序 查找 排序 数组运用--字符串 不可变字符序列(String) 可变字符序列(StringBuilder ...

  5. 菜鸟学习笔记:Java基础篇2(变量、运算符、流程控制语句、方法)

    菜鸟学习笔记:Java基础篇2 变量 基本概念 变量作用域 final关键字 运算符 算术运算符 比较运算符 逻辑运算符 位运算符 赋值运算符 条件运算符 运算符优先级 Java三种流程控制语句 顺序 ...

  6. Java基础篇--设计模式

    目录 前言 设计模式 创建型模式 单例模式 工厂方法模式 抽象工厂模式 建造者模式 原型模式 结构型模式 适配器模式 桥接模式 组合模式 装饰模式 外观模式 亨元模式 代理模式 行为型模式: 访问者模 ...

  7. java基础篇---第一天

    今日开始在心中正式开始在培训班开始培训.一下是在培训的过程中发现自己在自学过的过程中发现的问题.这篇是java基础篇. 第一天 : 1)配置java环境变量 1.在系统变量中新建JAVA_HOME:j ...

  8. 【程序员养成之路】Java基础篇 8-流进流出的IO流(二)

    以下内容若有误,欢迎私信我或在下方留言,谢谢^_− 目录 IO流(二) 1.特殊操作流 1.1 标准流 1.2 打印流 1.3 对象序列化流 1.4 Properties 拓展1:比较字节流和字节缓冲 ...

  9. Java基础篇 学习笔记

    List item Java基础篇 学习笔记 java基础篇 第1章 计算机.程序和java概述 学习笔记 1.1什么是计算机 简单来说:计算机就是 ' 存储 ' 和 ' 处理 ' 数据的电子设备. ...

  10. 你所需要的java基础篇深入解析大汇总

    java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...

最新文章

  1. oracle 学习小结11
  2. LeetCode Unique Binary Search Trees(dp)
  3. 【转】一个安全测试的CheckList
  4. html 日期判断周几,javascript怎么根据日期判断星期几?
  5. 从需求出发来看关系模型与非关系模型–时代的变革
  6. android java项目源码_Android项目源码本站第三个知乎app项目
  7. Arpg战斗系统-技能学习篇
  8. 苹果发布蓝牙耳机新固件,耳机Find My功能越发普及
  9. An internal error occurred during: svn错误
  10. 工控机安装服务器系统,工控机驱动安装步骤及流程说明
  11. 安卓仿苹果音量调节_Android实现音量调节的方法
  12. GBase UP是做什么的
  13. 关于卸载流氓软件的通用办法
  14. DOS(bat) 字符串替换原理
  15. android 加速度计算公式,android – 计算参考真北的加速度
  16. Kinect openni 驱动
  17. DevCloud加持下的青软,让教育“智”上云端
  18. 判断一棵树是否是另一棵树的子树
  19. rhsca10.29
  20. CNAA广告企业认证

热门文章

  1. 软考中级真题 2015年上半年 系统集成项目管理工程师 应用技术
  2. 华为云用docker部署halo
  3. 新形势下安全风险评估实践
  4. 自动驾驶汽车是如何利用高精度地图和高精度定位来导航
  5. 1024程序员节活动继续:购书优惠劵,折后再折,赶紧来抢啊
  6. 如何系统磁盘和raid卡的槽位对应起来
  7. 微信小程序实现腾讯地图定位功能-demo
  8. 天气预报apipython_基于Python的免费天气预报接口查询
  9. manjaro 亮度调节
  10. php不使用第三变量互换,总结PHP不用第三个变量交换两个变量的值的几种方法