java集合(网易大数据面试题)

网易大数据面试题

  1. 介绍一下arraylist、set、map的继承关系,画图
  2. 说一下ArrayList和LinkedList的底层实现原理和数据结构
  3. HashMap和Hashtable的区别

java集合体系


|-- Colletion(接口):实现了Iterable接口,有iterator()方法,返回一个Iterator对象

​	|--Set(接口):元素无序,不可重复

​		|--HashSet:Set接口的主要实现类;线程不安全;可以存储null

​			|--LinkedHashSet:遍历数据时可按照添加数据的顺序遍历;频繁遍历效率高于HashSet

​		|--SortedSet(接口)

​			|--TreeSet:可以按照添加对象的指定属性,进行排序

​	|--List(接口):元素有序,可重复

​		|--ArrayList:List接口的主要实现类;线程不安全,效率高;底层使用Object[] elementData[]存储

​		|--LinkedList:频繁插入删除操作,效率高;底层使用双向链表存储

​		|--Vector:List接口的古老实现类;线程安全,效率低;底层使用Object[] elementData[]存储



|-- Map(接口):双列数据

​	|--Hashtable:古老实现类;线程安全,效率低;不能存储null的key和value

​		|--Properties:常用来处理配置文件

​	|--HashMap:Map接口的主要实现类;线程不安全的,效率高;可存储null的key和value

​		|--LinkedHashMap:可以按照添加顺序进行遍历,HashMap底层结构基础上,添加一对指针,指向前一个后一个元素

​	|--SortedMap(接口)

​		|--TreeMap:保证按照添加的key-value对其进行排序;底层使用红黑树

HashMap的底层:数组+链表(jdk7)

​ :数组+链表+红黑树(jdk8)

Iterable接口与Iterator类

Iterable:接口,Collection实现了此接口,具有iterator方法,返回一个Iterator对象

Iterator:类,具有hasNext(),next()方法

对Set接口的理解

  1. 无序性不等于随机性,存储数据的顺序按照数据的哈希值决定,而不是根据索引顺序(也没有索引)

  2. 不可重复性:添加的元素按照equals()方法判断时,不能返回true

Collection源码分析

ArrayList源码分析

1.jdk7

  1. new一个对象时,创建了长度为10的Object[] elementData
  2. 扩容时,容量变为原来的1.5倍,将原有数据复制过来

2.jdk8

  1. new一个对象时,Object[] elementData初始化为{}
  2. 第一次调用add()时,底层才创建长度为10的数组,并将数据添加进去
  3. 后续操作无异

LinkedList源码分析

  1. 定义内部类Node作为保存数据的基本结构
  2. 定义Node类型的first和last,记录首末元素;双向链表

HashSet源码分析(底层使用HashMap)

  1. 底层使用数组,初始容量16,使用率超过0.75,扩大容量为原来的2倍
  2. 判断两个元素相等标准:通过hashcode()方法比较,继续比较equals()
  3. 若对象要存放在Set中,必须重写equals()和hashCode(Object obj)
  4. 后来的添加不进去

总结:

  1. 一次java应用中,同一个Object对象的hashcode必须保持一致,假定用于比较相等的信息没有改变(这个对象用于计算hashcode的属性)

  2. 如果两个对象的equals()返回true,那么hashcode必须一致

  3. 两者不equal,hashcode并不强制要求不相等。不过,严格不等的hashcode会提升hash表的性能。

也就是说:

  1. 当equals()重写,hashcode必须重写(默认只有在两者指向同一个Object,equals才会返回true);

  2. 用于equals()方法比较的Field,都应该用来计算hashCode值(一般由idea帮我们重写这两个函数)

添加元素的过程

  1. 调用hashcode()方法,计算哈希值;
  2. 根据哈希值通过某种算法计算出在底层数组中存放位置,如果该位置有其他元素比较哈希值,哈希值不同,添加成功;哈希值相同,调用equals方法,返回true添加失败,返回false添加成功
  3. 对于添加成功且原位置上有元素的情况,元素与其以链表的方式存储
    • Jdk7:新元素放到数组中,指向原来的元素
    • Jdk8:原来的元素在数组中,指向新元素(七上八下)

数组+链表的结构存储

LinkedHashSet源码分析

  1. 根据元素的hashcode来决定存储位置,同时使用双向链表维护元素的次序,使元素看起来是以插入顺序保存的
  2. 迭代访问时性能好

TreeSet源码分析

  1. 确保元素处于排序状态,两种排序方法:自然排序和定制排序。默认情况下,采用自然排序
  2. 底层使用红黑树结构存储数据
  3. 必须添加同一个类的对象
  4. 判断两个对象相等的唯一标准是:两个对象通过compareTo()比较返回值

自然排序vs定制排序

自然排序:元素必须实现Comparable接口,TreeSet调用元素的compareTo方法

定制排序:TreeSet构造器传入一个实现Comparator接口的实例

Map源码分析

Map结构的理解

  1. Map中的key:无序的,不可重复的,使用set存储所有的key(key所在的类要重写equals()和hashcode())
  2. Value:无序的,可重复的。使用Collection存储所有的value
  3. key-value构成了一个Entry对象。Map中的entry:无序的,不可重复的,使用set存储所有的entry

HashMap的底层实现原理

Jdk7 数组+链表 元素为entry

Jdk8 数组+链表+红黑树 元素为node

源码中的重要常量

DEFAULT_INITIAL_CAPACITY:默认容量16

DEFAULT_LOAD_FACTOR:默认加载因子0.75

threshold:扩容的临界值 = 容量*加载因子

TREEIFT_THRESHOLD:桶中的链表长度大于该默认值:转化为红黑树 8

MIN_TREEIFY_CAPACITYL:桶中的Node被树化时最小的hash表容量:64

  1. 添加元素以及扩容和之前HashSet添加元素的逻辑相同,因为HashSet底层使用了HashMap,Hashset要存储的元素作为key存储,value用Object Present代替
  2. 当HashMap其中一个链对象个数达到了8个,若capacity没有达到64,会先扩容。若已达到,链变为红黑树,节点类型由Node变成TreeNode

jdk8与jdk7区别

  1. new HashMap():底层没有创建一个长度为16的数组
  2. 底层数组是 ;Node[],而非Entry[]
  3. 首次调用put()方法,创建长度为16的数组
  4. 多一个红黑树;当链表数据超过8个且数组长度大于64,链表树化

LinkedHashMap

  1. HashMap的子类
  2. 在其存储结构的基础上,使用一对双向链表来记录添加元素的顺序
  3. 内部类:Entry

TreeMap

底层使用红黑树,类比TreeSet(自然排序和定制排序按照key)

常用方法

Collection

增:add(Object obj),addAll(Collection c)
删:clear(),remove(Object obj)
改:

查:size()有效元素个数,contains()

操作:iterator(),toArray()

List

提供额外关于索引的方法

增:add(int index,Object obj)

删:remove(int index)(注意:remove现在有两个重载方法了)

改:set(int index,Object obj)

查:get(int index)

Set

未提供额外方法

Map

增:put()

删:remove()/clear()

改:

查:containsKey(),containsValue(),size()

相关操作:keySet(),values(),entrySet()

Collections工具类

reverse()

posted @ 2021-11-25 20:46  somelovelanguage  阅读(124)  评论(0)    收藏  举报