一、集合框架概述
(一).集合的引用
我们前面学习了java的基本数据类型,用用类型都是可以用来存储我们的数据的,但是仅仅之只能存储单个,我们可以通过数组的形式来存储多个数据,但是数组有个特点是长度不能改变,那就意味着数组在处理需要对数组中的数据做添加和删除操作时就会显得非常麻烦。所以Java给我们提供了集合类来解决这个问题。
(二)集合的概念
集合就是javaAPI所提供的一系列的实例,可以用来动态的存放多个对象,Java集合框架提供了一套性能优良,使用方便的接口和类,位于Java.util包中。集合的特点:长度不固定,只能存储引用类型的对象。
(三)集合和数组的区别
类型 | 说明 |
长度 | 数组:长度固定不变 集合:长度是可以根据实际的需求变动的 |
内容 | 数组:数组中存储的是同一种类型的数据 集合:可以存储不同类型的数据 |
数据类型 | 数组:可以存储基本数据类型和引用数据类型 集合:只能存储引用数据类型 |
(四)集合的框架图
集合其实是由一系列的java类和接口组成的
二、Collection(接口)集合
结合集合的框架结构,我们可以推演下集合的设计,因为集合由很多的增删改查的方法,而且集合是一套框架,既然是框架,那么每一种集合在处理增删改查的时候方式会不一样。
(一)、Collection集合概述
1.是单列集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素。
2.JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现
(二)、创建Collection集合的对象
以多态的方式创建。
(三)、Collection集合常用方法
方法名 | 说明 |
boolean add(E e) addAll() | 添加元素 |
boolean remove(Object o) removeAll() | 从集合中移除指定的元素 |
boolean removeIf(Object o) | 根据条件进行移除 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否存在指定的元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中元素的个数 |
toArray() | 将集合转换成数组 |
retainAll() | 求交集 |
在Collection接口中并没有提供直接修改的方法。要修改只能先删除在添加。
(四)、Iterator迭代器
所有实现了Collection接口的集合类都有一个Iterator()方法,该方法返回一个Iterator接口对象,提供的有集合数据遍历的方式。可以用来完成集合的遍历。
hasNext():判断索引右边是否有元素
next():返回索引右边的元素,并将索引移动到下一个位置。
Collection c1 = new ArrayList();
c1.add("张三1");
c1.add("张三2");
c1.add("张三3");
c1.add("张三4");
c1.add("张三5");
Iterator iterator = c1.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
foreach实现集合的遍历
public static void main(String[] args) {
//foreach实现集合的遍历
Collection c1 = new ArrayList();
c1.add("张三1");
c1.add("张三2");
c1.add("张三3");
c1.add("张三4");
c1.add("张三5");
Iterator iterator = c1.iterator();
for(Object o: c1){
System.out.println(o);
}
}
(五)、collection的特点
1.有序:部分集合实现是有序的,部分集合实现是无序的,这里的有序指的是存储的顺序。
2.可排序:部分集合实现是可排序的,部分集合实现是不可排序的。
3.可重复:部分集合实现是可重复的,部分集合实现是不可重复的。
每个集合的特点取决于各自的实现方式,但是有些特点是集合所共有的:
1.长度可变。
2.能够存储任意的应用类型。
3.具备很多对象的增删改查的方法。
4.集合也能存储基本数据类型的包装类。
实现方式取决于底层的数据结构。
三、List接口
(一)、LIst集合的概述和特点
1.List集合的概述
(1)有序集合,这里的有序指的是存取顺序
(2)用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
(3)与Set集合不同,列表通常允许重复的元素
2.List集合的特点
(1)存取有序
(2)可以重复
(3)有索引
(二)、List集合的方法
特有方法
方法名 | 描述 |
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
添加方法
//list的方法
List list1 = new ArrayList();
list1.add(1);
list1.add(2);
list1.add(3);
//添加方法
list1.add(0,"小明");
System.out.println(list1);
List list2 = new ArrayList();
list2.add("小华");
list2.addAll(0,list1);
System.out.println(list2);
删除方法
public static void main(String[] args) {
//list的方法
List list1 = new ArrayList();
list1.add(1);
list1.add(2);
list1.add(3);
//删除方法
list1.remove(2);
System.out.println(list1);
}
修改方法
public static void main(String[] args) {
//list的方法
List list1 = new ArrayList();
list1.add(1);
list1.add(2);
list1.add(3);
//修改方法
list1.set(1,"666");
System.out.println(list1);
}
查询方法
public static void main(String[] args) {
//list的方法
List list1 = new ArrayList();
list1.add(1);
list1.add(2);
list1.add(3);
//查询方法
System.out.println(list1.get(1));
}
常用方法:
方法名 | 说明 |
int indexOf(object o) | 返回此列表中指定元素第一次出现的索引,如果此列表不包含元素,则返回-1 |
int lastIndexOf(object o) | 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1 |
List<E> subList(int fromIndex, int toIndex) | 返回此列表中指定的fromIndex(包含)和toIndex之间的视图 |
集合遍历
ListIterator():集合迭代
public static void main(String[] args) {
//list的方法
List list1 = new ArrayList();
list1.add(1);
list1.add(2);
list1.add(3);
//遍历方法
//toArray()
Object[] objects = list1.toArray();
for (int i = 0; i < objects.length; i++) {
System.out.println(objects[i]);
}
System.out.println("---------------------------");
//普通for()
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
System.out.println("---------------------------");
//正向迭代
ListIterator iterator = list1.listIterator();
while (iterator.hasNext()){
System.out.println(iterator.nextIndex()+":"+iterator.next());
}
System.out.println("-------------------------------------");
//反向迭代
while(iterator.hasPrevious()){
System.out.println(iterator.previousIndex() + ":" + iterator.previous());
}
}
(三)、List接口的相关实现类
1.ArrayList
(1)概述
可调整大小的数组的实现List接口。 实现所有可选列表操作,并允许所有元素,包括null 。 除了实现List 接口之外,该类还提供了一些方法来操纵内部使用的存储列表的数组的大小。 (这个类是大致相当于Vector,不同之处在于它是不同步的).
(2)特点
底层是数组,长度可变。可以存储null值。线程不安全,效率高。查询和修改的效率高,增加和删除的效率低。有索引,能够方便检索。元素可以重复。不可排序。
2.LinkedList(链表)
(1)概述
双链表实现了List
和Deque
接口。 实现所有可选列表操作,并允许所有元素(包括null
)。所有的操作都能像双向列表一样预期。 索引到列表中的操作将从开始或结束遍历列表,以更接近指定的索引为准。
双向链表结构图
(2)特点
LinkedList底层的数据结构是一个双向链表,元素有序,可重复
LinkedList在实现数据的添加和删除效率高,查询和修改效率低。顺序访问会非常高效,而随机访问效率比较低。
LinkedList实现了List接口,支持使用索引访问元素。
LinkedList实现Deque,所以LinkedLIst也可以当作双端队列使用
LinkedList是线程不安全的,效率高。
3.Vector(向量)
(1)概述
Vector
类实现了可扩展的对象数组。 像数组一样,它包含可以使用整数索引访问的组件。 但是, Vector
的大小可以根据需要增长或缩小,以适应在创建Vector
之后添加和删除项目。
(2)常用方法
添加方法
//添加方法
v1.add(1);
v1.add(2);
v1.add("3");
v1.add(null);
v1.add('A');
System.out.println(v1);
删除方法
//删除方法
v1.removeElement(0);
修改方法
//修改方法
v1.setElementAt("666",1);
遍历
//遍历
System.out.println("==============================");
Enumeration elements = v1.elements();
while(elements.hasMoreElements()){
System.out.println(elements.nextElement());
}
获取集合中的元素
//获取集合中元素的方法
Object first = v1.firstElement();
Object last = v1.lastElement();
Object ele = v1.elementAt(1);
System.out.println(v1);
(3)特点
底层是数据结构是数组。
有索引,能够方便检索。
增加和删除的效率低,查询和修改的效率高。
线程安全,效率低。
能够存储null。
元素可重复。
不可以排序。
四、数据结构
(一)、stack(栈)
1.概述
Stack
类代表最先进先出(LIFO)堆栈的对象。 它扩展了类别Vector与五个操作,允许一个向量被视为堆栈。 设置在通常的push和pop操作,以及作为一种方法来peek在堆栈,以测试堆栈是否为empty的方法,以及向search在栈中的项目的方法在顶部项目和发现多远它是从顶部。
2.常用方法
public static void main(String[] args) {
//栈(stack):向量(Vector)的子类
//构造方法
Stack stack = new Stack();
//压栈(添加)
stack.push("a");
stack.push("b");
stack.push("c");
System.out.println(stack);
System.out.println("==============================");
//int search( Object o):返回对象在栈中的位置
System.out.println(stack.search("a"));
System.out.println("==============================");
//获取栈顶元素
System.out.println(stack.peek());
//pop()弹栈:获取栈顶元素并弹出
System.out.println(stack.pop());
System.out.println(stack);
System.out.println("========================");
while(!stack.isEmpty()){
System.out.println(stack.peek());
System.out.println(stack.pop());
}
}
3.特点
基于栈结构的集合,先进后出。
Stack类是Vector类的子类,所以该类也是线程安全的,效率低。
(二)、Queue(队列)
1.概述
设计用于在处理之前保留元素的集合。 除了基本的Collection
操作之外,队列还提供额外的插入,提取和检查操作。 这些方法中的每一种都有两种形式:如果操作失败,则抛出一个异常,另一种返回一个特殊值( null
或false
,具体取决于操作)。 插入操作的后一种形式专门设计用于容量限制的Queue
实现; 在大多数实现中,插入操作不能失败。 Summary of Queue methods Throws exception Returns special value Insert add(e)
offer(e)
Remove remove()
poll()
Examine element()
peek()
2.常用方法
public static void main(String[] args) {
//构造方法
java.util.Queue q = new ArrayDeque();
//添加方法
System.out.println(q.add(1));
System.out.println(q.add("1"));
System.out.println(q.add("a"));
System.out.println(q.offer('A'));
System.out.println("===========================");
//检查:只会取数据不会弹出
System.out.println(q.element());
System.out.println(q.element());
System.out.println(q.peek());
System.out.println(q.peek());
System.out.println(q.element());
System.out.println("=============================");
//删除方法
q.remove();
System.out.println(q);
q.remove();
System.out.println(q);
q.poll();
System.out.println(q);
q.poll();
System.out.println(q);
q.poll();
System.out.println(q);
System.out.println("==================================");
System.out.println(q.add(1));
System.out.println(q.add("1"));
System.out.println(q.add("a"));
System.out.println(q.offer('A'));
//遍历
while(!q.isEmpty()){
System.out.println(q.poll());
}
System.out.println("============================");
}
3.特点
该接口是队列接口的根接口,先进先出。
该接口提供队列相关的两种形式方法,一种抛异常,一种返回特殊值(null或者false)
(三)、Deque(双端列表)
1.概述
支持两端元素插入和移除的线性集合。 名称deque是“双端队列”的缩写,通常发音为“deck”。 大多数Deque
实现对它们可能包含的元素的数量没有固定的限制,但是该接口支持容量限制的deques以及没有固定大小限制的deques。
2.常用方法
头部 | 尾部 | |||
抛出异常 | 特殊值 | 抛出异常 | 特殊值 | |
插入 | addFirst() | offerFirst() | addLast() | offerLast() |
移除 | removeFirst() | pollFirst() | removeLast() | pollLast() |
检查 | getFirst() | peekFirst() | getLast() | peekLast() |
3.特点
Deque是一个Queue的子接口,是一个双端队列,支持在两端插入和移除元素。
Deque支持索引值直接存取。
Deque头部和尾部添加或移除元素都非常快速,但是在中部安插元素或移除元素是比较费劲。
插入、删除、获取操作支持两种方式:快速失败和返回null或true/false。
不推荐插入null元素,null作为特定返回值表示队列为空。
(四)、散列表
数组:查询和修改效率高,添加和删除效率低
链表:添加和删除效率高,查询和修改效率低
散列表:添加、删除、查询、修改效率都还可以。
(五)、二叉树
放入的规则:
3进入的时候二叉树没有节点,直接放在根节点。
6进入的时候,6和3比较,比3大所以放在3的右边
9进入的时候,9和3比较,较大,放3右边,在和6比较,较大,放6的右边
2进入的时候,2和3比较,较小,放3的左边
3进入的时候,3和3比较,相等,不放入二叉树。
4进入的时候,4和3比较,较大,放3的右边,4和6比较,较小,放6的左边。
取出规则:
从整个二叉树的最左侧开始取数据。2,3,4,6,9
特点:
左侧节点数据肯定比右侧节点数据小。
查询数据的效率比链表高。
缺点:
不平衡二叉树。查询效率不高。
(六)、红黑树
红黑树是一个自平衡的二叉查找树。树上的每个节点都遵循如下规则。
每个节点要么是黑色,要么是红色。
根节点是黑色。
每个叶子节点都是黑色。
每个红色节点的两个子节点一定是黑色的。
任意一个节点到每个叶子节点的路径包含数量相同的黑色节点。
通过如下两个规则来实现上述规则
recolor重新标记颜色。
rotation旋转这个树达到平衡。
红黑树能够自平衡的三个操作
左旋
右旋
变色
节点颜色由黑变红或由红变黑。
五、泛型
(一)、泛型的概述
1.为什么要使用泛型?
集合中是可以存储任意的引用数据类型的,如果同一个集合中存储的数据类型不一致,那么我在操作数据的时候有可能出现数据类型安全问题,这时我们就可以通过泛型来解决这个问题。
2.泛型的概念
在编译时就确定类型的一种技术,注意:泛型时JDK1.5之后引入的新特性,是一种将引用类型当作参数传如的参数化类型,在编译时期就确定了集合存储的元素类型。
3.格式
<数据类型> 这里面的数据类型必须是引用数据类型。
4.泛型的好处
提高程序的安全性
消除黄色警告线
在编译时期将类型确定,减少不必要的强转代码。
(二)、泛型的分类
根据泛型的不同使用位置进行分类
泛型的使用必须先申明在使用
1.泛型类
格式:修饰符 class 类名<类型> { }
2.泛型方法:在参数列表的形参和返回值中使用泛型。
普通方法中可以使用类定义的泛型,但是静态方法不能使。
格式:修饰符 <类型> 返回值类型 方法名(类型 变量名) { }
3.泛型接口
格式:修饰符 interface 接口名<类型> { }
实现类的两种辨析方法
定义实现类时,定义和接口相同泛型,创建实现类对象时明确泛型的具体类型
定义实现类时,直接明确泛型的具体类型
(三)、泛型的通配符
前面介绍的泛型的使用都是在编译的时候能确定的一种类型,我们其实在泛型中可以借鉴多态的思想,这时就需要用到通配符
1.?(无界通配符)
2.? extends E(上边界通配符 :表示调用时类型必须是E及子类)
3.? super E(下边界通配符:表示调用时类型必须是E及父类)
五、set接口
(一)、set接口介绍
1.set有别于List接口(有序可重复),set是无序不可重复的。
(二)、set接口的特点
1.集合中的元素不重复,自动去重。
2.存储的元素是无序的。
(三)、HashSet
1.概述
此类实现Set接口,由哈希表(实际为HashMap实例)支持。 对集合的迭代次序不作任何保证; 特别是,它不能保证订单在一段时间内保持不变。 这个类允许null元素。
2.特点
HashSet实现了Set接口,所以具备Set接口的特点。
1.集合中的元素不重复,自动去重。
2.存储的元素是无序的。
hashset能够具有上述特点是通过hashset的底层数据结构哈希表来实现的(HashTable,散列表)。
3.HashSet的实现原理
HashSet底层是通过散列表实现的,但是HashSet和散列表还是又区别的。散列表可以存储重复数据,但是HashSet不能存储重复元素。
通过构造方法我们可以发现HashSet实例化的时候其实是创建了一个HashMap实例。
在调用add方法的时候本质上是通过HashMap来实现的。
HashSet中自定义类型需要重写hashcode方法和equals方法。
(四)、TreeSet
1.概述
基于TreeMap的NavigableSet的实现。使用元素自然顺序对元素进行排序。或者根据set提供的Comparator进行排序,具体取决于使用的构造方法。
2.特点
满足Set接口的特点(无序不重复)
存储数据排序
不能存储null
3.实现原理
API层面:
TreeSet在构造器里卖弄创建了一个TreeMap实例。
TreeSet在调用add方法时,本质是调用了TreeMap的put方法。
所以,TreeSet的实现的本质是TreeMap。
底层原理:
TrssSet的底层实现数据结构是红黑树。
(五)、compareable接口
自定义的的引用类型,是没有排序规则的,可以通过实现Comparator接口的从,pampareTo方法来指定特定的排序规则。
(五)、comparator接口
对于comparable接口定义的排序规则的缺点(我们只能定义一种规则,不太灵活)我们可以通过comparator接口来完善,同时comparator接口的实现会覆盖掉comparable接口的实现。
针对本身的数据结构没有提供排序功能的集合,我们同样可以通过comparator来实现排序。
六、Map接口
(一)map概述
1.为什么要学习map集合
Map集合提供了集合之间的映射关系,让集合于集合之间产生了关联。
interface Map<K,V> K:键的类型;V:值的类型
2.常用方法
基本方法
方法名 | 说明 |
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
获取方法
方法名 | 说明 |
V get(Object key) | 根据键获取值 |
Set<K> keySet() | 获取所有键的集合 |
Collection<V> values() | 获取所有值的集合 |
Set<Map.Entry<K,V>> entrySet() | 获取所有键值对对象的集合 |
public static void main(String[] args) {
//获取一个map实例
Map<String,Object> map = new HashMap<>();
//添加数据
map.put("id",1001);
Map<String,Object> m = new HashMap<>();
m.put("name","张三");
map.putAll(m);
map.put("age", 18);
map.put("score", 100);
map.put(null, 100);
map.put("address" , null);
//删除功能(返回删除的值)
System.out.println(map.remove("id"));
//清空集合中的数据
//map.clear();
//修改数据
map.put("id",1003);
System.out.println("========================");
//获取功能
Object id = map.get("id");
System.out.println(id);
System.out.println("========================");
//遍历
//toString
System.out.println(map);
System.out.println("========================");
//遍历每个元素
//方法一:keySet()
Set<String> keys = map.keySet();
for (String key: keys
) {
System.out.println(key + ":" + map.get(key));
}
//方法二
System.out.println("==============================");
Collection<Object> values = map.values();
for (Object o:values
) {
System.out.println(o);
}
//方法三
System.out.println("===============================");
Set<Map.Entry<String, Object>> entries = map.entrySet();
for (Map.Entry<String, Object> entry : entries
) {
String key = entry.getKey();
Object value = entry.getValue();
System.out.println(key + ":" + value);
}
System.out.println("===================================");
//判断功能
System.out.println(map.containsKey("id"));
System.out.println(map.containsValue(19));
System.out.println(map.isEmpty());
System.out.println("========================");
//长度
System.out.println(map.size());
}
3.Map集合的特点
双列集合,一个键对应一个值。
键不可以重复,值可以重复。
值的顺序取决于键的顺序。
key和value都可以存储null。
(二)、HashMap
1.概述
基于哈希表的Map接口的实现。 允许null的值和null键。 ( HashMap类大致相当于Hashtable ,除了它是不同步的,并允许null)。
HashMap的特点:
键无序,唯一,类似于Set集合。
值无序,可重复,类似于List
底层数据结构是哈希表,保证Key唯一。
2.底层结构
jdk1.7及以前是采用数组加链表。
jdk1.8之后才有数组+链表(深度小于8)或者数组+红黑树(元素大于8)进行元素的存储。
(三)、TreeMap
1.TreeMap概述
一个红黑树基于NavigableMap实现。该映射根据其键的自然顺序进行排序,或者根据创建映射提供的Comparator进行排序。
2.特点
键可排序,唯一。
值有序,可重复。
底层数据结构是红黑树。
排序的方式类似于TreeSet。
类结构图