Java集合框架(Java Collections Framework简称JCF)是为表示和操作集合,而规定的一种统一的标准的体系结构。集合框架包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
集合就是用于存储对象的容器。 只要是对象类型就可以存进集合框架中。集合的长度是可变的。 集合中不可以存储基本数据类型的值
数组和集合相比,数组的缺点是它长度是固定的,没有办法动态扩展。
而集合存储数据时是没有长度限制的,是可以动态扩展的。集合容器因为内部的数据结构不同,有多种不同的容器对象。这些容器对象不断的向上抽取,就形成了集合框架。
特点
特点:
首先导入:
(1)import java.util.ArrayList;(2)import java.util.List;
创建一个List对象:
创建一个集合对象,可以指定集合容器的长度也可以不指定,如果指定那么默认长度为10;
List 集合名 =new ArrayList();//没有定义长度默认为10的集合
List 集合名=new ArrayList(5);//定义一个长度为5的集合
List list =new ArrayList();
List list =new ArrayList(5);
List-Array中可以添加任意类型的数据;
(1)单个元素的添加:
集合名.add(需要添加的元素);
list.add("你好集合");//添加字符串数据
list.add(2);//添加整型
list.add(3.14);//添加浮点数
list.add(true);//添加布尔型
(2)根据指定下标位置来添加元素
集合名.add(下标位置,元素);
向指定位置添加完元素后,后面的元素会向后移位
list.add(0,001);//向集合中下标为0的位置添加元素001
(3)向集合中添加多个元素(创建一个新集合把新集合添加到需要添加的集合中)
集合名.add(要添加的集合名);默认添加到最后
List list1=new ArrayList();//创建一个新集合
list1.add("a");//向新集合中添加元素
list1.add("b");
list.addAll(list1);//将新集合添加到原集合中
(1)删除指定位置的元素(根据下标位置删除)
集合名.remove(下标位置);
list.remove(2);//删除集合中下标位置为2的元素
(2)清空集合中所有的元素
集合名.clear();
list.clear();//清空名字为list的集合中的所有元素
修改指定位置的元素(根据下标位置进行修改)
集合名.set(下标位置,修改后的内容);
list.set(1,"蜜汁小汉堡");//将list集合中下标位置为1的内容改为"蜜汁小汉堡"
(1)查询指定位置的元素(根据下标位置查询)
集合名.get(下标位置); //注意要记得接收
Object o1=list.get(2);//定义一个Objiect类型的o1用来接收查询到的集合中下标为2的元素的数据
System.out.println(o1);//打印输出o1
(2)获取当前集合中元素的个数
集合名.size();
int num1=list.size();//定义一个整型num1用来接收集合的长度
System.out.println(num1);//打印num1
(3)查询判断集合中是否有这个元素
集合名.contains(要查找的元素);
如果找到会返回true;
boolean b1=list.contains("001");//定义一个布尔类型用于接收返回值,查询内容为001的元素
System.out.println(b1);
(4)查找集合中的内容并返回它第一次出现的位置
集合名.index(查询内容);
如果找到返回第一次出现的位置,如果找不到返回-1;
(1)for循环遍历
//for循环遍历的集合的内容
for(int i=0;i
(2)for each循环遍历
for(Object o3:list){//:前用于接收,:后是要遍历的集合
System.out.println(o3);
}
通过对ArrayList方法的底层代码分析:底层就是对数组的操作。
ArrayList的底层就是基于数组实现的。
LinkedList: 具有List的特征,底层以链表结构实现,可以进行头尾元素的添加删除
LinkedlList底层是双向链表的结构,它增加和删除效率很高,但是它的查询效率低。
查询效率低的原因是因为它把集合对半分成两份在前一份和后一份中一个一个查找.
LinkedList的常见方法:它的方法和ArrayList中的方法比较相似,它有自己特有的方法:
addFirst(),addLast(),getFirst(),getLast()
LinkedList 集合名字 = new LinkedList();
LinkedList linkedList =new LinkedList();//创建一个名字linkedList的集合
集合名字.addFirst(内容);
linkedList.addFirst("张三");//向集合中第一个位置添加张三这个数据
集合名字.addLast(内容);
linkedList.addLast("李四");//向集合最后一个位置添加元素"李四"
查询第一个元素:集合名字.getFirst();
查询最后一个元素:集合名字.getLast();
linkedList.getFirst();
linkedList.getLast();
删除第一个元素:集合名字.removeFirst();
删除最后一个元素:集合名字.removeLast();
linkedList.removeFirst();
linkedList.removeLast();
集合名.isEmpty();
结果是true/false记得要用布尔类型接收;
boolean empty = linkedList.isEmpty();//判断是否为空
pre集合中上一个元素的信息;
next集合中下一个元素的信息;
(1) HashSet 集合名字 = new HashSet(初始容器大小);
(2)HashSet 集合名字 = new HashSet(初始容器大小,负载因子f);
HashSet集合可以初始定义容器大小也可不定义容器大小
HashSet有负载因子;
负载因子:当容器达到一定值时容器会自扩充,那个值就是负载因子
负载因子如果不写默认是达到75%(0.75)时会自动动态扩充容器;
HashSet hashSet=new HashSet();//定义一个HashSet集合没有指定初始容器大小和负载因子
HashSet hashSet1=new HashSet(15);//定义一个HashSet集合给定初始容器大小为15没有负载因子;
HashSet hashSet2=new HashSet(15,0.75f);//定义一个HashSet集合给定初始大小为15给定负载因子为0.75(75%);
(1)添加单个元素:集合名字.add(内容);
(2)添加多个元素:集合名字.addAll(另一个集合名);
添加多个元素只能是通过创建另一个HashSet集合将另一个集合的元素添加到本集合中;
hashSet.add("张三");//向集合中添加"张三"这个数据;
hashSet.addAll(hashSet1);//向集合中添加另一个集合的数据;
(1)删除单个元素:集合名字.remove(要删除的数据);
(2)清空集合中的所有数据:集合名字.clear();
hashSet.remove("张三");//删除集合中张三这个元素
hashSet.clear();//清空集合中所有元素
(1)查询元素是否在集合中:集合名字.contains(要查询的内容);
判断的结果是true/false要用boolean 接收;
(2)判断集合是否为空:集合名字.isEmpty();
判断的结果是true/false要用boolean 接收;
boolean b1=hashSet.contains("张三");//查询张三是否在集合中,如果在返回true否则false
boolean b2=hashSet.isEmpty();//判断集合是否为空
(1)for each的遍历
for(Object o:hashSet){
System.out.println(o);
}
(2)通过迭代器来遍历
//迭代器遍历
Iterator iterator = hashSet.iterator();//获取迭代器对象 有序:有下标
while (iterator.hasNext()){//判断是否指定能够移动
Object next = iterator.next();//指定移动并获取当前的元素
System.out.println(next);
}
迭代器(iterator)有时又称游标(cursor)是程序设计的软件设计模式,可在容器对象(container,例如链表或数组)上遍访的接口,设计人员无需关心容器对象的内存分配的实现细节。
HashSet类中没有提供根据集合索引获取索引对应的值的⽅法,
因此遍历HashSet时需要使⽤Iterator迭代器。Iterator的主要⽅法如下
hasNext():判断指针是否能够移动,能够移动返回true否则返回false;
next():指针移动并货期指定所在位置的元素;
TreeSet中的方法和HashSet中的方法一模一样 只是他们的实现不一样。
TreeSet 基于TreeMap 实现。TreeSet可以实现有序集合,但是有序性需要通过比较器实现。
TreesSet特点:
TreeSet基于二叉树,它是一个有序得集合,要求里面得元素必须实现Comparable接口。 按照该接口得方法进行排序以及去重。
TreeSet对元素进行排序的方式:
1) 如果是基本数据类型和String类型,无需其它操作,可以直接进行排序。
2) 对象类型元素排序,需要实现Comparable接口,并覆盖其compareTo方法。
3) 自己定义实现了Comparator接口的排序类,并将其传给TreeSet,实现自定义的排序规则。
例子(eg):
@Override
public int compareTo(Object o) {
System.out.println("===调用Student 的 compareTo===");
// 判断要比较的目标类型和当前类型是否一致
if(!(o instanceof Student)){
return -1;
}
// 目标数据属于当前类型
Student s = (Student) o;
if(this.age>s.age){
return 1;
}else if(this.age
创建TreeSet时一定要为其指定排序规则即重写Comparator接口实现接口;
TreeSet 集合名字=new TreeSet(你定义的排序规则);
map中得每个元素属于键值对模式。 如果往map中添加元素时 需要添加key 和 value. 它也属于一个接口,该接口常见得实现类有: HashMap.
HashMap实现了Map接口,拥有Map接口的基本特点。HashMap线程不安全,效率高。HashMap的底层是由哈希表、链表加红黑树构成的。
(1)创建无初始容器大小无负载因子的HashMap:Map 集合名字=new HashMap();容器默认大小为16
(2)创建有初始容器大小无负载因子的HashMap:Map 集合名字=new HashMap(容器初始大小);
(3)创建有初始容器大小有负载因子的HashMap:Map 集合名字=new HashMap(容器初始大小,负载因子f);
Map map=new HashMap();
Map map1=new HashMap(15);
Map map2=new HashMap(15,0.75f);
添加操作时要添加key和value;键不允许重复必须唯一;
(1)单个键值对的添加:集合名字.put(键,值);
(2)多个键值对的添加(即添加另一个HashMap集合):集合名字.putAll(要添加的HashMap);
(3)判断添加,如果指定得key存在,则不放入map中,如果不存在则放入map中:
集合名字.putIfAbsent(键,值);
map.put("name","张三");//添加一个键为name值为"张三"
map.putAll(map1);//向map中添加集合map1
map.putIfAbsent("age",19);//判断是否有age这个键如果没有就添加如果有就不添加
如果键已经存在我再添加同一个键的值,后一个会把前一个给覆盖即:键相同时,后面覆盖前面的;
集合名字.replace(键,值);替换name键里的元素
map.replace("name","李四");//修改map中name键的元素为李四
(1)判断集合中是否存在指定的key
集合名字.containsKey(键key);如果存在返回true否则返回false
(2)根据指定的key获取对应的value值
集合名字.get(键key)
(3)返回该map中所有的key
集合名字.keySet()
boolean b1=map.containsKey("name");//判断map中是否有name键,返回值类型为boolean
Object o1=map.get("sex");//根据sex键返回map中所有的value值,返回类型为Object
Set s1=map.keySet();//返回map集合中所有的键,返回类型为Set;
for each循环遍历
// 遍历键的集合
for(Object key : set){
// 输出所有键
// map.get(key):获取对应键的值
System.out.println(key+" "+map.get(key));
}
/ 遍历map
for(Object obj : map.keySet()){
System.out.println(obj+" "+map.get(obj));
}
JDK1.7 和 JDK1.8它们是有区别的。
JDK1.7使用得数据结构: 数组+链表 而且链表插入模式为头部插入(造成死循环)。
jdk1.8使用得数据结构: 数组+链表+红黑树 而且链表得插入模式为尾部插入。
第一步:首先将k,v封装到Node对象当中(节点)。
Node节点中存储的是键,值,和下一个元素的地址;
第二步:它的底层会调用K的hashCode()方法得出hash值。
第三步:通过哈希表函数/哈希算法,将hash值转换成数组的下标(即哈希值16%得到一个0~15之间的数为下标),下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equals。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
第一步:先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
第二步:通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。重点理解如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着参数K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。