介绍
集合可以动态保存任意多个对象,使用比数组较方便
提供了一系列方便的操作对象的方法:add,remove,set,get等
集合的框架体系
集合由Collection和Map接口组成,他们两个都继承了Iterable类。注意他们两个都没有直接的实现子类,而是通过他们的子类接口来实现的。
单列集合:Collection
双列集合:Map (K-V)
Collection接口实现类的特点
1,Collection接口实现的子类可以存放多个元素,每个元素都是Object
2,Collection的子类接口List,可以存放重复的元素,而Collection的子类接口Set则不可以
3,Collection的子类接口List是有序的,而Collection的子类接口Set是无序的
4,Collection接口没有直接的实现子类,是通过他的子类接口List和Set来实现的
常用方法
添加:add,addAll
删除:remove,removeAll
包含:contains,containsAll
获取元素个数:size
判断是否为空:isEmpty
清空:clear
List接口
实现类:ArrayList,LinkedList,Vector
1,List集合类中元素有序,且可重复
2,List集合中的每个元素都有下标
3,ArrayList和LinkedList都是线程不安全的,Vector线程安全
常用方法
添加:add,addAll
获取:get
查找:indexOf,lastIndexOf
删除:remove
替换:set
ArrayList的底层操作机制源码分析
ArrayList中维护了一个Object类型的数组elementDate
transient Object[] elementData: transient 表示瞬间,短暂的,表示改属性不会被序列号
ArrayList演示常用方法代码:
package com.java.test;
import java.util.ArrayList;
public class List_{
public static void main(String[] args) {
ArrayList a1 = new ArrayList();
ArrayList a2 = new ArrayList();
//添加:add,addAll
a1.add("语文");
a1.add("数学");
a2.add("英语");
a1.addAll(a2);
System.out.println("a1="+a1);
//获取:get
System.out.println(a1.get(0));
//替换:set
a1.set(1, "物理");
System.out.println("a1="+a1);
//查找:indexOf返回第一次出现的索引,lastIndexOf返回最后一次出现的索引
System.out.println(a1.indexOf("语文"));
//删除:remove,removeAll
a1.remove("数学");
a1.removeAll(a2);
System.out.println("a1="+a1);
//包含:contains,containsAll
System.out.println(a1.contains("语文"));
//获取元素个数:size
System.out.println(a1.size());
//判断是否为空:isEmpty返回布尔值
//清空:clear
System.out.println(a1.isEmpty());
a1.clear();
System.out.println(a1.isEmpty());
}
}
代码执行结果:
a1=[语文, 数学, 英语]
语文
a1=[语文, 物理, 英语]
0
a1=[语文, 物理]
true
2
false
true
ArrayList的扩容倍数
如果是无参,默认0,第一次10,第二次扩容按照1.5倍扩容
如果有参则每次直接按照1.5倍扩容
Vector
1,底层也是一个对象数组,protected Object[] elementData
2,线程安全
Vector的扩容倍数
如果是无参构造器,默认10,满后就按照2倍扩容
如果指定大小,则每次直接按照2倍扩容
LinkedList
1,底层实现了双向链表和双端队列
2,可以添加任意元素(元素可以重复)
LinkedList的底层操作机制
1,LinkedList底层维护了一个双向链表
2,LinkedList中维护了两个属性first和last分别指向首节点和尾节点
3,每个节点(Node对象),里面又维护了prev,next,item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表
4,使用LinkedList的元素的添加和删除相对来说效率较高
ArrayList和LinkedList的比较
ArrayList是可变数组 增删的效率较低 改查的效率较高
LinkedList是双向链表 增删的效率较高 改查的效率较低
ArrayList和LinkedList都是线程不安全的
List接口的遍历方法:
1,Iterator迭代器
2,增强for循环
3,for循环
package com.java.test;
import java.util.ArrayList;
import java.util.Iterator;
public class List_{
public static void main(String[] args) {
ArrayList a1 = new ArrayList();
a1.add(10);
a1.add(100);
a1.add(1000);
//1,Iterator迭代器
Iterator iterator = a1.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//2,增强for循环
for(Object i:a1){
System.out.println(i);
}
//3,for循环
for(int i = 0 ; i < a1.size() ; i++) {
System.out.println(a1.get(i));
}
}
}
Set接口
实现类:HashSet,LinkedHashSet,TreeSet
1,无序的,没有下标
2,不允许重复元素,最多包含一个null
3,取出的顺序的顺序虽然不一定是添加的顺序,但是他是固定的
4,Set接口的常用方法和List一致
HashSet
1,实现了Set接口
2,HashSet实际上是HashMap
3,可以存放null值,但是只能有一个null
4,HashSet不保证元素是有序的,取决于hash后,再确定索引的结构
5,不能有重复的元素
HashSet的添加机制
1,HashSet底层是HashMap
2,添加一个元素时,先得到hash值,会转成索引值
3,找到table数组,看这个索引位置是否以及存放的有元素,如果没有,直接加入,如果有,调用equals比较,如果相同则放弃添加,如果不相同则添加到其链表后
6,再Java8中,如果一条链表的元素个数超过8并且table的大小大于等于64就会进行树化(红黑树)
LinkedHashSet
1,LinkedHashSet时HashSet的子类
2,LinkedHashSet底层是一个LinkedHashMap(为HashMap的子类),底层维护了一个数组+双向链表,LinkedHashSet有head和tail,每个节点有before和after属性
3,LinkedHashSet根据元素的hashCode值来确定元素的储存位置,同时使用链表维护元素的次序,是的元素看起来是以插入顺序保存的。即添加的顺序和取出的顺序一样
4,LinkedHashSet不允许添加重复元素
5,添加第一次时,直接将数组table扩容到16,数组是HashMap$Node[],存放的节点类型时LinkedHashMap$Entry
TreeSet
1,底层就是TreeMap
2,当使用无参构造器创建TreeSet时,仍然是无序的
3,当希望按照字符串大小来排序:
使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)并指定排序规则
如果匿名内部类里面的compare方法比较字符串长度则如果有两个长度相同的String不可重复添加
Set接口的遍历方法:
1,Iterator迭代器
2,增强for循环
3,Set是无序的没有索引的,所以遍历时不可用for循环遍历
package com.java.test;
import java.util.HashSet;
import java.util.Iterator;
public class Set_{
public static void main(String[] args) {
HashSet a1 = new HashSet();
a1.add(10);
a1.add(100);
a1.add(1000);
//1,Iterator迭代器
Iterator iterator = a1.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//2,增强for循环
for(Object i:a1){
System.out.println(i);
}
}
}
Map接口
Map与Collection并列存在,用于保存具有映射关系的数据:K-V
实现类:Hashtable,HashMap,TreeMap
常用方法
添加:put
删除:remove
获取值:get
获取元素个数:size
判断是否为空:isEmpty
清空:clear
包含:containsKey
Map接口的遍历方法
1,通过keySet获取所有的键,再使用get方法获取值
2,通过entrySet来获取K-V
package com.java.test;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Map_{
public static void main(String[] args) {
HashMap h1 = new HashMap();
h1.put("语文", 100);
h1.put("数学", 90);
h1.put("英语", 110);
//1,通过keySet获取所有的键,再使用get方法获取值
Set keyset = h1.keySet();
//(1)增强for循环
for(Object key : keyset){
System.out.println(key+"-"+h1.get(key));
}
//(2)Iterator迭代器
Iterator iterator = keyset.iterator();
while(iterator.hasNext()){
Object key = iterator.next();
System.out.println(key+"-"+h1.get(key));
}
//2,通过entrySet来获取K-V
Set entryset = h1.entrySet();
//(1)增强for循环
for(Object entry : entryset){
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey()+"-"+m.getValue());
}
//(2)Iterator迭代器
Iterator iterator1 = entryset.iterator();
while(iterator1.hasNext()){
Object entry = iterator1.next();
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey()+"-"+m.getValue());
}
}
}
HashMap
1,Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中(节点HashMap$Node实现Map$Entey接口)
2,Map中的key不允许重复但value可以重复,当重复添加key时就等价于替换value
3,HashMap中的key和value可以为null
4,常用String类作为Map的key
5,key和value之间存在单向一对一关系,即可以通过指定的key总能找到对应的value
6,Map存放数据的K-V时放在一个Node中的,Node内部类实现了Entry接口
7,线程不安全
HashMap演示常用方法代码:
package com.java.test;
import java.util.HashMap;
public class Map_{
public static void main(String[] args) {
HashMap h1 = new HashMap();
//添加:put
h1.put("语文", 100);
h1.put("数学", 90);
h1.put("英语", 110);
//删除:remove
h1.remove("语文");
//获取值:get
System.out.println(h1.get("数学"));
//获取元素个数:size
System.out.println(h1.size());
//判断是否为空:isEmpty
//清空:clear
System.out.println(h1.isEmpty());
h1.clear();
System.out.println(h1.isEmpty());
//包含:containsKey
System.out.println(h1.containsKey("英语"));
}
}
代码执行结果:
90
2
false
true
false
Hashtable
1,存放的是键值对
2,Hashtable的键值都不可以为null,否者会抛出NullPointerException异常
3,Hashtable使用方法基本上和HashMap一样
4,线程安全
Hashtable的扩容机制
底层数组Hashtable$Entry[]初始大小为11
临界值threshold 8 = 11 * 加载因子(创建对象时默认为0.75)0.75
当cound >= threshold时 扩容到当前容量的两倍加一
Properties类继承自Hashtable类
1,Properties也是使用一种键值对的形式保存数据
2,他的使用特点和Hashtable类似
3,Properties还可以用于xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改
4,工作后xxx.properties文件通常作为配置文件
HashMap和Hashtable的对比
HashMap线程不安全,效率高,键值都可以为null
Hashtable线程安全,效率低,键值都不可以为null
TreeMap
1,当使用无参构造器创建TreeMap时,仍然是无序的
2,当希望按照key(String)的大小来排序
3,使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)并指定排序规则
如果匿名内部类里面的compare方法比较字符串长度则如果有两个长度相同的key(String)不可重复添加,如果添加则替换
集合选型规则
在开发中,选择声明集合实现类,取决与业务操作特点分析:
先判断存储的类型(一组对象或一组键值对)
一组对象:Collection接口
允许重复List
线程不安全
增删多LinkedList底层维护了一个双向链表
查改多ArrayList底层维护Object类型的可变数组
线程安全Vector
不允许重复Set
无序HashSet底层是HashMap,维护了一个哈希表:数组+链表+红黑树
排序TreeSet
添加和取出的顺序一致LinkedHashSet维护数组+双向链表
一组键值对:Map接口
键无序HashMap底层是哈希表:数组+链表+红黑树
键排序TreeMap
键添加和取出的顺序一致LinkedHashMap
读取文件Properties
Collections工具类
1,Collections是一个操作List,Set和Map集合的工具类
2,Collections中提供了一系列静态的方法对集合元素进行排序,查询,和修改等操作
排序操作
反转:reverse(List)
随机排序:shuffle(List)
自然顺序排序:sort(List)
匿名内部类规则排序:sort(List,Comparator)
元素交换:swap(List , int , int)
最大值max(List)
匿名内部类规则取最大值max(List,Comparator)
返回集合中指定元素的出现次数frequency(Collection , Object)
复制:copy(Collection c1 , Collection c2) copy前需要数组的大小大于或等于源数组的长度
替换:replaceAll(Collection c1 , Object oldVal , Object newVal)