Java集合框架总结

Java的集合框架分为Collection接口和Map接口。
Collection接口分为List接口和Set接口。
List接口存储有序的、可重复的数据。ArrayList、LinkedList、Vector。
Set接口存储无序的、不可重复的数据。HashSet、LinkedSet、TreeSet。
Map是双队集合,用来存储一一映射的一对数据。HashMap、LinkedHashMap(HashMap子类)、TreeMap、Hashtable、Properties(Hashtable子类)。

ArrayList、LinkedList、Vector的异同:
同:三者都是List接口实现类,存储数据都是有序的、可重复的。
不同:ArrayList:线程不安全、效率高;底层用Object[ ]存储。查找效率高,插入、删除
LinkedList:底层用双向链表存储。查找效率低
Vector:线程安全,效率低;底层用Object[ ]存储。

HashSet:是Set接口的主要实现类,线程不安全。
LinkedSet:作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历。
TreeSet:底层是红黑树。可以按照添加对象的指定属性进行排序。添加的对象要是一个类。

HashMap:线程不安全,效率高;存储的key和value可为null
LinkedHashMap(HashMap子类):在HashMap基础上添加了两个指针,能够根据添加的顺序实现便利。(需要遍历多的时候用)
TreeMap:能够按照添加的key-value进行排序实现排序的遍历。此时考虑key的自然排序或定制排序。底层使用红黑树。
Hashtable:线程安全,效率低;存储的key和value不可为null(任一都不行)
Properties(Hashtable子类):常用来处理配置文件。key和value都是String类型。

一、Collection接口中的常用方法

add(xxx):添加元素到集合中。
addAll(Collection):将另一集合的所有元素添加到这个集合中。
isEmpty():判断内部是否有元素。
clear():清空内部元素。
contains(xxx):查看集合内是否有这个对象。(注意:实际上调用的是equals方法来比对,xxx.equals(集合元素)往下挨个对比。如果里面是两个new的String,返回true,因为String重写了equals)
containsAll(Collection):判断Collection的所有元素是否在这个集合中。
remove(xxx):如果有xxx则移除。返回值为boolean。
removeAll(Collection):移除当前集合中的所有Collection中的元素。返回值为boolean。
retainAll(Collection):当前集合修改为二者交集。返回值boolean。
equals(Collection):判断两个集合是否完全相同(注意需要考虑Collection是否有序)。
hashCode():返回当前对象的hash值。
toArray():返回一个Object数组。集合转数组。
数组转集合:Arrays.asList()。注意这个方法传入形参为new int[ ]{ }这样时,默认为这是一个元素,但是如果int换为Integer就能正确识别。

迭代器:迭代器是专门为容器服务的。
建造:Iterator iterator=集合实例.iterator(); 集合对象每调用一次iterator()返回一个迭代器,默认游标在第一个元素之前。
方法:next方法() 指向下一个元素,输出当前元素。(iterator一开始指向的是第一个元素之前)
hasNext();看有没有下一个元素,返回值boolean。

迭代器还有remove方法来删除集合中的元素。但是如果未调用next()或上一次调用next方法后已经用了remove发给发,在调用remove就会报异常。

JDK5.0开始可以使用foreach来遍历集合。

二、ArrayList源码分析

JDK7时:

底层是Object[ ]。
空参构造:创建一个容量为10的Object[ ]。
添加时先确定添加是否超出容量,如果没超出直接添加,如果超出先扩容,扩充大小为oldsize+oldsize>>1(如果这还不够,直接拿传进来的大小进行扩容,此外还存在溢出情况),扩容后原数组元素copy过来。
有参构造传入初始容量,底层直接创建容量为指定大小的数组,不用慢慢扩容。

JDK8时的变化:

空参构造:一开始创建时候底层并没有创建出来数组。
添加时:第一调用时候创建容量为10的数组,将元素添加进去。
后续添加扩容与JDK7相同。

总结:JDK7时候类似单例模式的饿汉式创建。JDK8候类似单例模式的懒汉式创建延迟数组创建,节省了内存。

三、LinkedList源码分析

底层为双向链表链表。每个节点都有两个指针,一个指向前一节点一个指向后一节点。
当构造器new之后,内部声明Node类型的first和last属性,默认值为null。
添加节点删除节点只需要调整前后节点、自身节点的指针即可。

四、Vector源码分析

底层和ArrayListJDK7.0时一样。扩容时每次扩容为二倍。

五、List接口的方法

void add(int index, Object ele):index位置添加ele。
boolean addAll(int index, Collection):从index位置插入Collection中所有元素。
Object get(int index):获取指定索引元素。
int indexOf(Object):obj首次出现位置,不存在返回-1。
int lastIndexOf(Object):obj最后一次出现位置,不存在返回-1。
Object remove(int index):移除指定索引元素并返回。(注意和Collection接口的remove进行区分)
Object set(int index,Object ele):设置指定索引元素。
List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex的子集合。

六、Set接口

无序性:不等于随机性,只是存储的先后顺序不是添加顺序。
不可重复性:equals判断相同的元素只有一个。

七、HashSet

底层是HashMap。底层创建的数组长度为16.JDK7.0时new 就创建,JDK8.0时第一次add时候创建。
添加元素的过程:添加a过程:调用a类的hashCode()计算a的hash值。之后根据散列算法得到存放的HashMap数组中的位置。如果该位置没有元素,则添加a。如果存在元素调用a类的equals()方法。如果为true,则添加失败。如果为false,则以链表的情况存储a。其中7.0采用头插法8.0采用尾插法。
此外,如果使用率超过0.75,就会扩大容量为原来的2倍。
(因此要注意重写equals方法和hashCode方法)
equals相等的要保证hashcode相等,但hashcode相等的equals不一定为true。

八、LinkedHashSet

在HashSet的基础上每个节点又额外维护了两个指针来指向其添加的前后元素。好处对于频繁的遍历操作,LinkedHashSet的效率高于HashSet。

九、TreeSet

TreeSet:底层是红黑树。可以按照添加对象的指定属性进行排序。添加的对象要是一个类,不能添加不同类的对象。另外添加的类要实现Comparable接口,指定排序的方法。
另外,TreeSet中自然排序的比较用的是添加的类中实现的Comparable接口的compareTo,compareTo返回0的就认为是一个对象。
定制排序中(传入set构造器Comparator接口实现类):对比标准为compare方法。

十、Map的理解及常用方法

key无序不可重复,value无序但可重复
以HashMap为例,要重写key的equals方法和hashCode方法。
Object put(key,value):添加键值对
void putAll(Map):Map放到当前map
Object remove(key):移除指定键值对,返回value
void clear():情况map
Object get(key):通过key得到value
boonlean cotainsKey(key):是否包含key
boonlean cotainsValue(value):是否包含value
int size():返回键值对个数
boolean isEmpty():判断map是否为空
boolean equals(Object):判断map和Object是否相等
Set keySet():返回key的set集合
Collection values():返回value的Collection集合
Set entrySet():返回所有key-value对构成的Set集合,每个元素为一个Node。

十一、HashMap

JDK1.7的时候是先扩容后插入,而在JDK1.8的时候则是先插入后扩容

JDK7.0

底层:JDK7数据+链表
通过无参构造实例化底层创建了长度为16的一维数组Entry[ ] table。
当put(key,value)时,调用key所在类的hashcode方法计算哈希值,通过某种散列算法后得到存放到数组中的位置。
如果此位置数据为空,则直接添加成功。
如果不为空(有一个或多个数据链表链表形式存在),比较key和已存在的数据的哈希值。如果哈希值都不同,则添加成功。如果有相同,调用key所在类的equals方法。如果为false,添加成功。如果true,新的值替换旧的值。
在JDK7.0时候,链表添加使用的是头插法。
默认扩容方式为旧容量的二倍,默认填充因子0.75。

JDK8.0

JDK8数据+链表+红黑树
new HashMap()底层没有创建数组,当首次调用put方法时,底层创建长度16的Node[ ]数组。
当数组的某一个索引位置上的元素以链表形式存在的数据个数>8,且当前数组的长度>64时(如果不>64则扩容当前数组),此时此索引位置上的数据改用红黑树存储。
默认扩容方式为旧容量的二倍,默认填充因子0.75。
当红黑树上的节点数量小于6个,会重新把红黑树变成单向链表数据结构。(为了避免频繁的在链表和树之间切换)
但是树形结构是需要实现Comparable的才能进行排序,如果放入的对象的该类没有实现Comparable接口怎么办?class类名来进行string的排序。如果类名也相同 ,那么会按照对象的hashcode来进行比较排序。
为什么不直接用红黑树:单个 TreeNode 需要占用的空间大约是普通 Node 的两倍,所以只有当包含足够多的 Nodes 时才会转成 TreeNodes,这个足够多的标准就是由 TREEIFY_THRESHOLD 的值(默认值8)决定的。而当桶中节点数由于移除或者 resize (扩容) 变少后,红黑树会转变为普通的链表,这个阈值是 UNTREEIFY_THRESHOLD(默认值6)。
为什么阈值是8:如果 hashCode的分布离散良好的话,那么红黑树是很少会被用到的,因为各个值都均匀分布,很少出现链表很长的情况。在理想情况下,链表长度符合泊松分布,各个长度的命中概率依次递减,注释中给我们展示了1-8长度的具体命中概率,当长度为8的时候,概率概率仅为0.00000006,这么小的概率,HashMap的红黑树转换几乎不会发生,因为我们日常使用不会存储那么多的数据。

HashMap和HashTable区别:

1、继承的父类不同:Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。
2、线程安全性不同:Hashtable 线程安全,因为它每个方法中都加入了Synchronize。
3.HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey。 Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。
4. Hashtable中,key和value都不允许出现null值。HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。
5. 哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
6. 内部实现使用的数组初始化和扩容方式不同。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。

十二、LinkedHashMap

每个节点都多出了before和after能够按照添加顺序遍历。

十三、TreeMap

底层是红黑树。TreeMap中添加key-value要求key必须是同一个类创建的对象。因为要按照key进行排序。具体和TreeSet一样。

十四、Properties

key和value都是String类型。常用来处理配置文件。
使用:方式1

Properties pro=new Properties();
FileInputStream fis=new FileInputStream(文件);
pros.load(fis);
String name= pros.getProperty("name");

方式2:

ClassLoader classLoder=当前类.class.getClassLoader();
InputStream is=classLoader.getResourceAsStream(文件路径);
pros.load(is);
String name= pros.getProperty("name");
``

十五、Collections

Collections是一个工具类。
reverse(List):反转List中元素的顺序
shuffle(List):对List集合元素进行随机排序
sort(List):根据元素的自然顺序对指定List 集合元素按升序排序
sort(List, Comparator): 根据指定的Comparator产生的顺序对List集合元素进行排序
swap(List, int,int): 将指定list集合中的i处元素和j处元素进行交换
object max(Collection): 根据元素的自然顺序,返回给定集合中的最大元素
object max(Collection, Comparator): 根据Comparator指定的顺序,返回给定集合中的最大object min(ColLection)
Object min( Comparator)
Object min(Collection, Comparator)
int frequency(Collection, object): 返回指定集合中指定元素的出现次数
void copy(List dest,List src):将src中的内容复制到dest中
boolean replaceALL(List list, Object oldVaL, object newVal):使用新值替换List的旧值。

此外还有得到线程安全的容器的方法:返回相应的线程安全的容器。
synchronizedCollection(Collection)
synchronizedList(List)
synchronizedMap(Map)
synchronizedSet(Set)
synchronizedSortedMap(SortedMap)
synchronizedSortedSet(SortedSet)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值