1.java集合框架概述

java集合就像是一种容器,可以动态的把多个对象的引用放入容器中。它可以存贮数量不等的多个对象,还可以用于保存具有映射关系的关联数组。

Java集合可分为Collection和Map两个体系

Collection接口:单列数据,定义了存取一组数组对象的方法的集合。(List:元素有序,可重复; Set:元素无序,不可重复)

map:双列数据,保存具有映射关系的“Key-value”的集合;

Collection继承树

Java集合的交集 java集合join_集合


map继承树

Java集合的交集 java集合join_List_02

2.Collection接口

Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。

add(Object obj): 
addAll(Collection co): 添加

int size(): 获取有效元素的个数
void clear(): 清空集合
boolean isEmpty(): 判断是否是空集合
boolean contains(Object onj): 是通过元素的equals方法来判断是否是同一个对象
boolean containsAll(): 也是调用equals方法计较

boolean remove(Object obj): 通过元素的equals方法判断是否是要删除的那个元素。只会删除找到的第一个元素

boolean equals(Object obj): 判断集合是否相等
Object[] toArray(): 转成对象数组
hashCode(): 获取集合对象的哈希值

iterator(): 返回迭代器对象,用于集合遍历

3.Iterator迭代器

Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
Collection接口继承了java.lang.Iterator接口,该接口有一个iterator方法,那么所有实现了Cllocation接口的集合类都会有一个Iterator方法,用于返回实现了Iterator接口的对象。
Iterator仅用于遍历集合,Iterator本身并不提供承装对象的能力。如果需要创建Iterator对象,则必须有一个被迭代的集合。
集合对象每次调用Iterator方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。

hasNext(): 判断是否还有下一个元素
next(): 指针下移,且将下移后集合位置上的元素返回

在调用next方法之前,必须调用hasNext方法,否则可能会出现NoSuchElementException异常。

Iterator iter = coll.iterator();
while(iter.hasNext()){
	Object obj = iter.next();
	if(Obj.equals("Love")){
		iter.remove();//迭代器对象的remove方法可以删除集合的元素。
	}
}

如果还没有调用next方法或在调用next方法之后已经调用了remove方法,再调用remove方法都会报异常。

4.Collection子接口之一:List接口

list接口概述:
鉴于Java中数组用来存储数据的局限性,我们通常使用List替代数组。
List集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引。
List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
JDK API中List接口的实现类常用的有:ArrayList、LinkedList和Vector。

//List接口的一些方法
void add(int index, Object obj): 在index位置插入obj元素
boolean addAll(int index, Collection objs): 从index位置开始,将objs中的元素都添加进来
Object get(int index): 获取指定的index位置的元素

Object remove(int index): 移除指定index位置的元素,并返回此元素
Object set(int index, Object obj):设置指定index位置的元素为obj

List接口的实现类:ArrayList
在jdk1.7,ArrayList直接创建一个初始容量为10的数组
jdk1.8,ArrayList一开始创建一个长度为0的数组,当添加第一个元素时再创建一个初始容量为10的数组
Arrays工具类中的asList()方法的返回值不是ArrayList的实例,也不是Vector的实例,而是一个固定长度的List集合

List实现类:LinkedList
对于频繁的插入或者删除元素的操作,使用LinkedList效率比较高。
LinkedList是双向链表,内部没有声明数组,而是定义了Node类型的first和last,用于记录首末元素。同时,定义内部类Node,作为LinkedList中保存数据的基本结构。Node除了保存数据,还定义了两个变量:
prev变量记录前一个元素的位置
next变量记录下一个元素的位置

private static class Node<E>{
	E item;
	Node<E> next;
	Node<E> prev;
	
	Node(Node<E> prev, E element, Node<E> next){
		this.item = element;
		this.next = next;
		this.prev = prev;
	}
}

Java集合的交集 java集合join_java_03


一些方法:

Java集合的交集 java集合join_java_04


List实现类:Vector

Vector从jdk1.0就有了,大多操作与ArrayList相同,区别之处在于Vector是线程安全的。

ArrayList、LinkedList和Vector的异同:
①ArrayList和LinkedList的异同
二者都是线程不安全的,相对于线程安全的Vector,执行效率较高。
此外,ArrayList是实现了基于动态数组的数据结构,LinkedList是基于链表的数据结构。对于随机访问的get和set,ArrayList优于LinkedList,因为LinkedList要移动指针。对于新增和删除操作,add和remove,LinkedList比较快,因为ArrayList要移动数据。
②ArrayList和Vector的区别
Vector和ArrayList几乎是完全相同的,唯一的区别在于Vector是同步类(synchronized),属于强同步类。Vector每次扩容请求其大小两倍的空间,而ArrayList是1.5倍。

Collection子接口:Set接口

set集合不允许包含相同的元素
set判断相个对象是否相等是用的equals方法

Set实现类:HashSet
HashSet是Set集合最常用的实现类。
HashSet按照Hash算法来存贮集合中的元素,因此具有很好的存取、查找、删除性能。
HashSet线程不安全,集合元素可以是null

hashSet判断两个元素是否相等的标准: 两个对象通过hashCode()方法比较相等,并且两个对象的equals方法返回也相等。
对于存放在Set容器中的对象,对应的类一定要重写equals方法和hashCode方法来实现对象相等规则。即:对象相等必须有相等的散列码。

向HashSet中添加元素的过程:

当向HashSet集合中存入一个元素时,HashSet会调用该对象的HashCode()方法来得到该对象的HashCode值,然后根据hashCode值决定该对象在HashSet底层数组中的储存位置。

如果两个元素的HashCode值相等,会再继续调用equals方法,若果equals方法结果为true,添加失败;如果为false,那么会保存该元素,但是该数组的位置已经有元素了,那么会通过链表的方式继续连接。

如果两个元素的equals方法返回true,但他们的hashCode值不同,那么hashSet将会把它们存贮在不同的位置,可以添加成功。

Java集合的交集 java集合join_List_05

Set实现类:LinkedHashSet

LinkedHashSet是HashSet的子类。

LinkedHashSet根据元素的hashCode值来决定元素的存储位置,但他同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。

LinkedHashSet插入性能略低于HashSet,但在迭代访问Set里的全部元素时有很好的性能。

LinkedHashSet不允许集合元素重复。

Java集合的交集 java集合join_List_06

Set实现类:TreeSet

TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
TreeSet底层使用红黑树结构存储数据。
TreeSet两种排序方法:自然排序和定制排序。默认采用自然排序。
自然排序:
TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列。
如果要把一个对象添加到TreeSet中,则该对象必须要实现Comparable接口。
定制排序:
TreeSet的自然排序要求元素所属的类实现Comparable接口,如果元素所属的类没有实现Comparable接口,或不希望按照升序(默认情况)的方式排列元素或希望按照其它属性大小进行排序,则考虑使用定制排序。定制排序,通过Comparator接口来实现。需要重写compare(T o1,T o2)方法。

Map接口

Java集合的交集 java集合join_Java集合的交集_07


Map接口概述:

Map与Collection并列存在。用于保存具有映射关系的数据:key-value

Map 中的 key 和 value 都可以是任何引用类型的数据。

Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法。

key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value

HashMap是 Map 接口使用频率最高的实现类。

Java集合的交集 java集合join_List_08


Map实现类:HashMap

允许使用null键和null值,与HashSet一样,不保证映射的顺序。

所有的key构成的集合是Set:无序的、不可重复的。所以,key所在的类要重写:equals()和hashCode()

一个key-value构成一个entry

所有的entry构成的集合是Set:无序的、不可重复的

HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等。

HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true。HashMap的存储结构

JDK8之后HashMap是:数组+链表+红黑树实现

Java集合的交集 java集合join_List_09


HashMap的内部存储结构是数组+链表+红黑树的结合。当实例化一个HashMap时,会初始化:初始容量和负载因子,在put第一对映射关系时,系统会创建一个长度为initialCapacity的Node数组,这个长度在哈希表中被称为容量(Capacity), 在这个数组中可以存放元素的位置我们称之为“桶(bucket)”,每个bucket都有自己的索引,系统可以根据索引快速的查找bucket中的元素。

每一个bucket中存储一个元素,即一个Node对象,但是每一个Node对象可以带一个引用变量next,用于指向下一个元素,因此,在一个桶中,就有可能生成一个Node链。也可能是一个一个TreeNode对象,每一个TreeNode对象可以有两个叶子结点left和right,因此,在一个桶中,就有可能生成一个TreeNode树,而新添加的元素作为链表的last,或树的叶子结点。

那么HashMap什么时候进行扩容和树形化呢?

当HashMap中的元素个数超过数组大小(数组总大小length,不是数组中个数size)loadFactor 时 , 就会进行数组扩容 , loadFactor 的默认 值为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小为16,那么当HashMap中元素个数超过16 * 0.75=12(这个值就是代码中的threshold值,也叫做临界值)的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。
当HashMap中的其中一个链的对象个数如果达到了8个,此时如果capacity没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成树,结点类型由Node变成TreeNode类型。当然,如果当映射关系被移除后,下次resize方法时判断树的结点个数低于6个,也会把树再转为链表。

关于映射关系的key是否可以修改?
映射关系存储到HashMap中会存储key的hash值,这样就不用在每次查找时重新计算每一个Entry或Node(TreeNode)的hash值了,因此如果已经put到Map中的映射关系,再修改key的属性,而这个属性又参与hashcode值的计算,那么会导致匹配不上。

Map实现类:LinkedHashMap

LinkedHashMap是HashMap的子类
在HashMap的基础上,使用了一对双向链表来记录添加元素的顺序
与LinkedHashSet类似,LinkedHashMap可以维护Map的迭代顺序:迭代顺序与Key-Value对的插入顺序一致。

Map实现类:TreeMap

TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。
TreeMap 可以保证所有的 Key-Value 对处于有序状态。
TreeSet底层使用红黑树结构存储数据。
TreeMap 的 Key 的排序:
自然排序: TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
定制排序: 创建 TreeMap 时,传入一个Comparator 对象,该对象负责对TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现Comparable 接口。
TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0

Collections工具类

Collections 是一个操作 Set、List 和 Map 等集合的工具类。
Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法。

//排序操作:
reverse(List): 反转List中的元素顺序
shuffle(List): 对List集合元素进行随机排序
sort(List):根据元素的自然顺序对指定的List集合元素按升序排序
sort(List,Comparator): 根据指定的Comparator产生的顺序对List集合进行排序
swap(List, int i ,int j): 将指定的list集合中的i处的元素和j处的元素进行交换。
//查找、替换
Object max(Collection): 根据元素的自然顺序,返回给定的集合中的最大元素
Object max(Collection, Comparator): 根据Comparator指定的顺序,返回给定集合中最大的元素

int frequenvy(Collection, Object): 返回指定的集合中的指定元素的出现次数
void copy(List dest, List src): 将src中的内容复制到dest中
boolean replaceAll(List list, Object oldVal, Object newVal): 使用新值替换List对象的所有旧值

才疏学浅,多谢指教。