java集合框架小结【菜鸟快速入门】:
1. 什么是框架:类库的集合
2.集合框架:用来表示和操作的统一的架构,包含了实现集合的接口与类
3.集合:存放数据的容器
集合框架包含了两部分:一部分是接口,一部分是类
4.为什么会出现接口:因为集合框架中的很多类 功能是相似的【所以用接口来规范类】
注:在"集合框架"中,接口 Map 和 Collection 在层次结构没有任何亲缘关系,它们是截然不同的。
不要简单的认为集合类机会就这些,jdk中集合类有很多这些不过是我们经常用到的而已
Collection、List、Set、Queue和Map都是接口(Interface),不是具体的类实现。
一.List [public interface List<E>extends Collection<E>]:
A.有序的集合接口,可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
B.与 set 不同,列表通常允许重复的元素。更正式地说,列表通常允许元素e1和元素e2满足e1.equals(e2).并且如果列表本身允许null 元素的话,通常它们允许多个 null 元素。难免有人希望通过在用户尝试插入重复元素时抛出运行时异常的方法来禁止重复的列表
C.List 接口在 iterator、add、remove、equals 和 hashCode 方法的协定上加了一些其他约定,更加规范了 Collection 接口中指定的约定。为方便起见,这里也包括了其他继承方法的声明
D.List 接口提供了 4 种对列表元素进行定位(索引)访问方法。列表(像 Java 数组一样)是基于 0 的。注意,这些操作可能在和某些实现(例如 LinkedList 类)的索引值成比例的时间内执行。因此,如果调用方不知道实现,那么在列表元素上迭代通常优于用索引遍历列表
E. 除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
List接口实现类很多:
AbstractList, AbstractSequentialList, ArrayList, AttributeList, CopyOnWriteArrayList, LinkedList, RoleList, RoleUnresolvedList, Stack, Vector 一般情况下主要用到的是ArrayList,和LinkedList,其他的类并不是说没用
ArrayList
ArrayList允许所有元素包括null。ArrayList没有同步
理解一:ArrayList 使用一个内置的数组来存储元素,这个数组的起始容量是10.当数组需要增长时,新的容量按如下公式获得:新容量=(旧容量*3)/2+1,也就是说每一次容量大概会增长50%。这就意味着,如果你有一个包含大量元素的ArrayList对象,那么最终将有很大的空间会被浪费掉,这个浪费是由 ArrayList的工作方式本身造成的。如果没有足够的空间来存放新的元素,数组将不得不被重新进行分配以便能够增加新的元素。
对数组进行重新分配,将会导致性能急剧下降。如果我们知道一个ArrayList将会有多少个元素,我们可以通过构造方法来指定容量。我们还可以通过trimToSize()方法在 ArrayList分配完毕之后去掉浪费掉的空间。
理解二:ArrayList是用数组实现的,它不是真正的链表,在初始化的时候它先对数组设置一个初始容量,当数组空间不够的时候,它会重新构建一个容量更大的数组,然后把先前的元素拷贝进去
不管是一还是二暂且不管他存放元素的方式。唯一一点可以确认的是它使用内置的数组
LinkedList
List接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现 List 接口外,
LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列 (deque)。此类实现 Queue 接口,为 add、poll 等提供先进先出队列操作。其他堆栈和双端队列操作可以根据标准列表操作方便地进行再次强制转换。虽然它们可能比等效列表操作运行稍快,但是将其包括在这里主要是出于方便考虑.
Vector
Vector类实现了一个动态数组。和ArrayList和相似,但是两者是不同的
Vector是同步访问的
Vector包含了许多传统的方法,这些方法不属于集合框架
Vector主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的情况。
Vector类支持4种构造方法:
1,Vector() 默认大小为10
2,Vertor(int size) 创建指定大小
3,Vector(int size,int incr) 创建指定的大小和指定增量的集合,增量表示每次增加的元素的数量
4,Vector(Collection c) 创建包含集合C元素的集合
总结:【 ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。 】
Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不 会接受这两个对象。
HashSet
HashSet有以下特点:
1,不能保证元素的排列顺序,顺序有可能发生变化
2,不是同步的
3,集合元素可以是null,但只能放入一个null
当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在
HashSet中存储位置。简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回
值相 等。注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通
过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
LinkedHashSet
LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素
看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。 LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。
TreeSet
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。
TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回 0
自然排序
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的
对象就可以比较大小。
obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是负
数,则表明obj1小于obj2。如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0
定制排序
自然排序根据集合元素的大小以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法。
三.Map
HashMap
HashMap是Map接口的一个实现类。HashMap中的方法在缺省情况下是非同步的需要额外的同步机制。但HashMap的同步问题可通过Collections
的一个静态方法得到解决:Collections.synchronizedMap(Map m),这个方法返回一个同步的Map,这个Map封装了底层的HashMap的所有方法,
使得底层的HashMap即使是在多线程的环境中也是安全的。
在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示HashMap中
没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()
方法来判断。
数据结构:
当我们往hashmap中put元素的时候,先根据key的hash值得到这个元素在数组中的位置(即下标),然后就可以
把这个元素放到对应的位置中了。如果这个元素所在的位子上已经存放有其他元素了,那么在同一个位子上的元素将以链表的形
式存放,新加入的放在链头,最先加入的放在链尾。
Hashtable
Hashtable是Dictionary的子类。Hashtable中的方法是同步的,在多线程应用程序中,不用专门的操作就安全地可以使用Hashtable了
Hashtable中,key和value都不允许出现null
[HashMap和Hashtable区别:]
第一,继承不同。
第二, HashMap 非线程安全 ; HashTabel 线程安全<span style="white-space:pre"> </span>public class Hashtable extends Dictionary implements Map
<span style="white-space:pre"> </span>public class HashMap extends AbstractMap implements Map
方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
第四,两个遍历方式的内部实现上不同。
Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
第五,哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值
第六,Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。
HashMap中hash数组的默认大小是16,而且一定是2的指数。
TreeMap
将Map中的值进行排序,其中对数字,字母,汉字都有排序。各自区别:
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
/**
* @author xiamingting
* @version V1.0
* @date 2015-12-25 下午03:21:20
*/
public class Demo {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
Map<String,String> map = new TreeMap<String,String>();
map.put("4", "2");
map.put("2", "4");
map.put("1", "5");
map.put("5", "1");
map.put("3", "3");
map.put("9", "大");
map.put("6", "啊");
map.put("8", "槽");
map.put("7", "不");
map.put("10", "A");
map.put("12", "C");
map.put("13", "D");
map.put("11", "B");
Collection col = map.values();
Iterator it = col.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
输出结果:5
A
B
C
D
4
3
2
1
啊
不
槽
大
SortedMap :
对数字排序:从大到小
对(大写)字母排序:A~Z 如果想不让英文区分大小写,则修改CollatorComparator类,找到 element1.toString()
修改为: element1.toString().toLowerCase()