首页 > 编程语言 > 详细

Java集合

时间:2021-04-01 18:44:22      阅读:19      评论:0      收藏:0      [点我收藏+]

技术分享图片

 

说说List,Set,Map三者的区别?
List(对付顺序的好帮?): List接?存储?组不唯?(可以有多个元素引?相同的对象),有
序的对象
Set(注重独???的性质): 不允许重复的集合。不会有多个元素引?相同的对象。
Map(?Key来搜索的专家): 使?键值对存储。Map会维护与Key有关联的值。两个Key可以引?相
同的对象,但Key不能重复,典型的Key是String类型,但也可以是任何对象。
 
Arraylist 与 LinkedList 区别?
1. 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安
全;
2. 底层数据结构: Arraylist 底层使?的是 Object 数组; LinkedList 底层使?的是
双向链表 数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链
表的区别,下?有介绍到!)
3. 插?和删除是否受元素位置的影响: ① ArrayList 采?数组存储,所以插?和删除元素
的时间复杂度受元素位置的影响。 ?如:执? add(E e) ?法的时候, ArrayList 会默认
在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i
插?和删除元素的话( add(int index, E element) )时间复杂度就为 O(n-i)。因为在进
?上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执?向后位/向前移?位的
操作。 ② LinkedList 采?链表存储,所以对于 add(?E e) ?法的插?,删除元素时间复杂
度不受元素位置的影响,近似 O(1),如果是要在指定位置 i 插?和删除元素的话
( (add(int index, E element) ) 时间复杂度近似为 o(n)) 因为需要先移动到指定位置
再插?。
4. 是否?持快速随机访问: LinkedList 不?持?效的随机元素访问,? ArrayList ?
持。快速随机访问就是通过元素的序号快速获取元素对象(对应于 get(int index) ?法)。
5. 内存空间占?: ArrayList的空 间浪费主要体现在在list列表的结尾会预留?定的容量空
间,?LinkedList的空间花费则体现在它的每?个元素都需要消耗?ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。
 
ArrayList 与 Vector 区别呢?为什么要?Arraylist取代Vector呢?
Vector 类的所有?法都是同步的。可以由两个线程安全地访问?个Vector对象、但是?个线程访问
Vector的话代码要在同步操作上耗费?量的时间。
Arraylist 不是同步的,所以在不需要保证线程安全时建议使?Arraylist。
 

ArrayList扩容机制:

ArrayList扩容的核心从ensureCapacityInternal方法说起。可以看到前面介绍成员变量的提到的ArrayList有两个默认的空数组:

DEFAULTCAPACITY_EMPTY_ELEMENTDATA:是用来使用默认构造方法时候返回的空数组。如果第一次添加数据的话那么数组扩容长度为DEFAULT_CAPACITY=10。

EMPTY_ELEMENTDATA:出现在需要用到空数组的地方,其中一处就是使用自定义初始容量构造方法时候如果你指定初始容量为0的时候就会返回。

    从下面可以看到如果是使用了空数组EMPTY_ELEMENTDATA话,那么不会返回默认的初始容量。

//判断当前数组是否是默认构造方法生成的空数组,如果是的话minCapacity=10反之则根据原来的值传入下一个方法去完成下一步的扩容判断
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//minCapacitt表示修改后的数组容量,minCapacity = size + 1
private void ensureCapacityInternal(int minCapacity) {
//判断看看是否需要扩容
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
    下面谈谈ensureExplicitCapacity方法(modCount设计到Java的快速报错机制后面会谈到),可以看到如果修改后的数组容量大于当前的数组长度那么就需要调用grow进行扩容,反之则不需要。

//判断当前ArrayList是否需要进行扩容
private void ensureExplicitCapacity(int minCapacity) {
//快速报错机制
 modCount++;

// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
    最后看下ArrayList扩容的核心方法grow(),下面将针对三种情况对该方法进行解析:

当前数组是由默认构造方法生成的空数组并且第一次添加数据。此时minCapacity等于默认的容量(10)那么根据下面逻辑可以看到最后数组的容量会从0扩容成10。而后的数组扩容才是按照当前容量的1.5倍进行扩容;
当前数组是由自定义初始容量构造方法创建并且指定初始容量为0。此时minCapacity等于1那么根据下面逻辑可以看到最后数组的容量会从0变成1。这边可以看到一个严重的问题,一旦我们执行了初始容量为0,那么根据下面的算法前四次扩容每次都 +1,在第5次添加数据进行扩容的时候才是按照当前容量的1.5倍进行扩容。
当扩容量(newCapacity)大于ArrayList数组定义的最大值后会调用hugeCapacity来进行判断。如果minCapacity已经大于Integer的最大值(溢出为负数)那么抛出OutOfMemoryError(内存溢出)否则的话根据与MAX_ARRAY_SIZE的比较情况确定是返回Integer最大值还是MAX_ARRAY_SIZE。这边也可以看到ArrayList允许的最大容量就是Integer的最大值(-2的31次方~2的31次方减1)。
//ArrayList扩容的核心方法,此方法用来决定扩容量
 private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 

HashMap 和 Hashtable 的区别
1. 线程是否安全: HashMap 是?线程安全的,HashTable 是线程安全的;HashTable 内部的?法
基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使? ConcurrentHashMap
吧!);
2. 效率: 因为线程安全的问题,HashMap 要? HashTable 效率??点。另外,HashTable 基本被
淘汰,不要在代码中使?它;
3. 对Null key 和Null value的?持: HashMap 中,null 可以作为键,这样的键只有?个,可以
有?个或多个键所对应的值为 null。。但是在 HashTable 中 put 进的键值只要有?个 null,
直接抛出 NullPointerException。4. 初始容量??和每次扩充容量??的不同 : ①创建时如果不指定容量初始值,Hashtable 默认
的初始??为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化??为16。之后
每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使?
你给定的??,? HashMap 会将其扩充为2的幂次???(HashMap 中的 tableSizeFor() ?
法保证,下?给出了源代码)。也就是说 HashMap 总是使?2的幂作为哈希表的??,后?会介
绍到为什么是2的幂次?。
5. 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了??的变化,当链表?度?于
阈值(默认为8)时,将链表转化为红?树,以减少搜索时间。Hashtable 没有这样的机制。
HashMap 中带有初始容量的构造函数:
下?这个?法保证了 HashMap 总是使?2的幂作为哈希表的??。
 
HashMap 和 HashSet区别
HashSet 底层就是基于 HashMap 实现的。(HashSet 的
源码?常?常少,因为除了 clone() 、 writeObject() 、 readObject() 是 HashSet ??不得不
实现之外,其他?法都是直接调? HashMap 中的?法。
技术分享图片

 

 

HashSet如何检查重复
当你把对象加? HashSet 时,HashSet会先计算对象的 hashcode 值来判断对象加?的位置,同时也会
与其他加?的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出
现。但是如果发现有相同hashcode值的对象,这时会调? equals() ?法来检查hashcode相等的对
象是否真的相同。如果两者相同,HashSet就不会让加?操作成功。(摘?我的Java启蒙书《Head fist
java》第?版)
 
hashCode()与equals()的相关规定:
1. 如果两个对象相等,则hashcode?定也是相同的
2. 两个对象相等,对两个equals?法返回true
3. 两个对象有相同的hashcode值,它们也不?定是相等的
4. 综上,equals?法被覆盖过,则hashCode?法也必须被覆盖
5. hashCode()的默认?为是对堆上的对象产?独特值。如果没有重写hashCode(),则该class的两
个对象?论如何都不会相等(即使这两个对象指向相同的数据)。
de与equals的区别
1. ==是判断两个变量或实例是不是指向同?个内存空间 equals是判断两个变量或实例所指向的内
存空间的值是不是相同
2. ==是指对内存地址进??较 equals()是对字符串的内容进?比较
3. ==指引?是否相同 equals()指的是值是否相同
 

Java集合

原文:https://www.cnblogs.com/cyf111/p/14606801.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!