集合的理解和好处
前面我们保存多个数据使用的是数组,那么数组有不足的地方,我们分析一下。
1)长度开始时必须指定,而且一旦指定,不能更改 2)保存的必须为同一类型的元素 3)使用数组进行增加元素的示意代码-比较麻烦
那么集合有哪些好处呢?
1)可以动态保存任意多个对象,使用比较方便! 2)提供了一系列方便的操作对象的方法: add、 remove、 set、 get等 3)使用集合添加, 删除新元素的示意代码-简洁了
public interface Collection < E > extends Iterable < E >
1)collection实现子类可以存放多个元素,每个元素可以是Object 2)有些Collection的实现类,可以存放重复的元素,有些不可以 3)有些Collection的实现类,有些是有序的(List),有些不是有序(Set) 4)Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的
Collection接口常用方法,以实现子类ArrayList来演示
add:添加单个元素 remove:删除指定元素 contains:查找元素是否存在 size:获取元素个数 isEmpty:判断是否为空 clear:清空 addAll:添加多个元素 containsAll:查找多个元素是否都存在 removeAll:删除多个元素
Collection接口遍历元素方式1 -使用Iterator(迭代器)
Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。 所有实现了Collection接口的集合类都有一个iterator(方法, 用以返回一个实现 了Iterator接口的对象,即可以返回一个迭代器。 Iterator的结构 Iterator仅用于遍历集合,Iterator 本身并不存放对象。
import java. util. ArrayList ;
import java. util. Iterator ;
public class Collection01 {
public static void main ( String [ ] args) {
ArrayList al = new ArrayList ( ) ;
al. add ( "AA" ) ;
al. add ( 11 ) ;
al. add ( "三国演义" ) ;
Iterator iterator = al. iterator ( ) ;
while ( iterator. hasNext ( ) ) {
Object obj = iterator. next ( ) ;
System . out. println ( obj) ;
}
}
}
Collection接口遍历对象方式2-for循环增强
增强for循环,可以代替iterator迭代器, 特点: 增强for就是简化版的iterator, 本质一样。只能用于遍历集合 或数组。
基本语法
for ( 元素类型 元素名: 集合名或数组名) {
访问元素
}
List接口和常用方法
List接口是Collection接口的子接口
List集合类中元素有序(即添加顺序和取出顺序一 致)、 且可重复 List集合中的每个元素都有其对应的顺序索引,即支持索引。 List容器中的元素都对应一 个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
List集合里添加了一些根据索引来操作集合元素的方法
void add(int index, Object ele):在index位置插入ele元素 boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来 Object get(int index):获取指定index位置的元素 int indexOf(Object obj):返回obj在集合中首次出现的位置 int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置 Object remove(int index):移除指定index位置的元素,并返回此元素 Object set(int index, Object ele):设置指定index位置的元素为ele , 相当于是替换 List subList(int fromIndex, int tolndex): 返回从fromIndex到tolndex位置的子集合
List[ArrayList, LinkedList, Vector]的三种遍历方式
方式一:使用iterator
方式二:使用增强for
方式三:使用普通for
ArrayList的注意事项
permits all elements, includling null , ArrayList可以加入nulI,并且多个 ArrayList是由数组来实现数据存储的 ArrayList基本等同于Vector ,除了ArrayList是线程不安全(执行效率高)看源码. 在多线程情况下,不建议使用ArrayList
ArrayList的底层操作机制源码分析
ArrayList中维护了-个Object类型的数组elementData. [debug 看源码] transient Object[] elementData; 当创建对象时,如果使用的是无参构造器,则初始elementData容量为0 (jdk7是10) 当添加元素时:先判断是否需要扩容,如果需要扩容,则调用grow方法,否则直接添加元素到合适位置 如果使用的是无参构造器,如果第一次添加, 需要扩容的话,则扩容elementData为10, 如果需要再次扩容的话,则扩容elementData为1.5倍。 如果使用的是指定容量capacity的构造器,则初始elementData容量为capacity 如果使用的是指定容量capacity的构造器,如果需要打容,则直接扩容elementData为 1.5倍。
Vector和ArrayList的比较
LinkedList底层结构
LinkedList底层实现了双向链表和双端队列特点 可以添加任意元素(元素可以重复),包括null 线程不安全,没有实现同步
LinkedList的底层操作机制
LinkedList底层维护了一个双向链表. LinkedList中维护了两个属性first和last分别指向首节点和尾节点 每个节点(Node对象) ,里面又维护了prev、next、 item三个属性, 其中通过 prev指向前一个,通过next指向后一个节点。最终实现双向链表 所以LinkedList的元素的添加和删除 ,不是通过数组完成的,相对来说效率较高 。 模拟一个简单的双向链表走代码
ArrayList和LinkedList的比较
这俩都是线程不安全的
如何选择ArrayList和LinkedList: 1)如果我们改查的操作多,选择ArrayList 2)如果我们增删的操作多,选择LinkedList 3)一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList 4)在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另外一个模块是LinkedList.
Set接口和常用方法
1 无序(添加和取出的顺序不一致),没有索引 2 不允许重复元素,所以最多包含一个null 3 JDK APl中Set接口的实现类有: AbstractSet, ConcurrentSkipListSet, CopyOnWriteArraySet, EnumSet, HashSet, JobStateReasons, LinkedHashSet, TreeSet
和List接口一样,Set接口也是Collection的子接口,因此,常用方法和Collection接口一样.
同Collection的遍历方式一样,因为Set接口是Collection接口的子接口。 1.可以使用迭代器 2.增强for 3.不能使用索引的方式来获取元素 .
HashSet的全面说明
HashSet实现了Set接口 HashSet实际上是HashMap,看下源码. 可以存放null值,但是只能有一个null HashSet不保证元素是有序的,取决于hash后,再确定索引的结果. 不能有重复元素/对象.在前面Set接口使用已经讲过
HashSet底层机制说明
分析HashSet的添加元素底层是如何实现(hash() + equals())
HashSet 底层是HashMap 添加一个元素时,先得到hash值-会转成->索引值 找到存储数据表table ,看这个索引位置是否已经存放的有元素 如果没有,直接加入 如果有,调用equals比较,如果相同,就放弃添加,如果不相同,则添加到最后 在Java8中,如果条链表的元素个数超过TREEIFY THRESHOLD(默认是8),并且table的大小 >=MIN_ TREEIFY CAPACITY(默认64),就会进行树化(红黑树)
HashSet的扩容和转成红黑树机制
HashSet底层是HashMap,第一次添加时,table 数组扩容到16,临界值(threshold)是
16
∗
加
载
因
子
(
l
o
a
d
F
a
c
t
o
r
)
是
0.75
=
12
16*加载因子(loadFactor)是0.75 = 12
1 6 ∗ 加 载 因 子 ( l o a d F a c t o r ) 是 0 . 7 5 = 1 2 如 如 果table数组使用到了临界值12,就会扩容到16* 2 = 32,新的临界值就是32*0.75 = 24,依次类推 在Java8中,如果一条链表的元素个数到达TREEIFY THRESHOLD(默认是8 ),并且table的大小>=MIN TREEIFY CAPACITY(默认64),就会进行树化(红黑树),否则仍然采用数组扩容机制
Set接口实现类 - LinkedHashSet
LinkedHashSet是HashSet的子类 LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表 LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序(图),这使得元素看起来是以插入顺序保存的。 LinkedHashSet不允许添重复元素
Map接口和常用方法
注意:这里讲的是JDK8的Map接口特点 Map_ java
Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中 Map中的key不允许重复,原因和HashSet一样,前面分析过源码. Map中的value可以重复 Map的key可以为null, value也可以为null,注意key为null,只能有一个,value为null ,可以多个. 常用String类作为Map的key key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value Map存放数据的key-value示意图,-对k-v是放在一 个Node中的,有因为Node实现了Entry接口,有些书上也说一对k-v就是一个Entry(如图)
常用方法
put:添加 remove:根据键删除映射关系 get:根据键获取值 size:获取元素个数 isEmpty:判断个数是否为0 clear:清除 containsKey:查找键是否存在
Map遍历方式
1)containsKey:查找键是否存在 2)keySet:获取所有的键 3)entrySet:获取所有关系k-v 4)values:获取所有的值
HashMap小结
Map接口的常用实现类: HashMap、 HashTable和Properties。 HashMap是Map接口使用频率最高的实现类。 HashMap是以key-val对的方式来存储数据(HashMap$Node) key不能重复,但是是值可以重复,允许使用null键和null值。 如果添加相同的key,则会覆盖原来的key-val ,等同于修改.(key不会替换,val会替换) 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的. HashMap没有实现同步,因此是线程不安全的
HashMap底层机制
HashMap底层维护了Node类型的数组table,默认为null 当创建对象时,将加载因子(loadfactor)初始化为0.75. 当添加key-val时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key是否和准备加入的key相等,如果相等,则直接替换val;如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容。 第1次添加,则需要扩容table容量为16,临界值(threshold)为12. 以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的2倍,即24,依次类推 在Java8中,如果一条链表的元素个数超过TREEIFY THRESHOLD(默认是8),并且table的大小>= MIN TREEIFY CAPACITY(默认64),就会进行树化(红黑树)
Map接口实现类 -HashTable的基本介绍
存放的元素是键值对:即K-V hashtable的键和值都不能为null,否则会抛出NullPointerException hashTable使用方法基本上和HashMap-样 hashTable是线程安全的,hashMap 是线程不安全的 简单看下底层结构
Map接口实现类 - Properties基本介绍
Properties类继承自Hashtable类并且实现了Map接口, 也是使用一种键值对的形式来保存数据。 他的使用特点和Hashtable类似 Properties 还可以用于从xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改 说明: 工作后xx.properties 文件通常作为配置文件,这个知识点在I0流举例,有兴趣可先看文章
总结-开发中如何选择集合实现类
1)先判断存储的类型(一组对象[单列]或一组键值对[双列]) 2)一组对象[单列]: Collection接口 允许重复: List 增删多: LinkedList [底层维护了一个双向链表] 改查多: ArrayList [底层维护Object类型的可变数组] 不允许重复: Set 无序: HashSet [底层是HashMap ,维护了一个哈希表即(数组+链表红黑树)] 排序: TreeSet 插入和取出顺序一致: LinkedHashSet , 维护数组+双向链表 3)一组键值对:Map 键无序: HashMap [底层是:哈希表jdk7: 数组+链表,jdk8:数组+链表+红黑树] 键排序: TreeMap 键插入和取出顺序一致: LinkedHashMap 读取文件Properties
Collections工具类
Object max(Collection): 根据元素的自然顺序,返回给定集合中的最大元素 Object max(Collection, Comparator): 根据Comparator指定的顺序,返回给定集合中的最大元素 Object min(Collection) Object min(Collection, Comparator) int frequency(Collection, Object): 返回指定集合中指定元素的出现次数 void copy(List dest,List src):将src中的内容复制到dest中 ections工具类