集合类
Posted zhhlainan521
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了集合类相关的知识,希望对你有一定的参考价值。
Stack(堆栈)与Queue(队列)前者先进后出,后者是先进先出.
Stack也是通过数组实现的,而非链表
stack堆栈:
queue队列:
Deque是queue的子接口,定义了“双端队列”,从队列的两端都可以入栈(offer)出栈(poll)
queue Deque linkedList三者的关系?queue-->deque->linkedlist
哈希算法:HashMap会使用键对象的hashcode()找到下标,然后会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象
LinkedHashMap 是基于元素进入集合的顺序或者被访问的先后顺序排序,TreeMap 则是基于元素的固有顺序 (由 Comparator 或者 Comparable 确定)。
LinkedHashMap 是根据元素增加或者访问的先后顺序进行排序,而 TreeMap 则根据元素的 Key 进行排序。
list:可以允许重复的对象
可以插入多个null元素
是一个有序的容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序
常见的实现类有:ArrayList ,LinkedList和Vector
ArryList 便于索引的随意访问
LinkedList便于添加和删除
Vector
set:不允许重复对象
无序容器,无法保证每个元素的储存顺序,TreeSet通过Comparator或者Comparable维护一个排序的顺序
(comparator接口叫做内比较器,comparable是外比较器)
只允许一个null元素(最多包含一个null元素)
set接口最流行的几个实现类:HashSet,LinkedHashSet以及TreeSet
基于HashMap实现的HashSet
TreeSet还实现了SortedSet接口,因此TreeSet是一个根据其compare()和compareTo()的定义进行排序的有序容器
map:将键值映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射一个值
Map不是collection的子接口或者是实现类,map是一个接口
TreeMap也通过Comparator或者Comparable维护一个排序顺序
map里可以拥有随意的null值但最多只能有一个null键
map接口最流行的几个实现类HashMap,LinkedHashMap,Hashtable和TreeMap(HashMap,TreeMap最常用)
*************************************************
List:
Vector类
Vector非常类似ArrayList,但是Vector是同步的。
Stack 类,Stack继承自Vector,实现一个后进先出的堆栈。
ArryList的底层实现就是一个数组(固定大小),当数组的长度不够用的时候就会重新开辟一个新的数组,然后将原来的数据拷贝到新的数组内
扩容数组调用的方法 Arrays.copyOf(objArr, objArr.length + 1);
ArrayList就是动态数组,它提供了动态的增加和减少元素,实现了Collection和List接口,可以灵活的设置数组的大小。要注意的是ArrayList并不是线程安全的,因此一般建议在单线程中使用ArrayList。
LinkedList底层是一个链表,LinkedList是采用链表的方式来实现List接口的,是由java实现的一个双向链表,实现其增删改查操作,和数据结构中的链表的增删改查完全相同,而且插入是有序的
LinkedList 底层的数据结构是基于双向循环链表的,且头结点中不存放数据,
LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。
注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
Set:
TreeSet是JAVA中集合的一种,TreeSet 是一个有序的集合,它的作用是提供有序的Set集合。它继承于AbstractSet抽象类,实现了NavigableSet<E>,Cloneable,java.io.Serializable接口。
TreeSet是基于TreeMap实现的。TreeSet中的元素支持2种排序方式:自然排序 或者 根据创建TreeSet 时提供的 Comparator 进行排序。这取决于使用的构造方法。
TreeSet的性能比HashSet差但是我们在需要排序的时候可以用TreeSet因为他是自然排序也就是升序
TreeSet继承于AbstractSet,并且实现了NavigableSet接口。
TreeSet的本质是一个"有序的,并且没有重复元素"的集合,它是通过TreeMap实现的。TreeSet中含有一个"NavigableMap类型的成员变量"m,而m实际上是"TreeMap的实例"。
TreeSet不支持快速随机遍历,只能通过迭代器进行遍历!
HashSet继承自AbstractSet,实现了Set接口,内部使用HashMap来存储数据,数据存储在HashMap的key中,value都是同一个默认值:
HashSet的确定性,也可以理解为唯一性,是通过HashMap的put方法来保证的,往HashMap中put数据时,如果key是一样的,只会替换key对应的value,不会新插入一条数据。所以往HashSet中add相同的元素没有什么用,这里的相同是通过equals方法保证的,具体的在HashMap中细说。
HashSet的底层实现是通过Map来实现的,Set中不允许有重复的元素,类似于集合,(底层使用HashMap来保存HashSet中所有元素)
在hashset的实现的时候,通过map来实现,每次往set里添加数据,都会将数据设置为map的键值,map的值设置一个默认值,因为Map的键值不能重复, 所以添加到set内的数据也不能重复。
HashSet就是限制了功能的HashMap,所以了解HashMap的实现原理,这个HashSet自然就通
对于HashSet中保存的对象,主要要正确重写equals方法和hashCode方法,以保证放入Set对象的唯一性
虽说时Set是对于重复的元素不放入,倒不如直接说是底层的Map直接把原值替代了
HashSet没有提供get()方法,原理是同HashMap一样,Set内部是无序的,只能通过迭代的方式获得
实现了Set接口
HashSet依赖的数据结构是哈希表
因为实现的是Set接口,所以不允许有重复的值
插入到HashSet中的对象不保证与插入的顺序保持一致。对象的插入是根据它的hashcode
HashSet中允许有NULL值
HashSet也实现了Searlizable和Cloneable两个接口
LinkedHashSet是继承自HashSet,底层实现是LinkedHashMap。并且其初始化时直接super(......),遍历序和插入序是一致的。
Map:
HashMap底层是一个数组+链表的实现,其基本的原理是:定义一个linkedList的数组,然后将数组储存到这个链表数组内。
HashMap的工作原理:HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。
当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,然后找到bucket位置来储存值对象。
当我们用get()方法获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。
当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,然后会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象
HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。
HashMap在每个链表节点中储存键值对对象。
优化:
1.使用不可变的、声明作final的对象,并且采用合适的equals()和hashCode()方法的话,将会减少碰撞的发生,提高效率。
不可变性使得能够缓存不同键的hashcode,这将提高整个获取对象的速度,使用String,Interger这样的wrapper类作为键是非常好的选择。
HashTable:
Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。
Hashtable 继承于Dictionary,实现了Map接口。Map是"key-value键值对"接口,Dictionary是声明了操作"键值对"函数接口的抽象类
Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。
Hashtable 的实例有两个参数影响其性能:初始容量 和 加载因子。
容量 是哈希表中桶 的数量,初始容量 就是哈希表创建时的容量
加载因子 是对哈希表在其容量自动增加之前可以达到多满的一个尺度。
通过“拉链法”解决哈希冲突的
因为Hashtable数据存储数组 private transient Entry[] table;
所以Hashtable中的key-value都是存储在table数组中的。
TreeMap:
TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。
TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合。
TreeMap 实现了NavigableMap接口,意味着它支持一系列的导航方法。比如返回有序的key集合。
TreeMap 实现了Cloneable接口,意味着它能被克隆。
TreeMap 实现了java.io.Serializable接口,意味着它支持序列化。
TreeMap基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序
TreeMap是非同步的。 它的iterator 方法返回的迭代器是fail-fastl的
LinkedHashMap:有序的map,linkedhashmap的元素取出的速度,和put的顺序一致
*****************************************
循环List列表的三种方式:
1)使用普通for循环,用get方法获取;
for(int i=0; i<userlist.size(); i++){
System.out.print(userlist.get(i)+" ");
}
2)使用Iterator迭代器,使用next方法遍历;
Iterator it = userlist.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
}
3)使用增强for循环,直接输出! 由此可见第三种方法是最方便,最简洁的!
for(String s : userlist){
System.out.print(s+" ");
}
***************************
1.HashTable和HashMap的区别
1)HashTable线程安全,同步,但是效率低下,HashMap线程不安全,非同步,效率相对高,
2)父类:hashTable的父类是Dictionary hashMap的父类是AbstractMap
3)HashTable的键和值不能为空,hashmap键最多一个为null,值可以有多个空
2.面试题:什么场景下使用list,set,map呢?
(或者会问为什么这里要用list、或者set、map,这里回答它们的优缺点就可以了)
答:
如果你经常会使用索引来对容器中的元素进行访问,那么 List 是你的正确的选择。如果你已经知道索引了的话,那么 List 的实现类比如 ArrayList 可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。
如果你想容器中的元素能够按照它们插入的次序进行有序存储,那么还是 List,因为 List 是一个有序容器,它按照插入顺序进行存储。
如果你想保证插入元素的唯一性,也就是你不想有重复值的出现,那么可以选择一个 Set 的实现类,比如 HashSet、LinkedHashSet 或者 TreeSet。所有 Set 的实现类都遵循了统一约束比如唯一性,而且还提供了额外的特性比如 TreeSet 还是一个 SortedSet,所有存储于 TreeSet 中的元素可以使用 Java 里的 Comparator 或者 Comparable 进行排序。LinkedHashSet 也按照元素的插入顺序对它们进行存储。
如果你以键和值的形式进行数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、HashMap、TreeMap 中进行选择。
3.在删除可插入对象的动作时,为什么ArrayList的效率会比较低呢?
解析: 因为ArrayList是使用数组实现的,若要从数组中删除或插入某一个对象,需要移动后段的数组元素,从而会重新调整索引顺序,调整索引顺序会消耗一定的时间,所以速度上就会比LinkedList要慢许多. 相反,LinkedList是使用链表实现的,若要从链表中删除或插入某一个对象,只需要改变前后对象的引用即可!
以上是关于集合类的主要内容,如果未能解决你的问题,请参考以下文章