java基础之 集合容器

集合和数组的区别:

1存储元素问题:数组可以是基本类型,也可以是引用类型。集合只能是引用类型。(JDK1.5以后还可以存储基本数据类型,因为JDK1.5自动装箱拆箱)

2长度问题:数组固定,集合可变。

3是否同一类型:数组元素类型一致,集合元素类型可以不一致。

为什么会出现这么多的容器呢?

    因为每一个容器对数据的存储方式都有不同,这个存储方式称之为:数据结构。

下面介绍具体的容器:

List(列表):元素是有序的,元素可以重复,因为该集合体系有索引。

|--ArrayList:底层是数组数据结构,查询速度很快,但是增删稍慢,线程不同步,默认10个元素。(线程不同步) 

|--LinkedList:底层是链表数据结构,查询很慢,增删速度很快。(线程不同步) 

|--Vector:底层是数组数据结构,和ArrayList一样,查询,增删,都很慢,Vector是1.0出现,ArrayList是1.2出现,(线程同步)但已经不用了。

Set(集):元素是无序的(存入和取出顺序不一定一致),元素不可以重复。 

|--HashSet底层数据结构是哈希表。线程是不同步的。采用散列函数对元素进行排序Asiic),是专门为快速查询而设计的。存入HashSet的对象必须定义hashCode方法。

|--LinkedHashSet:有序。内部使用散列以加快查询速度,同时使用链表维护元素插入的次序,在使用迭代器遍历Set时,结果会按元素插入的次序显示。  

|--TreeSet:底层的数据结构是二叉树。线程是不同步的。Set集合中的元素的进行指定(我们指定的比较器)顺序的排序。不同步。TreeSet层的数据结构就是二叉树。采用红黑树的数据结构进行排序元素,使用它可以从Set中提取有序(升序或者降序)的序列。需要注意的是, 存入自定义类时,TreeSet需要维护元素的存储顺序,因此自定义类要实现Comparable接口并定义compareTo方法。 

HashSet是如何保证元素唯一性的呢? 

是通过两个方法,hashCode和equals来完成。如果元素hashCode值相同,才会判断equals是否为true。如果元素的hashCode不同,不会调用equals方法。

Map

|--Hashtable:底层是哈希表数据结构,不可以存入nullnull值。该集合是线程同步的。JDK1.0.效率低。 

此类实现一个哈希表,该哈希表将键映射到相应的值。任何非null 对象都可以用作键或值。 

为了成功地在哈希表中存储和获取对象,用作键的对象必须实现 hashCode 方法和 equals 方法。

|--HashMap:基于哈希表的Map接口的实现。此实现提供所有可选的映射操作,并允许使用null 值和null键。 

(除了非同步和允许使用null 之外,HashMap 类与Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。  Hashtable替代,JDK1.2.效率高。

 |--TreeMap:基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator(比较器) 进行排序,具体取决于使用的构造方法。 和Set很像。其实大家,Set底层就是使用了Map集合。线程不同步。可以用于给Map集合中的键进行排序。

(3)HashMapHashtable的区别?(面试题)

主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。

Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步(Collections.synchronizedMap)。 

HashMap:线程不安全,效率高。允许null键和值。

Hashtable:线程安全,效率低。不允许null键和值。

(4)为什么HashMap是不安全的

HashMap底层是一个Entry数组,当发生hash冲突的时候,hashmap是采用链表的方式来解决的,在对应的数组位置存放链表的头结点。对链表而言,新加入的节点会从头结点加入。现在假如A线程和B线程同时对同一个数组位置调用addEntry,两个线程会同时得到现在的头结点,然后A写入新的头结点之后,B也写入新的头结点,那B的写入操作就会覆盖A的写入操作造成A的写入操作丢失。

当多个线程同时操作同一个数组位置的时候,也都会先取得现在状态下该位置存储的头结点,然后各自去进行计算操作,之后再把结果写会到该数组位置去,其实写回的时候可能其他的线程已经就把这个位置给修改过了,就会覆盖其他线程的修改

当多个线程同时检测到总数量超过门限值的时候就会同时调用resize操作,各自生成新的数组并rehash后赋给该map底层的数组table,结果最终只有最后一个线程生成的新数组被赋给table变量,其他线程的均会丢失。而且当某些线程已经完成赋值而其他线程刚开始的时候,就会用已经被赋值的table作为原始数组,这样也会有问题。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值