集合概念:
长度可以变化。就是一种容器。集合存储只能是对象。
集合框架:
如何学习集合??
1、会使用集合存储数据
2、会遍历集合,数据取出
3、掌握集合特性。
集合架构:
Collection:单列集合根接口,定义了单列集合共性的方法(所有的集合都可以使用),常用如下:没有索引的,不能使用for循环来遍历
public boolean add(E e)
: 把给定的对象添加到当前集合中 。
public void clear()
:清空集合中所有的元素。
public boolean remove(E e)
: 把给定的对象在当前集合中删除。
public boolean contains(E e)
: 判断当前集合中是否包含给定的对象。
public boolean isEmpty()
: 判断当前集合是否为空。
public int size()
: 返回集合中元素的个数。
public Object[] toArray()
: 把集合中的元素,存储到数组中。
使用步骤:
1、创建一个集合对象,可以使用多态
2、对象.方法
Iterator接口:也称为迭代器
要解决的问题,就是集合对象遍历问题。通用的取出集合元素的方式。
原理:
在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
Iterator接口的常用方法如下:
public E next()
:返回迭代的下一个元素。
public boolean hasNext()
:如果仍有元素可以迭代,则返回 true。
使用步骤:
因为是接口,需要使用实现类对象,获取对象的方式比较特殊:通过调用Collection接口中的Iterator()方法来实现,返回的就是实现类对象。 Iteratar<E> iterator(); //返回在此collection 的元素上进行迭代的迭代器。
1、使用集合中的方法Iterator()获取迭代类实现对象,使用Iteratorr接口接收(多态)
Iterator<E>也是有泛型的,迭代器的泛型跟着集合走,集合是什么泛型,迭代器就是什么泛型
2、使用Iterator接口中的方法hasNext判断还有没有下一个元素
3、使用next方法取出集合中的下一个元素。
增强for循环:专门用来遍历集合和数组的,底层使用的也是迭代器,只是使用for循环的格式,简化迭代器写法。
格式:
for(集合/数组的数据类型 变量名 :(冒号) 集合名/数组名){
sout(变量名);
}
泛型:集合中数据类型就是泛型,可以看成是一种未知的数据类型。也可以看成是一个变量用来接收数据类型。
1、什么时候确定泛型数据类型?
创建集合对象的时候,就会确定泛型的数据类型。
2、使用泛型好处?1、避免类型转换的麻烦。存储是什么类型,取出的就是什么类型 2、运行期异常(即运行之后才抛出的异常),提升到编译期。
3、泛型的类定义和使用?
定义格式:泛型可以接收任意的数据类型
修饰符 class 类名<代表泛型的变量> { }
4、含有泛型方法定义和使用?
格式:泛型定义在方法的修饰符和返回值类型之间
修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)){
方法体;
};//在调用方法的时候确定泛型的数据类型,传递什么类型的参数,泛型就是什么类型。
5、含有泛型的接口定义和使用?
格式:修饰符 interface接口名<代表泛型的变量> { }
第一种使用方式:定义接口的实现类,实现接口,指定接口泛型,如:
public interface Iterator<E> {
E next();
} //定义类时确定泛型的类型
Scanner 类实现了Interator接口,并指定接口的泛型为String,所以重写的next方法泛型默认就是String
public final class scanner implements Iterator<String>{
public String next(){}
}
第二种使用方法,接口使用什么泛型,实现类就使用什么泛型,类跟着接口走,就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型
如:public interface List<e>{
boolean add(E e);
E get(int index);
}
public class ArrayList<e> implements List<E>{
public boolean add(E e){ }
public E get(int index){ }
}
6、泛型的通配符 <?>代表任意的数据类型
使用场景?
不知道使用什么类型来接收的时候,使用 ? 来表示未知通配符。
此时只能接收数据,而不能往集合中存储数据
使用方式:
不能创建对象使用,只能作为方法的参数使用
泛型通配符高级使用:不太常用
泛型的上限限定:? extends 类 如 ? extends E //代表使用的泛型只能是E类型的子类/本身
泛型的下限限定:? super 类 如 ? super E //代表使用的泛型只能是E类型的父类/本身
集合数据结构:栈、队列、数组、链表和红黑树
栈:先进后出,出口与入口在一侧
队列:先进先出,出口与入口在集合的两侧
数组:查询快,增删慢。
数组的地址是连续的,通过数组的首地址可以找到数组,通过数组索引可以快速找到某一个元素。增删慢:因为长度是固定的,想要增删先要创建一个新的数组,把源数组复制过来。源数组会被垃圾回收。
链表:查询慢,增删快。
链表中的地址不是连续的,每次查询元素必须从头开始查询。
链表结构增删一个元素,对链表的整体结构没有影响。所以增删快。
单向链表:只有一条链子,不能保证元素的顺序(存储与取出的顺序可能不一致)。
双向链表:有两条链子,一条链子专门记录元素顺序,所以是一个有序的集合。
红黑树:
二叉树,分支不超过2个
排序树/查找树:在二叉树的基础上元素是有大小顺序的,左子树小,右子树大。
平衡树:左孩子与右孩子数量相等。查询速度非常快。
红黑树:趋近于平衡树,查询叶子节点的最大次数与最小次数不能超过2倍
红黑树的约束:了解
-
节点可以是红色的或者黑色的
-
根节点是黑色的
-
叶子节点(特指空节点)是黑色的
- 每个红色节点的子节点都是黑色的
- 任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同
List集合:继承了Collection接口
特征:1、有序集合,存储和取出元素的顺序是一致的。
2、带索引
3、允许重复元素
特有的方法:
public void add(int index, E element)
: 将指定的元素,添加到该集合中的指定位置上。
public E get(int index)
:返回集合中指定位置的元素。
public E remove(int index)
: 移除列表中指定位置的元素, 返回的是被移除的元素。
public E set(int index, E element)
:用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
List接口实现类:
ArrayList集合:底层结构是数组,所以是查询快,增删慢。也是基于多线程。
LinkedList集合:List的链表实现。多线程的。所以查询慢,增删快。包含了大量首尾元素的方法。使用linkedList集合特有的方法,就不能使用多态。因为多态是看不到子类特有的方法。
常用方法;
//添加
public void addFirst(E e)`:将指定元素插入此列表的开头。
public void addLast(E e)`:将指定元素添加到此列表的结尾。
//获取
public E getFirst()`:返回此列表的第一个元素。
public E getLast()`:返回此列表的最后一个元素。
//删除
public E removeFirst()`:移除并返回此列表的第一个元素。
public E removeLast()`:移除并返回此列表的最后一个元素
public E pop()`:从此列表所表示的堆栈处弹出一个元素。//相当于removeFirst();
public void push(E e)`:将元素推入此列表所表示的堆栈。
public boolean isEmpty()`:如果列表不包含元素,则返回true。
Vector集合:底层也是数组,同步的,单线程。jdk1.2+后被ArrayList取代。了解即可。
Set接口:externs Collection接口
特点:1、不允许存储重复的元素
2、没有索引,没有带索引的方法,也不能使用普通的for循环遍历
HashSet集合:实现了Set接口,除Set接口特点外:
一个无序的集合,存储元素和取出元素的顺序可能不一致
底层是一个哈希表结构(查询速度非常快)。
使用HashSet存储自定义元素:
存储元素必须重写hashCode方法和euals方法。
LinkedHashSet方法:extends HashSet集合
特点:有序的并且不允许重复
底层是一个哈希表(数组+链表/红黑树)+链表(记录元素存储顺序),保证元素有序
扩展:哈希
哈希值:一个十进制整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,不是物理地址)Object类有一个方法,可以获取对象的哈希值 int hashCode()返回对象的哈希码值
哈希表:哈希表=数组+红黑树 (提高查询速度)jdk1.8+后。
数组结构;把元素进行了分组(初始长度为16,链表/红黑树结构:把相同哈希值的元素链接到一起(链接到数组相同哈希值的下方)。
如果链表长度超过了8位,就会将链表转换为红黑树,提高查询速度。
set集合存储不重复原理:前提是重写对象的hashCode和equals方法。如String类,Integer类jdk已经重写好了
add方法先调用hashCode看哈希值有没有重复,没有就存储到集合,有就不存储,这就保证的只存储一次。若哈希值有冲突,会调用equals方法,对哈希值相同的元素进行比较,相同就不会存储第二个元素。
可变参数:当方法的参数列表的数据类型已经确定,但参数个数不确定时,就可以使用
格式:定义方法时使用
修饰符 返回值类型 方法名(数据类型 ... 变量名){}
实现原理:
底层是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数。个数可以是0个(返回的是数组的地址)
注意事项:
一个方法参数,只能有一个可以变列表
一个方法的参数有多个,那么可变参数必须写在参数列表的未尾。
可变参数的特殊写法(终极):
Object ... 变量名
Collections:集合的工具类,用来对集合进行操作
常用静态方法:
public static <T> boolean addAll(Collection<T> c, T... elements)
:往集合中添加一些元素。
public static void shuffle(List<?> list) 打乱顺序
:打乱集合顺序。
public static <T> void sort(List<T> list)
:将集合中元素按照默认规则排序。默认是升序
使用前提:被排序的集合,里面存储的元素,必须实现comparable,重写接口中的方法compareTo定义排序规则。
Comparable接口排序规则:
自己(this) - (减号) 参数:升序,反之就是降序//为什么?
可以这样记忆,this看成是一个参照点,减去一个数,相当于参照点变小了,减去的数越大,那么参照点越小,所以是升序
反之,数-参照点,数越大,参照点也越大,相当于是降序。
public static <T> void sort(List<T> list,Comparator<? super T> )
:将集合中元素按照指定规则排序。
Comparator与上一个的Comparable的区别:
Comparable:自己(this)和别人(传递进来的参数)比较,需要实现Comparable接口,重写比较规则 compareTo方法。
Compartor:相当于找一个第三方的裁判,比较两个
排序规则:前面减后面就是升序
Map集合接口:里面有两个泛型<k,v>,<键,值>双列集合
键是唯一的,不允许重复,value可以重复
key与value数据类型可以相同也可以不同
key与value是一一对应的。
常用实现类:
java.util.HashMap<k,v> implements Map<k,v>接口
特点:
底层也是一个哈希表。与HashSet相同。
无序的集合,存储与取出元素的顺序有可能不一样
java.util.LinkedHashMap<k,v> exteds HashMap<k,v>集合
特点:
底层是哈希表+链表,保证迭代的顺序
是一个有序的集合,存储与取出元素的顺序一致。
java.util.Hashtable<k,v>集合 implements Map<kv>接口
特点:
底层也是一个哈希表,是一个线程安全的集合,是单线程的集合速度慢。
HashMap底层也是一个哈希表,是一个线程不安全的集合,多线程,速度快
HashMap集合,可以存储null值,null键
Hshtable集合,不能存储null值,null键
Hashtable和Vector集合一样在jdk1.2之后被<HashMap,ArrayList>取代,但它的子类Properties依然在用,Proaperties集合是一个唯一和IO流相结合的集合
常用方法:
public V put(K key, V value) : 把指定的键与指定的值添加到Map集合中。
返回值:v
存储键值对的时候,key不重复,返回值v是null
key重复,会使用新的value替换map中重复的value,返回被替换的value值
public V remove(Object key) : 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元
值。
返回值v;
key存在,v返回被删除的值
key不存在,v返回null
public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
返回值 v:
key存在,返回对应的value值
不存在,返回null
boolean containKey(object key);//判断集合中是否包含指定的键
包含返回true,不包含返回false
//遍历
public Set<K> keySet() : 获取Map集合中所有的键,存储到Set集合中。
通过键找值方式:
1、使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
2、遍历set集合,获取Map集合中的每一个key
3、通过Map集合中的方法get(key),通过key 找到value
public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(取出来存储到Set集合)。
//Entry对象
Map.Entry<k,v>:在Map接口中有一个内部接口Entry
作用:当Map集合一创建,就会在Map集合中创建一个Entry对象,用来记录键与值(键值对对象)键与值的映射关系。
所以,使用Entry对象遍历步骤:
1、使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,放到一个set集合中。
2、遍历Set集合,获取每一个Entry对象
3、使用Entry对象中的方法getKey()和getValue()获取键与值
使用HashMap存储自定义类型键值:
Map集合保证key值是唯一的
作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一。
jdk9的新特性:
List接口,Set接口,Map接口,里面增加了一个静态方法of,可以给集合一次性添加多个元素
static <E> list<E> of(E... elements)
使用前提:当集合中存储的元素的个数已经确定了,不再改变时使用
注意事项:
1、of方法只适用于List接口,Set接口,Map接口,不适用于接口的实现类
2、of 方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素会抛出异常
3、Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常
idea:Debug追踪:
f8:逐行执行程序
f7:进入到方法中
shift+f8:跳出方法
f9:跳到下一个断点,如果没有,就结束程序
ctrl+f2:退出debug模式