一.List接口
1.1 List接口的特点
a.List接口 继承 Collection接口
b.List接口的特点:
有序的(Java中的有序不是指自然顺序,而是指存取元素的顺序是一致的,什么顺序存就怎么取)
有索引的
元素可重复的(存储的元素可以重复)
1.2 List接口中常用的方法以及常用实现类
a.List接口继承Collection接口,所以已经有了collection中的8个(7个常见+iterator)
b.List接口还有自己的特有方法(4个):
增:add(int index,E e)
删:remove(int index,E e)
改:set(int index,E e)
查:get(int index,E e)
c.List接口有哪些实现类
ArrayList[]
LinkedList[]
Vector[]
1.3 ArrayList的数据结构以及使用
a.ArrayList集合的方法(7个collection+1个迭代器+4个List接口中的)
特有方法:无
b.ArrayList集合底层采用的是数组结构,特点:查改快,增删慢
c.使用ArrayList
1 | public static void main(String[] args) { |
List的并发修改异常
并发修改异常:ConcurrentModificationException
•ConcurrentModificationException
产生原因:
•迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成类迭代器获取元素中判断欲求修改值和实际修改值不一致
解决方案:
•用for循环遍历,然后用集合对象做对应的操作即可(get方法)
ListIterator:列表迭代器
•通过List集合的listIterator()方法得到,它是List集合特有的迭代器
•用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
ListIterator中的常用方法
•E next();返回迭代中的下一个元素
•boolean hasNext();如果迭代器具有更多元素,则返回true
•E previous();返回迭代中的上一个元素
•boolean hasPrevious();如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true
•void add(E e);将指定的元素插入列表
1.4 LinkedList的数据结构以及使用
a.LinkedList的方法(7个collection+1个迭代器+4个List接口中的)
有特有方法:
public void addFirst(E e);//添加元素到集合首
public void addLast(E e);//添加元素到集合尾
public E getFirst(E e);//获取集合的首元素
public E getLast(E e);//获取集合的尾元素
public E removeFirst(E e);//删除集合的首元素
public E removeLast(E e);//删除集合的尾元素
public void pop(E e);//删除集合中的首元素,底层就是removeFirst
public void push(E e);//添加集合中的首元素,底层就是addFirst
源码:
1 | public E pop() { |
b.LinkedList底层采用的是链表结构,特点:查改慢,增删快
c.使用LinkedList
1 | LinkedList<String> list = new LinkedList<String >(); |
1.5 LinkedList的源码分析
a.LinkedList底层采用的是链表结构(双向列表)
b.LinkedList这个类有两个成员变量
Node first;记录了开始结点
Node last;记录了结束结点
c.结点类Node,它是LinkedList的内部类
1 | private static class Node<E> { |
d.LinkedList的add方法
I.将新增的结点,添加到last之后
II.并且将size++,总元素个数加一
1 | public boolean add(E e) { |
e.LinkedList的get方法
I.先查找指定索引的结点,(从前往后找,从后往前找)
II.找到结点后,获取结点的数据栈,然后返回
完整版:
•LinkedList的成员变量源码分析:
1 | public class LinkedList<E> extends AbstractSequentialList<E> |
•LinkedList的内部类Node类源码分析:
1 | public class LinkedList<E> extends AbstractSequentialList<E> |
•LinkedList的add()方法源码分析:
1 | public boolean add(E e) { |
•LinkedList的get()方法:
1 | public E get(int index) { |
二.Collections类
2.1 Collections的介绍
Collections不是collection!
作用:Collections是一个集合的工具类,该类中有一堆静态方法,专门操作集合
2.2 Collections常用功能
public static void shuffle(List list);//随机打乱集合中元素的顺序 public static void sort(List list);//将集合中的元素进行升序排序
扩展:Collections的sort方法,默认是对集合中对元素进行升序排序
如果集合的泛型是数值类型,那么按照数值的大小升序
如果集合的泛型是Character类型,那么按照字母的码值排序
如果集合的泛型是String类型,那么按照字母首字母排序,若一样,次字母排序,依次类推
提示:Collections.sort方法结论和Array.sort()是一样的
1 | public static void main(String[] args) { |
2.3 Comparator比较器排序
Collections还有一个sort方法:
public static void sort(List list,Comparator com);带有比较器的排序方法
这个比较器源码:
1 | public interface Comparator<T>{ |
我们注意到Comparator实际上是一个接口,那么我们在调用sort方法时,需要传人一个该接口的实现类对象(匿名内部类)
降序排序
1 | Collections.sort(arr, new Comparator<Integer>() { |
自定义排序
1 | public static void main(String[] args) { |
2.4 可变参数
a.什么是可变参数:是指方法参数的个数可以任意[JDK 1.5]
b.可变参数的格式:
数据类型 … 变量名
1
public static int getSum(int … a){}
可变参数的本质其实就是一个数组;
注意事项:
a.一个方法中最多只能有一个可变参数
b.一个方法中如果既有正常参数,又有可变参数,那么可变参数必须写在最后面
1 | public static void main(String[] args) { |
2.5 可变参数的应用场景
Arrays工具类中有一个静态方法:
•public static List asList<T…a>:返回由指定数组支持的固定大小的列表
•返回的集合不能做 增 删 操作,可以做修改操作
List接口中有一个静态方法:
•public static List of(E…elements):返回包含任意数量元素的不可变列表
•返回的集合不能做 增 删 该 操作
Set接口中有一个静态方法:
•public static Set of(E…elements):返回一个包含任意数量元素的不可变集合
•在给元素时,不能给重复的元素
例:
1 |
|
一次性向集合中添加多个元素
三.Set接口
3.1 Set接口的特点
a.Set接口也是继承Collection接口
b.Set接口的特点:
无序的(指存取顺序不保证一致)
无索引的(使用不能使用普通for循环遍历)
元素唯一的
但是实际上,严格来说,无序特点是不对的(实现类LinkedHashSet是有序的)
3.2 Set接口的常用方法以及常用实现类
a.Set接口中的方法(7个collection+1个迭代器)
b.Set方法的特有方法:无
c.Set接口的实现类:
HashSet
LinkedHashSet
TreeSet
3.3 HashSet的数据结构以及使用
a.HashSet也没有特有方法
b.HashSet底层采用的是哈希表结构(数组结构+链表结构+红黑树结构)
•对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素 顺序一致
•没有带索引的方法,索引不能使用普通for循环遍历
•Set集合,所以是不包含重复元素的集合
c.HashSet的使用
1 |
|
3.4 LinkedHashSet的数据结构以及使用
a.LinkedHashSet也没有特有方法
b.LinkedHashSet底层采用的是(链表结构+哈希表结构)
•由链表保证元素有序,也就是说元素的存储和取出顺序是一样的
•由哈希表保证元素唯一,也就是说没有重复的元素
c.LinkedHashSet的使用
1 | public static void main(String[] args) { |
3.5 TreeSet的数据结构以及使用
a.TreeSet特点
无序的(无序是存取顺序不保证一致,但是它会以自然顺序输出)
TreeSet是无序的,但是它是无序中的一种特殊存在,有自然顺序!
TreeSet(Comparator comparator):根据指定的比较器进行排序
无索引,所以不能用普通for循环
元素唯一,因为是Set集合
b.TreeSet特有方法:无
c.TreeSet底层采用的是红黑树结构
d.TreeSet的使用
1 | TreeSet<Integer> tree = new TreeSet<Integer>(); |
扩展:
如果TreeSet保存的是数值类型,那么按照数值的大小升序
如果TreeSet保存是Character类型,那么按照字母的码值排序
如果TreeSet保存的是String类型,那么按照字母首字母排序,若一样,次字母排序,依次类推
e.TreeSet也可以使用比较器自定义排列顺序
TreeSet有一个带有比较器的构造方法
1 | public static void main(String[] args) { |
3.6 哈希表结构的的介绍
•对象的哈希值(对象的”数字指纹”,是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值)
a.对象的哈希值,相对于对象的“指纹”,只是这个指纹是一个数字
b.我们如何获取对象的哈希值:调用对象的hashCode()方法即可
1
2
3
4
5
public static void main(String[] args) {
Student s1 = new Student(1, “a”);
int hashCode = s1.hashCode();//返回哈希值
System.out.println(hashCode);
}
c.其实Java中所谓的地址值是假的,它是Hash值的16进制表示
源码
1 | public String toString() { |
d.Java中有真正的地址值,但是当打印时,会自动调用toString方法,将hash值输出
Dog d = new Dog();//d就是真正的地址值
System.out.println(d);//打印时,会自动调toString方法,hex16操作输出
e.不同的两个对象,可能有相同的hashCode(hashCode是int类型,最多42亿,因此会相同)
结论:哈希表结构如何保证元素的唯一性
哈希表结构,如何判断两个元素是否重复:
a.哈希表结构,会先比较两个对象的哈希值
b.当哈希值一样,再调用equals比较两个对象
只有哈希值相同,并且equals结构为true,才判定这两个元素是重复的
哈希表结构=数组结构+链表结构+红黑树结构(JDK8)
数组结构默认长度16
I.向哈希值中添加元素时,元素的索引:元素.hashCode()%数组长度 =0-15
II.当某个链表长度超过阀值(8)时,这个链表就会变成红黑树
3.7 哈希表结构保存自定义类型练习
为了保证哈希表中元素的唯一性,如果元素是自定义类型,那么必须重写hashCode和equals方法
1 | public class Dog { |
3.8 HashSet的源码分析
a.构造方法
1 | public class HashSet<E> extends AbstractSet<E> |
b.HashMap的add方法
1 | public class HashSet { //...... |
c.HashMap的put方法
HashMap保存键时,是以键的哈希值为依据确定键的保存位置
添加成功之后,size++,将元素的个数增加1
1 | public class HashMap { //...... |
总结:
Collection
{
Iterator it = cc.iterator();
public boolean add(E e);添加元素,返回值表示是否添加成功。
public boolean remove(E e);删除元素,返回值表示是否删除成功。
无修改方法。
无查询方法。
public boolean contains(Object obj);判断集合中是否包含某个元素。
public void clear();清空集合(把集合中的元素全部删除,不是把集合置为Null)
public boolean isEmpty();判断集合是否为空(指集合中没有元素,而非集合是否为Null)
public int size();返回集合中元素的个数
public Object[] toArray();将集合转成数组
}
List接口:
特点:有序,有索引,元素可重复
特有方法:
add(int index,E e);
remove(int index,E e);
set(int index,E e);
get(int index,E e);
ArrayList:
底层是数组结构
特有方法:无
特点:有序,有索引,元素可重复
LinkedList
底层是链表结构
特有方法:
public void addFirst(E e);//添加元素到集合首
public void addLast(E e);//添加元素到集合尾
public E getFirst(E e);//获取集合的首元素
public E getLast(E e);//获取集合的尾元素
public E removeFirst(E e);//删除集合的首元素
public E removeLast(E e);//删除集合的尾元素
public void pop(E e);//删除集合中的首元素,底层就是removeFirst
public void push(E e);//添加集合中的首元素,底层就是addFirst
特点:有序,有索引,元素可重复
Set接口:
特点:无序(LinkedHashSet除外),无索引,元素唯一
特有方法:无
特点:无索引,元素唯一
HashSet
底层是哈希表结构(数组结构+链表结构+红黑树结构)
特有方法:无
特点:无序,无索引,元素唯一
LinkedHashSet
底层是(链表结构+哈希表结构)
特有方法:无
特点:有序,无索引,元素唯一
TreeSet
底层是红黑树结构
特有方法:无
特点:无序的(无序是存取顺序不保证一致,但是它会以自然顺序输出),无索引,元素唯一
使用哈希表保存自定义类型时,为了保证元素的唯一性,要重写自定义类型中的hashCode方法和equals方法