今日内容
数据结构
List子体系
Set子体系
Collections工具类
集合体系
Collection(单列集合)
|-List:存取有序,有索引,可以存储重复元素
|-ArrayList:数组结构
|-Vector:数组结构
|-LinkedList:链表结构
|-Set:存取无序,无索引,不能存储重复元素
|-HashSet:哈希表结构
|-LinkedHashSet:链表哈希表结构
|-TreeSet:二叉树结构
Map(双列集合)
数据结构
栈
一端开口一端封闭
压栈:进栈或者入栈
弹栈:出栈
特点:先进后出
后进先出
举例:
子弹弹夹
超市货架
内存图中的方法进栈出栈
队列
两端开口
特点:先进先出
举例:
火车过山洞
排队
数组
特点:查询快,增删慢
查询快:数组中有连续的索引,查询的时候直接根据索引找到
增删慢:由于数组长度固定,如果要添加或者删除某个元素,必须新建一个数组,然后再将
原数组中的元素复制到新数组中
链表
特点:查询慢,增删快
查询慢:地址不是连续的,必须从头往里一个个开始查找
增删快:增删不会影响链表的整体结构,增删时只要改变节点记录的下一个节点
红黑树
是二叉树中的一种
特点:查询快 排序
List集合
List是一个接口,它继承了Collection接口,所以Collection接口中定义的功能方法在List中都能使用
由于List的特点不一样,比如有索引,所以List除了有共性的方法,还有其特有的方法
都是和索引相关的方法:
void add(int index, E element):将指定的元素添加到指定的索引位置
E get(int index):获取指定索引处的元素
E remove(int index):删除指定索引处的元素,并返回被删除的元素
E set(int index, E element):修改指定索引处的元素
ArrayList
底层是数组数据结构,查询快,增删慢
如果是增删比较多的时候,不选择ArrayList,选LinkedList,否则就选择ArrayList
LinkedList
底层是链表结构,查询慢,增删快
特有方法:
public void addFirst(E e):添加到第一个位置 add(0,e)
public void addLast(E e):添加到最后一个位置 add(list.size(),e)
public void push(E e):相当于addFirst
public E getFirst(); get(0)
public E getLast(); get(list.size()-1)
public E removeFirst(); remove(0)
public E removeLast(); remove(list.size()-1)
public E pop();
Vector
底层是数组结构,出现的版本JDK1.0,集合体系(框架)是JDK1.2出现
面试题:ArrayList和Vector的区别?
ArrayList的出现替代了Vector,Vector和ArrayList大致相同,ArrayList做了两点改进:
(1)方法的名称进行规范和简化
void addElement(E obj) ->boolean add(E e)
elements() ->iterator()
E elementAt(int index) ->E get(int index)
(2)效率提高了
Vector是同步的,多线程下安全,加了同步锁,加锁之后每次执行需要判断锁,效率低
ArrayList是不同步的,多线程下不安全,没有加同步锁,不需要判断锁,效率高
面试题:迭代器与(Iterator)枚举(Enumeration)的区别?
迭代器与(Iterator)枚举(Enumeration)有两点不同:
(1)迭代器可以移除 collection 中的元素,而枚举没有提供移除(remove)的功能。
(2)方法名称得到了改进。
boolean hasMoreElements() -> boolean hasNext()
E nextElement() -> E next()
Set集合
Set接口中的方法和Collection中的完全一样,没有特有方法,不用单独学习了
Set的特点:
(1)不保证有序
(2)无索引,不能操作所有和索引相关的方法
(3)不能存储重复元素
Set虽然不保证有序,但是遍历出来的结果是固定的
HashSet
// 创建HashSet集合对象
// 添加元素,使用add方法
// 遍历,使用迭代器和增强for
哈希值
哈希值就是一个十进制的整数
通过hashCode方法可以得到哈希值
如果没有重写Object类中的hashCode方法,可以反映对象的内存地址值
如果重写了Object类中的hashCode方法,就不能反映对象的内存地址值
不同的对象哈希值不一般不同,也有可能相同,但是相同对象的哈希值一定相同
哈希值相同,说明一定是同一个对象吗? 不一定
哈希值不同,说明一定是不同对象吗? 一定
HashSet集合不能存储重复元素的原理
HashSet底层添加方法(add)依赖的是hashCode和equals方法
首先调用的是hashCode计算哈希值,比较集合中的元素是否和该哈希值相同,
如果哈希不同直接认为是不同元素,进行存储,这时不需要调用equals方法。
如果哈希值相同,此时就需要继续借助equals方法来判断,比较的是内容
如果equals比较的结果为true,则认为是相同元素,不存储
如果equals比较的结果为false,则认为是不同的元素,存储
hashCode粗过滤,它存在意义就是为了减少equals的执行次数,hashCode重写的原则是让不同的成员变量的对象哈希值尽量不同
equals完全过滤,重写比较其中的内容
结论:HashSet存储自定义对象,如果想保证去重,必须重写hashCode和equals方法
重写使用快捷键:alt+insert 选择hashCode和equals
课堂练习:
使用HashSet存储Student自定义对象,有四个Student对象分别是:
向问天,20
叶良辰,18
李天一,16
叶良辰,18
我们认为姓名和年龄相同的学生为同一个学生,希望对是同一个的学生进行去重。
LinkedHashSet
是HashSet的子类,HashSet中的方法它都能使用
特点:
(1)有序(保证怎么存就怎么取)
(2)无索引
(3)不能存储重复元素
该集合除了有序之外,其余的都和父类HashSet一样
课堂练习:
定义一个集合,存储一些列字符串:"hello","world","php","hello","hello","java"
要求去除重复的字符串,并且保证元素取出的顺序和存储的顺序一致
选择LinkedHashSet集合
Collections工具类
可变参数
JDK1.5的新特性(自动拆装箱、泛型、增强for、可变参数、枚举)
格式:
数据类型... 变量名
使用的位置
只能在方法的小括号中,当作方法的形式参数使用
修饰符 返回值类型 方法名(数据类型... 变量名){
}
可变参数本质
它是一个数组
使用场景
当参数的类型确定,但是传递的个数不确定的时候
当参数的类型不确定,传递的个数也不确定就可以使用终极版本:Object... 变量名
两种排序方式:
自然排序(Comparable接口)
(1)要进行排序的对象所在的类必须实现该接口
(2)实现int compareTo(T o) 方法,定义比较的规则
比较器排序(Comparator接口)
(1)创建一个比较器对象[使用匿名内部类创建对象,自定义一个实现类]
(2)实现int compare(T o1, T o2) 方法,定义比较的规则
(3)当做参数传递到需要比较器的方法中,比如:
static <T> void sort(List<T> list, Comparator<? super T> c)
其中第二个参数传递的就是比较器对象
以上两种方式都可以定义比较的规则
(1)如果是JDK提供的类,比如Integer、String,已经实现了第一种自然排序(Comparable接口)方法,按升序排
如果不想要第一种排序方式默认的排序规则,我们就可以再使用第二种排序方式对第一排序方式的规则进行覆盖
(2)如果是自定义的类,没有定义排序的规则,以上两种排序方式我们都可以选择
如果两种排序方式都存在的情况下,优先使用第二种的排序规则