- Collection是最基本的集合接口。Collection是一个接口,用以提供规范定义,不能被实例化使用
- List是可重复集合,Set是不可重复集合,这两个接口都实现了Collection父接口. Map未继承Collection,而是独立的接口, Map是一种把键对象和值对象进行映射的集合,它的每一个元素都包含了一对键对象和值对象, Map中存储的数据是没有顺序的, 其key是不能重复的,它的值是可以有重复的。Queue保持一个队列(先进先出)的顺序.
- Interface Iterable
迭代器接口,这是Collection类的父接口。实现这个Iterable接口的对象允许使用foreach进行遍历,这个Iterable接口只有一个方法: iterator()
set
- 无序,唯一
- Set判断两个对象相同不是使用"=="运算符,而是根据equals方法。
- 遍历set 有两种方式 (迭代器 增强for循环)
Set的实现类有HashSet和TreeSet;
- HashSet
HashSet是Set接口的典型实现,内部是由哈希表(实际上是一个 HashMap 实例)支持的。它不保证 set元素的迭代顺序。HashSet使用Hash算法来存储集合中的元素,因此具有良好的存取和查找性能。
- TreeSet: TreeSet使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序.,TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态
- LinkedHashSet
LinkedHashSet集合也是根据元素的hashCode值来决定元素的存储位置,但和HashSet不同的是,它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的。当遍历LinkedHashSet集合里的元素时,LinkedHashSet将会按元素的添加顺序来访问集合里的元素。
LinkedHashSet需要维护元素的插入顺序,因此性能略低于HashSet的性能,但在迭代访问Set里的全部元素时(遍历)将有很好的性能 - SortedSet
此接口主要用于排序操作,即实现此接口的子类都属于排序的子类 - EnumSet
EnumSet是一个专门为枚举类设计的集合类,EnumSet中所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式、或隐式地指定。EnumSet的集合元素也是有序的,它们以枚举值在Enum类内的定义顺序来决定集合元素的顺序
Queue
- Queue用于模拟"队列"这种数据结构(先进先出 FIFO)。队列的头部保存着队列中存放时间最长的元素,队列的尾部保存着队列中存放时间最短的元素。新元素插入(offer)到队列的尾部,访问元素(poll)操作会返回队列头部的元素,队列不允许随机访问队列中的元素。
- PriorityQueue并不是一个比较标准的队列实现,PriorityQueue保存队列元素的顺序并不是按照加入队列的顺序,而是按照队列元素的大小进行重新排序.
- Deque接口代表一个"双端队列",双端队列可以同时从两端来添加、删除元素,因此Deque的实现类既可以当成队列使用、也可以当成栈使用
- ArrayDeque 是一个基于数组的双端队列,和ArrayList类似,它们的底层都采用一个动态的、可重分配的Object[]数组来存储集合元素,当集合元素超出该数组的容量时,系统会在底层重新分配一个Object[]数组来存储集合元素
Map
Map用于保存具有"映射关系"的数据,Map的key不允许重复。
HashMap,Hashtable,TreeMap,LinkedHashMap
- HashMap: 内部存储的键值对是无序的是按照哈希算法进行排序,是非线程安全的。键或值可以为null。在JDK1.6、1.7中,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个数组中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
- Hashtable: 内部存储的键值对是无序的是按照哈希算法进行排序,是线程安全。键或者值不能为null,为null就会抛出空指针异常。
- SortedMap:Map接口也派生出一个SortedMap子接口,SortedMap接口也有一个TreeMap实现类。
- TreeMap: 基于红黑树数据结构实现, 按 key 排序,默认的排序方式是升序。每个key-value对即作为红黑树的一个节点。TreeMap存储key-value对(节点)时,需要根据key对节点进行排序。TreeMap可以保证所有的key-value对处于有序状态。同样,TreeMap也有两种排序方式: 自然排序、定制排序
- LinkedHashMap:有序的Map集合实现类,相当于一个栈,先put进去的最后出来,先进后出。同时也使用双向链表来维护key-value对的次序,该链表负责维护Map的迭代顺序,与key-value对的插入顺序一致(注意和TreeMap对所有的key-value进行排序进行区分)。
- WeakHashMap: WeakHashMap与HashMap的用法基本相似。区别在于,HashMap的key保留了对实际对象的"强引用",这意味着只要该HashMap对象不被销毁,该HashMap所引用的对象就不会被垃圾回收。但WeakHashMap的key只保留了对实际对象的弱引用,这意味着如果WeakHashMap对象的key所引用的对象没有被其他强引用变量所引用,则这些key所引用的对象可能被垃圾回收,当垃圾回收了该key所对应的实际对象之后,WeakHashMap也可能自动删除这些key所对应的key-value对
- EnumMap
EnumMap是一个与枚举类一起使用的Map实现,EnumMap中的所有key都必须是单个枚举类的枚举值。创建EnumMap时必须显式或隐式指定它对应的枚举类。EnumMap根据key的自然顺序(即枚举值在枚举类中的定义顺序)
- Hashmap与Hashtable
主要的区别有:线程安全性,同步(synchronization),以及速度。
在多线程环境下若使用HashMap可以通过下面的语句进行同步获取一个线程安全的集合HashMap:Map m = Collections.synchronizeMap(hashMap);
HashMap和Hashtable的底层实现都是数组+链表结构实现;内存初始大小不同,HashTable初始大小是11,而HashMap初始大小是16;内存扩容时采取的方式也不同,Hashtable采用的是2old+1,而HashMap是2old。
遍历Map有三种方式
- Set keySet():遍历所有的key, 将当前Map中所有的key存入到一个Set集合后返回
List
-
List的实现类有ArrayList, Vector和LinkedList、Collections.SynchronizedList、CopeOnWriteArrayList
-
ArrayList,
是基于数组实现的List类,它封装了一个动态的增长的、允许再分配的Object[]数组。 -
Vector
和ArrayList在用法上几乎完全相同,在JDK1.2以后,java提供了系统的集合框架,就将Vector改为实现List接口,统一归入集合框架体系中。Stack是Vector提供的一个子类,用于模拟"栈"这种数据结构(LIFO后进先出) -
LinkedList implements List
<E>
, Deque<E>
。
是一种可以在任何位置进行高效地插入和移除操作的有序序列,它是基于双向链表的数据结构存储数据,在做查询时会按照序号索引数据进行前向或后向遍历,查询效率偏低,是线程不安全的,允许元素为null的双向链表。即可以根据索引来随机访问集合中的元素。同时它还实现Deque接口,即能将LinkedList当作双端队列使用。自然也可以被当作"栈来使用" -
ArrayList和LinkedList相同和区别
1:ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2:对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针
3:当需要插入数据的时候,如果是在集合的前段(大概集合容量的前1/10)处插入数据时,linkedlist性能明显优于arraylist,但是!!!!当在集合的中部甚至靠后的位置插入大量数据时,arraylist的性能反而远远优于linkedlist,所以,linkedlist相较于arraylist的唯一优势在于集合前段的数据的插入
4:对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。
5:在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
6:ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
7:LinkedList:不需要扩容和预留空间,空间效率高,增删效率高,因为ArrayList要移动数据。但是,随机访问时间效率低,改查效率低
- ArrayList和Vector的区别
1:ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差。而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,索引就变慢了,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
2:这两个类都实现了List接口(List接口继承了Collection接口),他们都是有序集合,我们以后可以按位置索引号取出某个元素,HashSet之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素。
3:同步性:
Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不同步的.
4:数据增长:
ArrayList与Vector都有一个初始的容量大小,Vector默认增长为原来两倍,而ArrayList的增长策略是增长为原来的1.5倍。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。
总结:即Vector增长原来的一倍,ArrayList增加原来的0.5倍。 - ArrayList,Vector, LinkedList的存储性能和特性
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。 - 怎么实现集合中引用类型元素的自定义排序
当一个类实了Comparable接口后,接口要求必须重写方法comparaTo,该方法的作用
是定义当前对应于参数给定对象比较大小规则
方法要求返回一个整数,该整数不关注具体值,只关注取值范围,即:
当返回值>0当前对象大于参数对象
当返回值<0当前对象小于参数对象
当返回值=0两个对象相等
然后在使用时直接调用Collections.sort(list);传入要比较的集合就会按照自己定义的比 较规则进行比较.
注: 该方法在排序自定义元素时,对我们的程序有侵入性
侵入性:当我们使用一个功能时,该功能要求我们为其修改的代码越多,侵入性越强高侵入性不利于程序扩展,应尽量避免, 侵入性的弊端是一旦该功能不再需要时,之前修改的代码都不具意义,增加后期维护代码成本
重写equals方法的规则
1).如果传过来的obj是null那么就返回false
2).如果obj==this,传过来的obj和当前对象时同一个对象,返回true
3).如果obj 和当前对象是相同类型,则返回当前对象和obj的属性的比较,否则返回false
public boolean equals(Object obj){
if(obj==null){
return false;
}
if(obj==this){
return true;
}
if(obj instanceof Point){
Point p=(Point)obj;
return this.x==p.x&&this.y==p.y;
}
return false;
}
为什么要重写hashcode()和equals()
-
哈希碰撞会对hashMap的性能带来灾难性的影响。如果多个hashCode()的值落到同一个桶内的时候,这些值是存储到一个链表中的。最坏的情况下,所有的key都映射到同一个桶中,这样hashmap就退化成了一个链表——查找时间从O(1)到O(n)
-
hashcode方法.并且两个方法应满足:
1:一致性,即:当两个对象equals比较为true,那么hashcode值应当相等.反之亦然.
因为当两个对象hashcode值相等,但是equals比较为false,那么在HashMap中
会产生链表,影响查询性能.
2:成对重写,即重写equals就应当重写hashcode.
枚举(enum)
-
枚举的简介:需要在一定的范围内取值,这个值只能是这个范围内中的任意一个。
-
枚举的API
name() :返回枚举的名称
ordinal() :枚举的下标,下标从0开始
valueOf(Class enumType, String name) :得到枚举的对象 -
这两个方法是编译的时候生成两个方法
valueof(String name) 转换枚举对象
values() 获得所有枚举对象数组 -
知道枚举的对象,得到枚举名称和下标
public void test1() {
//得到枚举对象
Color100 c100 = Color100.RED;
//枚举名称
String name = c100.name();
//枚举的下标
int idx = c100.ordinal();
System.out.println(name+" "+idx);
}
- 知道枚举的名称,得到枚举的对象和下标
public void test2() {
String name1 = "GREEN";
//得到对象
Color100 c1 = Color100.valueOf(name1);
//枚举下标
int idx1 = c1.ordinal();
System.out.println(idx1);
}
- 知道枚举的下标,得到枚举的对象和名称
public void test3() {
int idx2 = 2;
//得到枚举的对象
Color100[] cs = Color100.values();
//根据下标得到对象
Color100 c12 = cs[idx2];
//得到枚举的名称
String name = c12.name();
System.out.println(name);
}