List、Set、Map有什么异同(详解)
引⾔:Java集合框架提供了⼀套性能优良、使⽤⽅便的接⼝和类,它们位于java.util包中
Java集合框架(常⽤接⼝):
演讲稿范文青春励志Collection 接⼝存储⼀组不唯⼀,⽆序的对象(⽗类接⼝)
高考乙卷List 接⼝存储⼀组不唯⼀,有序(插⼊顺序)的对象
Set 接⼝存储⼀组唯⼀,⽆序的对象
Map接⼝存储⼀组键值对象,提供key到value的映射
⼀、List接⼝
List是⼀个继承于Collection的接⼝,即List是集合中的⼀种。List是有序的队列,List中的每⼀个元素都有⼀个索引;第⼀个元素的索引值是0,往后的元素的索引值依次+1。和Set 不同,List中允许有重复的元素。实现List接⼝的集合主要有:ArrayList、LinkedList、Vector、Stack。
1.可以允许重复的对象。
2.可以插⼊多个null元素。
3.是⼀个有序容器,保持了每个元素的插⼊顺序,输出的顺序就是插⼊的顺序。
4.常⽤的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流⾏,它提供了使⽤索引的随意访问,⽽LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。
ArrayList
关于勤俭节约的名言警句ArrayList是⼀个动态数组,也是我们最常⽤的集合。它允许任何符合规则的元素插⼊甚⾄包括null。每⼀个ArrayList都有⼀个初始容量:
private static final int DEFAULT_CAPACITY = 10;
随着容器中的元素不断增加,容器的⼤⼩也会随着增加。在每次向容器中增加元素的同时都会进⾏容量检查,当快溢出时,就会进⾏扩容操作。所以如果我们明确所插⼊元素的多少,最好指定⼀个初始容量值,避免过多的进⾏扩容操作⽽浪费时间、效率。
size、isEmpty、get、t、iterator 和 listIterator 操作都以固定时间运⾏。add 操作以分摊的固定时间运⾏,也就是说,添加 n 个元素需要 O(n) 时间(由于要考虑到扩容,所以这不只是添加元素会带来分摊固定时间开销那样简单)。
ArrayList擅长于随机访问。同时ArrayList是⾮同步的。
LinkedList
同样实现List接⼝的LinkedList与ArrayList不同,ArrayList是⼀个动态数组,⽽LinkedList是⼀个双向链表。所以它除了有ArrayList的基本操作⽅法外还额外提供了
get,remove,inrt⽅法在LinkedList的⾸部或尾部。
由于实现的⽅式不同,LinkedList不能随机访问,它所有的操作都是要按照双重链表的需要执⾏。在列表中索引的操作将从开头或结尾遍历列表(从靠近指定索引的⼀端,节约⼀半时间)。这样做的好处就是可以通过较低的代价在List中进⾏插⼊和删除操作。
与ArrayList⼀样,LinkedList也是⾮同步的。如果多个线程同时访问⼀个List,则必须⾃⼰实现访问同步。⼀种解决⽅法是在创建List时构造⼀个同步的List:
List list = Collections.synchronizedList(new LinkedList(…));
Vector
与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。它的操作与ArrayList⼏乎⼀样。
Stack
Stack继承⾃Vector,实现⼀个后进先出的堆栈。Stack提供5个额外的⽅法使得Vector得以被当作堆栈使⽤。基本的push和pop⽅法,还有peek⽅法得到栈顶的元素,empty⽅法测试堆栈是否为空,arch⽅法检测⼀个元素在堆栈中的位置。Stack刚创建后是空栈。
⼆、Set接⼝
Set是⼀个继承于Collection的接⼝,Set是⼀种不包括重复元素的Collection。它维持它⾃⼰的内部排序,所以随机访问没有任何意义。与List⼀样,它同样运⾏null的存在但是仅有⼀个。由于Set接⼝的特殊性,所有传⼊Set集合中的元素都必须不同,关于API⽅⾯。Set的API和Collection完全⼀样。实现了Set接⼝的集合有:HashSet、TreeSet、LinkedHashSet、EnumSet。
1.不允许重复对象
2. ⽆序容器,你⽆法保证每个元素的存储顺序,TreeSet通过 Comparator 或者 Comparable 维护了⼀个排
序顺序。
3. 只允许⼀个 null 元素
4.Set 接⼝最流⾏的⼏个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流⾏的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接⼝,因此 TreeSet 是⼀个根据其 compare() 和 compareTo() 的定义进⾏排序的有序容器。
HashSet
HashSet堪称查询速度最快的集合,因为其内部是以HashCode来实现的。集合元素可以是null,但只能放⼊⼀个null。它内部元素的顺序是由哈希码来决定的,所以它不保证t的迭代顺序;特别是它不保证该顺序恒久不变。
TreeSet
TreeSet是⼆叉树实现的,基于TreeMap,⽣成⼀个总是处于排序状态的t,内部以TreeMap来实现,不允许放⼊null值。它是使⽤元素的⾃然顺序对元素进⾏排序,或者根据创建Set时提供的 Comparator 进⾏排序,具体取决于使⽤的构造⽅法。
LinkedHashSet
LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使⽤链表维护元素的次序。这样使得元素看起来像是以插⼊顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。LinkedHashSet在迭代访问Set中的全部元素时,性能⽐HashSet好,但是插⼊时性能稍微逊⾊于HashSet。
三、Map接⼝
销的笔顺
Map与List、Set接⼝不同,它是由⼀系列键值对组成的集合,提供了key到Value的映射。在Map中它保证了key与value之间的⼀⼀对应关系。也就是说⼀个key对应⼀个value,所以它不能存在相同的key值,当然value值可以相同。实现map的集合有:HashMap、HashTable、TreeMap、WeakHashMap。
1.Map不是collection的⼦接⼝或者实现类。Map是⼀个接⼝。
2.Map 的每个 Entry 都持有两个对象,也就是⼀个键⼀个值,Map 可能会持有相同的值对象但键对象必须是唯⼀的。
3. TreeMap 也通过 Comparator 或者 Comparable 维护了⼀个排序顺序。
4. Map ⾥你可以拥有随意个 null 值但最多只能有⼀个 null 键。
超可爱的二次元头像5.Map 接⼝最流⾏的⼏个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常⽤)
HashMap
以哈希表数据结构实现,查找对象时通过哈希函数计算其位置,它是为快速查询⽽设计的,其内部定义了⼀个hash表数组(Entry[] table),元素会通过哈希转换函数将元素的哈希地址转换成数组中存放的索引,如果有冲突,则使⽤散列链表的形式将所有相同哈希地址的元素串起来,可能通过查看HashMap.Entry的源码它是⼀个单链表结构。
HashTable科学声音
也是以哈希表数据结构实现的,解决冲突时与HashMap也⼀样也是采⽤了散列链表的形式。HashTable继承Dictionary类,实现Map接⼝。其中Dictionary类是任何可将键映射到相应值的类(如 Hashtable)的抽象⽗类。每个键和每个值都是⼀个对象。在任何⼀个 Dictionary 对象中,每个键⾄多与⼀个值相关联。Map是”key-value键值对”接⼝。 HashTable采⽤”拉链法”实现哈希表不过性能⽐HashMap要低。
TreeMap
有序散列表,实现SortedMap接⼝,底层通过红⿊树实现。
历经心血LinkedHashMap
LinkedHashMap它的特点主要在于linked,带有这个字眼的就表⽰底层⽤的是链表来进⾏的存储。相对于其他的⽆序的map实现类,还有像TreeMap这样的排序类,linkedHashMap 最⼤的特点在于有序,但是它的有序主要体现在先进先出FIFIO上。没错,LinkedHashMap主要依靠双向链表和hash表来实现的。
WeakHashMap
谈WeakHashMap前先看⼀下Java中的引⽤(强度依次递减)
1. 强引⽤:普遍对象声明的引⽤,存在便不会GC
2. 软引⽤:有⽤但并⾮必须,发⽣内存溢出前,⼆次回收
3. 弱引⽤:只能⽣存到下次GC之前,⽆论是否内存⾜够
4. 虚引⽤:唯⼀⽬的是在这个对象被GC时能收到⼀个系统通知
权字拼音
以弱键实现的基于哈希表的Map。在 WeakHashMap 中,当某个键不再正常使⽤时,将⾃动移除其条⽬。更精确地说,对于⼀个给定的键,其映射的存在并不阻⽌垃圾回收器对该键的丢弃,这就使该键成为可终⽌的,被终⽌,然后被回收。丢弃某个键时,其条⽬从映射中有效地移除,因此,该类的⾏为与其他的 Map 实现有所不同。null值和null键都被⽀持。该类具有与HashMap类相似的性能特征,并具有相同的效能参数初始容量和加载因⼦。像⼤多数集合类⼀样,该类是不同步的。
四、总结
1、List、Set都是继承⾃Collection接⼝,Map则不是
2、List特点:元素有放⼊顺序,元素可重复,Set特点:元素⽆放⼊顺序,元素不可重复,重复元素会覆盖掉,(注意:元素虽然⽆放⼊顺序,但是元素在t中的位置是有该元素的HashCode决定的,其位置其实是固定的,加⼊Set 的Object必须定义equals()⽅法,另外list⽀持for循环,也就是通过下标来遍历,也可以⽤迭代器,但是t只能⽤迭代,因为他⽆序,⽆法⽤下标来取得想要的值。)
3、Set和List对⽐:
Set:检索元素效率低下,删除和插⼊效率⾼,插⼊和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率⾼,插⼊删除元素效率低,因为会引起其他元素
位置改变。
4、Map适合储存键值对的数据
5、线程安全集合类与⾮线程安全集合类 :
LinkedList、ArrayList、HashSet是⾮线程安全的,Vector是线程安全的;
HashMap是⾮线程安全的,HashTable是线程安全的;
StringBuilder是⾮线程安全的,StringBuffer是线程安全的。
五:List、Set、Map的使⽤场景(⾯试题)
1. 如果你经常会使⽤索引来对容器中的元素进⾏访问,那么 List 是你的正确的选择。如果你已经知道索引了
的话,那么 List 的实现类⽐如 ArrayList 可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。
2. 如果你想容器中的元素能够按照它们插⼊的次序进⾏有序存储,那么还是 List,因为 List 是⼀个有
序容器,
它按照插⼊顺序进⾏存储。
3. 如果你想保证插⼊元素的唯⼀性,也就是你不想有重复值的出现,那么可以选择⼀个 Set 的实现类,⽐如
HashSet、LinkedHashSet 或者 TreeSet。所有 Set 的实现类都遵循了统⼀约束⽐如唯⼀性,⽽且还提供了额外的特性⽐如 TreeSet 还是⼀个 SortedSet,所有存储于 TreeSet 中的元素可以使⽤ Java ⾥的 Comparator 或者 Comparable 进⾏排序。LinkedHashSet 也按照元素的插⼊顺序对它们进⾏存储。
4. 如果你以键和值的形式进⾏数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、
HashMap、TreeMap 中进⾏选择。