文章目录
- 集合框架
- Collection接口
- 迭代器
- 迭代器基本使用
- 迭代器底层原理
- 并发修改异常
- 数据结构
- 栈
- 队列
- 数组
- 链表
- List接口
- 底层源码分析
- LinkList集合
- LinkedList底层成员解释说明
- LinkedList中get方法的源码分析
- LinkedList中add方法的源码分析
- 增强for
- 增强for的介绍以及基本使用发
- 2.使用增强for的注意事项
- 集合工具类
- 比较器
- 泛型
- 为什么要使用泛型
- 泛型的定义
- 含有泛型的类
- 含有泛型的方法
- 含有泛型的接口
- 泛型的高级使用
- 泛型的上限和下限
集合框架
概述:容器
作用:一次存储多个数据
特点:
长度可变
只能存储引用数据类型的数据
有很多的方法直接操作元素,方便
单列集合:一个元素由一部分构成
list.add(“张三”)
双列集合:一个元素由两部分构成------ key value形式 键值对形式
map.put(“张三”,“18”)
Collection接口
概述:Collection是单列集合的顶级接口
特点:
a.元素有序
b.元素可重复
c.没有索引
创建
Collection 集合名 = new ArrayList()
a.E:代表的是集合元素的具体类型
b.<>里面只能存储引用类型,如果啥也不写,默认为Object类型
----- 不对
---- 对
------对
等号右边的泛型可以空着
5.方法:
boolean add(E e) : 将给定的元素添加到当前集合中(我们一般调add时,不用boolean接收,因为add一定会成功)
boolean addAll(Collection<? extends E> c) :将另一个集合元素添加到当前集合中 (集合合并)
void clear():清除集合中所有的元素
boolean contains(Object o) :判断当前集合中是否包含指定的元素
boolean isEmpty() : 判断当前集合中是否有元素->判断集合是否为空
boolean remove(Object o):将指定的元素从集合中删除
int size() :返回集合中的元素数。
Object[] toArray(): 把集合中的元素,存储到数组中
Collection<String> collection = new ArrayList<String>();
//往集合中添加元素
collection.add("李云龙");
collection.add("丁伟");
collection.add("孔捷");
collection.add("楚云飞");
System.out.println(collection);
//将另一个集合元素添加到当前集合中,集合合并
Collection<String> collection1 = new ArrayList<String >();
collection1.add("魏大勇");
collection1.add("大彪");
collection1.add("段鹏");
System.out.println(collection1);
//将另一个集合元素添加到当前集合中(集合合并)
collection1.addAll(collection);
System.out.println(collection1);
//清除集合中所有的元素
collection1.clear();
System.out.println(collection1);
//判断当前集合中是否包含指定元素
System.out.println(collection.contains("李云龙"));
//将指定的元素从集合中删除
collection.remove("孔捷");
System.out.println(collection);
//返回集合中的元素数
System.out.println("collection.size() = " + collection.size());
//将集合中的元素存储到数组中
Object[] array = collection.toArray();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);}
迭代器
迭代器基本使用
概述:Iterator接口
作用: 遍历集合
获取 Collection中的方法 Iterator iterator()
方法: boolean hasNext() ---- 判断集合还有没有下一个元素
E next ---- 获取下一个元素
public class test02 {
public static void main(String[] args) {
Collection<String> collection = new ArrayList<String>();
collection.add("李云龙");
collection.add("丁伟");
collection.add("孔捷");
//定义一个迭代器
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()){
String element1 = iterator.next();
//String element2 = iterator.next();
System.out.println("element1 = " + element1);
//System.out.println("element2 = " + element2);
}
}
}
注意:使用i迭代器时尽量不要连续调用多次next方法获取元素,防止报错
迭代器底层原理
只有ArrayList集合使用迭代器的时候Iterator指向的是Itr,其他集合不一定,比如HashSet集合
public class test03 {
public static void main(String[] args) {
final HashSet<String> set = new HashSet<>();
set.add("孙悟空");
set.add("猪八戒");
set.add("唐僧");
set.add("沙和尚");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
并不是顺序输出
并发修改异常
我们定义一个集合,存储亮剑中三个团长,遍历集合,在遍历的过程中,如果获取出来的是李云龙,就直接在集合中添加”张大彪“
public class test04 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("李云龙");
list.add("孔捷");
list.add("丁伟");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String element = iterator.next();
if ("李云龙".equals(element)){
list.add("张大彪");
}
}
System.out.println(list);
}
}
我么发现报错:ConcurrentModificationException
modCount:实际操作次数
expectionModCount:预期操作次数
结论:当实际操作次数和预期操作次数不相等时,出现并发修改异常
总结:当我们调用add方法,底层单独给modCount+1,但是没有重新将更改后的modCount赋值给二线expectionModCount
再调用next方法时,next方法底层做了一个判断,当实际操作次数和预期操作次数不相等时,出现并发修改异常
拓展:ArrayList集合中的方法:ListIterator()
数据结构
学过数据机构的同学们,对此章节可能会比较了解,这里不做详细的介绍,只简单的过一下 ·
栈
特点: 先进后出
队列
特点:先进先出
数组
特点 查询快,增删慢
查询快:有索引,我们可以通过索引获取对应的元素
增删慢:定长
添加元素:先创建一个新的数组,指定新长度,将老数组的元素复制到新数组中,再添加新的元素
删除元素:先创建一个新的数组,指定新新长度,将老数组的元素复制到新数组中
链表
特点:查询慢,增删快
分类:
单向链表:一个字节分两部分
前面的字节记录后面字节的地址
后面字节不记录前面字节的地址
如果集合底层数据结构用的是单向链表,无法保证元素有序
双向链表:一个字节分三部分
前面的字节机会后面字节的地址
后米娜的字节记录前面字节的地址
如果集合底层数据结构用的是双向链表,能够保证元素有序
List接口
概述:list接口是Collection接口的子接口
实现类
ArrayList,LinkedList,Vector
4.常用方法:
boolean add(E e) -> 将元素添加到集合中->尾部(add方法一定能添加成功的,所以我们不用boolean接收返回值)
void add(int index, E element) ->在指定索引位置上添加元素
boolean remove(Object o) ->删除指定的元素,删除成功为true,失败为false
E remove(int index) -> 删除指定索引位置上的元素,返回的是被删除的那个元素
E set(int index, E element) -> 将指定索引位置上的元素,修改成后面的element元素
E get(int index) -> 根据索引获取元素
int size() -> 获取集合元素个数
public class test05 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("李云龙");
list.add("丁伟");
list.add("孔捷");
list.add("张大彪");
list.add("魏大勇");
list.add("段鹏");
//往指定位置添加元素
list.add(3,"楚云飞");
//删除指定元素,删除成功返回true,失败返回false
list.remove("楚云飞");
//删除指定位置的元素,返回值为删除的元素
System.out.println(list.remove(0));
//将指定索引位置上的元素,修改为后面的元素,返回值为被替换元素的值
System.out.println(list.set(1, "李云龙"));
// System.out.println(list);
//根据索引获取元素
System.out.println(list.get(2));
//获取集合元素的个数
System.out.println(list.size());
//快速遍历集合的方法
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
底层源码分析
ArrayList是一个集合,集合的长度是可变的,ArrayList底层数据结构数组,所以需要进行数组扩容使得数组长度可变
rrayList有一个空参构造: ArrayList() 构造一个初始容量为10的空列表
注意:不是 new就创建一个长的为10的空列表
而是第一次add的时候才会创建长度为10的空列表
扩容方式为
elementData = Arrays.copyOf(elementData, newCapacity);->数组扩容,数组复制
扩容1.5倍
LinkList集合
基本使用
概述:是List接口下的实现类
特点:
a.元素有序
b.元素可重复
c.有索引
d.线程不安全
数据结构双向链表
LinkList 将来我们有可能有大量的首位元素的操作,LinkList有很多特有方法
这些特有防火阀都是直接操作首位元素的
.方法:
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():从此列表所表示的堆栈处弹出一个元素。
public void push(E e):将元素推入此列表所表示的堆栈。
public boolean isEmpty():如果列表不包含元素,则返回true。
public class test06 {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
System.out.println("农药的龙年王者限定皮肤");
list.add("赵云");
list.add("孙尚香");
list.add("孙策");
list.add("安其拉");
list.add("大乔");
System.out.println(list);
//将指定元素插入到列表开头
list.addFirst("龙年限定");
//将指定元素插入得到列表结尾
list.addLast("就这五个");
//返回列表的第一个元素
System.out.println(list.getFirst());
//返回列表的最后一个元素
System.out.println(list.getLast());
//移出并返回列表的第一个元素
System.out.println(list.removeFirst());
//移出并返回列表的最后一个元素
System.out.println(list.removeLast());
//从此列表表示的堆栈处弹出一个元素,底层调用removFirst
list.pop();
//将元素推入到次列表所表示的堆栈,底层调用addFirst
list.push("龙年限定");
}
}
LinkedList底层成员解释说明
1.LinkedList底层成员
transient int size = 0; 元素个数
transient Node first; 第一个节点对象
transient Node last; 最后一个节点对象
2.Node代表的是结点对象
private static class Node {
E item;//节点上的元素
Node next;//记录着下一个节点地址
Node prev;//记录着上一个节点地址
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
LinkedList中get方法的源码分析
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
LinkedList中add方法的源码分析
LinkedList<String> list = new LinkedList<>();
list.add("a");
list.add("b");
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
增强for
增强for的介绍以及基本使用发
作用 遍历集合或者数组
格式
for(元素的数据类型 变量名:要遍历的集合名或者数组名){
变量代表的就是每一个元素
}
快捷键
集合名或者数组名.,for
ArrayList<String> list = new ArrayList<>();
list.add("李云龙");
list.add("丁伟");
list.add("孔捷");
list.add("张大彪");
list.add("魏大勇");
list.add("段鹏");
for (String s : list) {
System.out.println(s);
}
int[] arr = {1, 2, 3, 4, 5};
for (int i : arr) {
System.out.println(i);
}
2.使用增强for的注意事项
1.在使用增强for遍历集合的时候尽量也不要随意改变集合长度,不然也会出现"并发修改异常"
a.增强for在遍历集合的时候,实现原理为迭代器
b.增强for在遍历数组的时候,实现原理为普通for
public class test07 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("李云龙");
list.add("丁伟");
list.add("孔捷");
list.add("张大彪");
list.add("魏大勇");
list.add("段鹏");
for (String s : list) {
System.out.println(s);
}
int[] arr = {1, 2, 3, 4, 5};
for (int i : arr) {
System.out.println(i);
}
集合工具类
概述:Collections集合工具类
特点
构造私有
成员方法是静态的
使用
类名直接调用
常用方法
static boolean addAll(Collection<? super T> c, T... elements)->批量将元素存到集合中 static void shuffle(List<?> list) -> 将集合中的元素顺序打乱
static void sort(List list) ->将集合中的元素按照默认规则排序->ASCII
static void sort(List list, Comparator<? super T> c)->将集合中的元素按照指定规则排序
public class test01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//批量将元素存到集合中
Collections.addAll(list,"李玉龙","孔捷","丁伟");
System.out.println(list);
System.out.println("============================");
//将集合中的元素打乱
Collections.shuffle(list);
System.out.println(list);
//将集合中的元素按照默认规则排序 ASCII
Collections.sort(list);
System.out.println(list);
}
}
比较器
概述 Comparator:接口–比较器
方法:
int compare(T o1,T o2) ----- 设置比较规则
o1-o2 ----- 升序
o2-o1 ------降序
相关代码,首先构造javabean
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" + name + '\'' + ",age:" +age+'}';
}
@Override
public int compareTo(Person o) {
return o.getAge() - this.getAge();
}
}
构建测试类
public class test01{
public static void main(String[] args) {
final ArrayList<Person> list = new ArrayList<>();
list.add(new Person("刘备",30));
list.add(new Person("关羽",48));
list.add(new Person("张飞",45));
System.out.println(list);
//由于sort继承comparable.调用重写的方法
Collections.sort(list);
System.out.println(list);
}
}
泛型
使用
注意:
泛型中写的类型都是引用数据类型
如果<>中什么都不写,元素默认类型为Object类型
为什么要使用泛型
从使用上看,如果使用了泛型,规定了数据类型,那么数据类型是一致的,防止了类型转换异常
从定义上看,定义泛型以后,在使用的时候确定啥类型,泛型就是啥类型,通用
泛型的定义
含有泛型的类
定义格式:
piublc class 类名{ }
什么时候确定泛型类型
new对象的时候确定类型
public class MyArrayList <E>{
public void add(E e){
System.out.println(e);
}
}
public class test02 {
public static void main(String[] args) {
final MyArrayList<String> list = new MyArrayList<>();
list.add("李云龙");
final MyArrayList<Integer> list1 = new MyArrayList<>();
list1.add(123);
}
}
含有泛型的方法
格式 修饰符 返回值类型 方法名(E e) { }
调用的时候确定类型
public class Mylist {
public <E> void add(E e){
System.out.println(e);
}
}
测试类
public class test03 {
public static void main(String[] args) {
final Mylist mylist = new Mylist();
mylist.add(1);
mylist.add("李云龙");
}
}
含有泛型的接口
格式 public interfa 接口名{}
什么时候确定类型
在实现类的时候确定类型 比如Scanner
在实现类的时候还不确定类型,只能在new的时候确定类型 ---- 比如 ArrayList
public interface MyList <E>{
public void add(E e);
}
public class MyScanner implements MyList<String>{
@Override
public void add(String s) {
System.out.println(s);
}
}
public class MyScanner implements MyList<String>{
@Override
public void add(String s) {
System.out.println(s);
}
}
public class Test01 {
public static void main(String[] args) {
MyScanner myScanner = new MyScanner();
myScanner.add("哈哈哈");
}
}
泛型的高级使用
什么时候使用泛型通配符:参数位置当不知道接收什么类型时 ------ 一般用在集合方面
用在什么位置上 一般用在参数位置上
import java.util.ArrayList;
public class test06 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("李云龙");
list.add("孔捷");
list.add("丁伟");
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
method(list);
method(list1);
}
public static void method(ArrayList<?> list){
for (Object o : list) {
System.out.println(o);
}
}
}
泛型的上限和下限
泛型通配符的高级使用 受限泛型
上限:
a.格式: 类型名称<? extends 类> 对象名
b,意义:?只能接收extends后面的本类以及子类
下限
a.格式:类型名称<? super 类> 对象名
b.意义: ?只能接受super后面的本类以及父类
import java.util.ArrayList;
import java.util.Collection;
public class test07 {
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<>();
Collection<String> list2 = new ArrayList<>();
Collection<Number> list3 = new ArrayList<>();
Collection<Object> list4 = new ArrayList<>();
getElement1(list1);
//getElement1(list2); 报错
getElement1(list3);
//getElement1(list4); 报错
System.out.println("================================");
//getElement2(list1); 报错
//getElement2(list2); 报错
getElement2(list3);
getElement2(list4);
}
// 上限 ?只能接受extends后面的本类以及子类
public static void getElement1(Collection<? extends Number> collection){
}
//下限 ?只能接受super后的本类以及父类
public static void getElement2(Collection<? super Number> collection){
}
}