第一章.集合框架(单列集合)
1.集合:分为两大类
2.分类:
单列集合:集合中的元素单独保存
list.add("张三");
list.add("李四");
双列集合:集合中的元素都是成对出现(键值对 key value形式)
map.put("涛哥","柳岩")
1.概述:容器
2.作用:存储数据
3.特点:
a.只能存储引用数据类型
b.长度可变
c.集合有很多强大的方法来直接操作元素
第二章.Collection接口
1.概述:单列集合的顶级接口
2.特点:
a.元素有序
b.元素可重复
c.无索引(没有通过索引操作元素的方法)
3.使用:
Collection<E> 集合名 = new 实现类对象<E>()
a.<E>:泛型 -> a.泛型必须是引用数据类型 b.泛型是为了明确,集合中元素的数据类型
c.如果要是不指定,默认泛型为Object类型
b.比如:Collection<String> 集合名 = new 实现类对象<String>()
c.注意:等号右边的泛型可以不写
4.方法:
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(): 把集合中的元素,存储到数组中
public class Test01 {
public static void main(String[] args) {
//创建Collection集合
Collection<String> collection = new ArrayList<String>();
//boolean add(E e) : 将给定的元素添加到当前集合中(我们一般调add时,不用boolean接收,因为add一定会成功)
collection.add("张三");
collection.add("李四");
collection.add("王五");
collection.add("赵六");
collection.add("田七");
collection.add("猪八");
collection.add("猪八");
System.out.println(collection);
/*
boolean addAll(Collection<? extends E> c) :将另一个集合元素添加到当前集合中 (集合合并)
参数:Collection接口类型
*/
Collection<String> collection1 = new ArrayList<String>();
collection1.add("刘备");
collection1.add("关羽");
collection1.add("张飞");
collection1.add("赵云");
collection1.add("黄忠");
collection1.add("马超");
collection.addAll(collection1);
System.out.println(collection);
Collection<String> collection2 = new ArrayList<>();
collection2.add("释迦牟尼佛");
collection2.add("斗战胜佛");
collection2.add("旃檀功德佛");
collection2.add("阿弥陀佛");
collection2.add("南无大圣舍利尊王佛");
//void clear():清除集合中所有的元素
/*collection2.clear();
System.out.println(collection2);*/
//boolean contains(Object o) :判断当前集合中是否包含指定的元素
boolean result01 = collection2.contains("斗战胜佛");
System.out.println("result01 = " + result01);
//boolean isEmpty() : 判断当前集合中是否有元素->判断集合是否为空
System.out.println(collection2.isEmpty());
//boolean remove(Object o):将指定的元素从集合中删除
/*
boolean result02 = collection2.remove("南无大圣舍利尊王佛");
System.out.println("result02 = " + result02);
System.out.println(collection2);
*/
//int size() :返回集合中的元素数。
System.out.println(collection2.size());
//Object[] toArray() : 把集合中的元素,存储到数组中
Object[] array = collection2.toArray();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
第三章.迭代器
1.迭代器基本使用
1.概述:迭代器是一个接口-> Iterator
2.获取:
Collection中的方法:Iterator<E> iterator() -> 凡是Collection以及实现类都可以用此方法获取迭代器对象
3.方法:
boolean hasNext() -> 判断是否有下一个元素
E next() -> 获取下一个元素
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("孙悟空");
list.add("二郎神");
list.add("哮天犬");
list.add("姜子牙");
//获取迭代器对象
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
经验值:使用迭代器时尽量不要连续调用多次next()方法获取元素
public class Test01 { 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()){ System.out.println(iterator.next()); //System.out.println(iterator.next()); } } }
2.迭代器迭代原理
3.迭代器底层原理
Iterator<String> iterator = list.iterator();
等号左边是Iterator接口,必然会接收一个实现类,实现类是哪个实现类呢?
1.注意:
Iterator指向ArrayList内部类Itr,这种情况,仅仅局限于迭代ArrayList集合
2.如果迭代HashSet集合,Iterator指向的实现类就不是Itr,那么是谁呢?
4.并发修改异常
1.需求:定义集合,存储"孙悟空","唐僧","猪八戒","沙和尚",遍历集合,在遍历的过程中,如果获取出来的是猪八戒,就直接在集合中添加"白龙马"
public class Test02 {
public static void main(String[] args) {
/*
1.需求:定义集合,存储"孙悟空","唐僧","猪八戒","沙和尚",
遍历集合,在遍历的过程中,如果获取出来的是猪八戒,就直接在集合中添加"白龙马"
*/
ArrayList<String> list = new ArrayList<>();
list.add("孙悟空");
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);
}
}
Exception in thread "main" java.util.ConcurrentModificationException--> 并发修改异常
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at com.atguigu.b_iterator.Test02.main(Test02.java:21)
结论:使用迭代器的过程中,不能随便改变集合长度
问题1.为什么上面的代码会出现并发修改异常呢?
=======================================
Iterator<String> iterator = list.iterator();
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
/*
modCount:实际操作次数
expectedModCount:预期操作次数
*/
int expectedModCount = modCount;
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
}
final void checkForComodification() {
/*
如果实际操作次数不等于预期操作次数
直接抛出"并发修改异常"
*/
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
结论:当实际操作次数不等于预期操作次数直接抛出"并发修改异常"
问题2:我们做什么操作了,导致了modCount和expectedModCount不相等了呢? -> 调用了ArrayList中的add方法
==========================================================================================
list.add("白龙马");
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
}
最总结论:为甚出现并发修改异常
当调用add时,只给modCount++了,然后expectedModCount并没有被重新赋值,此时再调用next方法,next方法底层直接做了判断
如果modCount和expectedModCount不相等,就直接出现"并发修改异常"
扩展:ListIterator迭代器(了解)
public class Test02 { public static void main(String[] args) { /* 1.需求:定义集合,存储"孙悟空","唐僧","猪八戒","沙和尚", 遍历集合,在遍历的过程中,如果获取出来的是猪八戒,就直接在集合中添加"白龙马" */ ArrayList<String> list = new ArrayList<>(); list.add("孙悟空"); list.add("唐僧"); list.add("猪八戒"); list.add("沙和尚"); /* Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ String element = iterator.next(); if ("猪八戒".equals(element)){ list.add("白龙马"); } }*/ ListIterator<String> iterator = list.listIterator(); while(iterator.hasNext()){ String element = iterator.next(); if ("猪八戒".equals(element)){ iterator.add("白龙马"); } } System.out.println(list); } }
第四章.数据结构
1.栈
1.特点:
先进后出
2.好比:手枪压子弹
2.队列
1.特点:先进先出
2.好比:排队
3.数组
1.特点:
查询快(有索引)
增删慢(定长)
2.如果想往数组中添加一个元素,首先要创建一个新数组,将老数组的元素复制到新数组中,然后在最后添加新的元素
4.链表
1.特点:
查询慢
增删快
2.分类:
单向链表
双向链表
4.1单向链表
1.特点:
一个节点分成2部分
第一部分:数据域-> 存数据
第二部分:指针域-> 下一个元素的地址
2.前面的节点记录后面的节点地址
但是后面的节点地址不记录前面的节点地址
3.如果集合底层是单向链表,无法保证元素有序
4.2双向链表
1.特点:
一个节点分3部分
第一部分:上一个节点地址
第二部分:数据域
第三部分:下一个节点地址
2.一个节点,既记录上一个节点地址,也记录下一个节点地址
前面记录后面的节点,后面记录前面的节点
3.如果集合底层数据结构是双向链表,能保证元素有序
第五章.List接口
1.概述:
List接口是Collection接口的子接口
2.特点:
a.元素有序
b.元素可重复
c.有索引
3.数据结构:不同的实现类数据结构不同
第六章.List集合下的实现类
1.ArrayList集合
1.概述:ArrayList是List接口的实现类
2.特点:
a.元素有序
b.元素可重复
c.有索引
3.数据结构:
数组
4.使用:
ArrayList<泛型> 集合名 = new ArrayList<>()
5.常用方法:
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() -> 获取集合元素个数
1.1.ArrayList集合使用
public class Demo01ArrayList {
public static void main(String[] args) {
//创建ArrayList集合
ArrayList<String> list = new ArrayList<String>();
//boolean add(E e) -> 将元素添加到集合中->尾部(add方法一定能添加成功的,所以我们不用boolean接收返回值)
list.add("玉皇大帝");
list.add("王母娘娘");
list.add("涛哥");
list.add("如来佛祖");
System.out.println(list);
//void add(int index, E element) ->在指定索引位置上添加元素
list.add(0, "翠儿");
System.out.println(list);
//boolean remove(Object o) ->删除指定的元素,删除成功为true,失败为false
/*boolean result01 = list.remove("涛哥");
System.out.println(result01);
System.out.println(list);*/
//E remove(int index) -> 删除指定索引位置上的元素,返回的是被删除的那个元素
/*System.out.println(list.remove(0));
System.out.println(list);*/
//E set(int index, E element) -> 将指定索引位置上的元素,修改成后面的element元素
String element1 = list.set(0, "太上老君");
System.out.println(element1);
System.out.println(list);
//E get(int index) -> 根据索引获取元素
System.out.println(list.get(0));
//int size() -> 获取集合元素个数
System.out.println(list.size());
}
}
//遍历ArrayList集合
public class Demo02ArrayList {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("岳不群");
list.add("林平之");
list.add("东方不败");
list.add("任我行");
list.add("尹志平");
//迭代器
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("======================");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("======================");
/*
遍历快捷键
集合名.fori
*/
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
经验值:
public class Demo03ArrayList { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(2); /* 集合只有一个元素 如果直接调用remove传递2 2默认类型为int型 所以会直接调用删除指定索引位置上的元素的那个remove 解决: 将2变成Integer类型 */ //list.remove(2); list.remove(new Integer(2)); System.out.println(list); } }
1.2.底层源码分析(扩展)
1.ArrayList构造:
a.ArrayList() 构造一个初始容量为 10 的空列表(数组)
并不是一new ArrayList底层就会马上创建一个容量为10的空列表
而是在第一次add的时候ArrayList底层才会马上创建一个容量为10的空列表
b.ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表。
2.数组是定长的,集合长度可变,那么ArrayList底层是数组,为什么还要说ArrayList长度可变呢?怎么变的长度?
elementData = Arrays.copyOf(elementData, newCapacity);
3.如果超出了数组的初始化容量,ArrayList底层自动扩容,怎么扩的?
elementData = Arrays.copyOf(elementData, newCapacity);
4.扩容多少倍? 1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
ArrayList<String> list = new ArrayList<>();
=========================================================================
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
transient Object[] elementData;-> ArrayList底层数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
==========================================================================
在第一次add的时候ArrayList底层才会马上创建一个容量为10的空列表
list.add("abc");
public boolean add(E e) {//e -> abc
ensureCapacityInternal(size + 1); // Increments modCount!!
}
private void ensureCapacityInternal(int minCapacity --> 1) {
// ensureExplicitCapacity(10);
ensureExplicitCapacity(calculateCapacity(elementData-> 数组 , minCapacity -> 1));
}
private static int calculateCapacity(Object[] elementData -> 数组, int minCapacity -> 1) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY ->10, minCapacity-->1); //返回10
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity-->10) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity-->10);
}
private void grow(int minCapacity-->10) {
// overflow-conscious code
int oldCapacity = elementData.length;//0
int newCapacity = oldCapacity + (oldCapacity >> 1);// 0+(0/2) 0
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;// 10
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
/*
elementData = Arrays.copyOf(elementData,10)-> 数组扩容
*/
elementData = Arrays.copyOf(elementData, newCapacity);
}
=============================================================
ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表。
ArrayList<String> list = new ArrayList<>(10);
public ArrayList(int initialCapacity-->10) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
第七章.LinkedList集合
1.概述:LinkedList 是List的实现类
2.特点:
a.元素有序
b.有索引
c.元素可重复
3.底层数据结构:
双向链表
4.常用方法->很多直接操作首尾元素的方法
- 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 Demo05LinkedList {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
list.add("柳岩");
list.add("金莲");
list.add("松下");
list.add("三上");
list.add("大桥");
list.add("涛哥");
//- public void addFirst(E e):将指定元素插入此列表的开头。
list.addFirst("大郎");
System.out.println(list);
//- public void addLast(E e):将指定元素添加到此列表的结尾。
list.addLast("二郎");
System.out.println(list);
//- public E getFirst():返回此列表的第一个元素。
System.out.println(list.getFirst());
//- public E getLast():返回此列表的最后一个元素。
System.out.println(list.getLast());
//- public E removeFirst():移除并返回此列表的第一个元素。
System.out.println(list.removeFirst());
System.out.println(list);
//- public E removeLast():移除并返回此列表的最后一个元素。
list.removeLast();
System.out.println(list);
}
}
public class Demo06LinkedList {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
list.add("柳岩");
list.add("金莲");
list.add("松下");
list.add("三上");
list.add("大桥");
list.add("涛哥");
//迭代器
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//普通for
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
- public E pop():从此列表所表示的堆栈处弹出一个元素。
- public void push(E e):将元素推入此列表所表示的堆栈
public class Demo07LinkedList {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
list.add("柳岩");
list.add("金莲");
list.add("松下");
list.add("三上");
list.add("大桥");
list.add("涛哥");
System.out.println(list);
//- public E pop():从此列表所表示的堆栈处弹出一个元素。
list.pop();
System.out.println(list);
//- public void push(E e):将元素推入此列表所表示的堆栈
list.push("张三");
System.out.println(list);
}
}
第八章.LinkedList集合
1.LinkedList集合
1.概述:LinkedList是List的实现类
2.特点:
元素有序
元素可重复
有索引
3.数据结构:链表(双向链表)
4.特有方法:
- 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 Demo01LinkedList {
public static void main(String[] args) {
//创建LinkedList集合对象
LinkedList<String> list = new LinkedList<>();
list.add("张无忌");
list.add("张三丰");
list.add("张翠山");
list.add("赵敏");
list.add("周芷若");
//- public void addFirst(E e):将指定元素插入此列表的开头。
list.addFirst("玄冥二老");
System.out.println(list);
//- public void addLast(E e):将指定元素添加到此列表的结尾。
list.addLast("灭绝师太");
System.out.println(list);
//- public E pop():从此列表所表示的堆栈处弹出一个元素。
//list.pop();
//System.out.println(list);
//- public void push(E e):将元素推入此列表所表示的堆栈。
list.push("金毛狮王");
System.out.println(list);
System.out.println("===========================");
//普通for遍历
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//迭代器
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
1.1 LinkedList底层成员解释说明
1.LinkedList底层成员
transient int size = 0; 元素个数
transient Node<E> first; 第一个节点对象
transient Node<E> last; 最后一个节点对象
2.Node代表的是结点对象
private static class Node<E> {
E item;//节点上的元素
Node<E> next;//记录着下一个节点地址
Node<E> prev;//记录着上一个节点地址
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
1.2 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++;
}
1.3.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;
}
}
index < (size >> 1)采用二分思想,先将index与长度size的一半比较,如果index<size/2,就只从位置0往后遍历到位置index处,而如果index>size/2,就只从位置size往前遍历到位置index处。这样可以减少一部分不必要的遍历
第九章.Collections集合工具类
1.概述:Collections,是集合工具类
2.特点:
a.构造私有
b.方法都是静态的
3.使用:
类名直接调用
4.常用方法:
static <T> boolean addAll(Collection<? super T> c, T... elements)->批量将元素存到集合中
static void shuffle(List<?> list) -> 将集合中的元素顺序打乱
static <T> void sort(List<T> list) ->将集合中的元素按照默认规则排序->ASCII
static <T> void sort(List<T> list, Comparator<? super T> c)->将集合中的元素按照指定规则排序
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//static <T> boolean addAll(Collection<? super T> c, T... elements)->批量将元素存到集合
Collections.addAll(list,"樱桃小丸子","铁臂阿童木","蜡笔小新","飞天小女警");
System.out.println(list);
//static void shuffle(List<?> list) -> 将集合中的元素顺序打乱
Collections.shuffle(list);
System.out.println(list);
//static <T> void sort(List<T> list) ->将集合中的元素按照默认规则排序->ASCII
ArrayList<String> list1 = new ArrayList<>();
list1.add("Ba");
list1.add("Ac");
list1.add("Cd");
list1.add("Db");
Collections.sort(list1);
System.out.println(list1);
}
}
1.static <T> void sort(List<T> list, Comparator<? super T> c)->将集合中的元素按照指定规则排序
2.Comparator:比较器,接口
3.Comparator接口中的方法:
int compare(T o1, T o2)
o1-o2-> 升序
o2-o1-> 降序
public class 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='" + name + ''' +
", age=" + age +
'}';
}
}
public class Test02 {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("柳岩",36));
list.add(new Person("涛哥",18));
list.add(new Person("翠儿",45));
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o2.getAge()-o1.getAge();
}
});
System.out.println(list);
}
}
比较器:Comparable接口
方法: public int compareTo(T o); 比较: this-o -> 升序 o-this-> 降序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='" + name + ''' + ", age=" + age + '}'; } @Override public int compareTo(Person o) { return o.age-this.age; } }public class Test02 { public static void main(String[] args) { ArrayList<Person> list = new ArrayList<>(); list.add(new Person("柳岩",36)); list.add(new Person("涛哥",18)); list.add(new Person("翠儿",45)); /* Collections.sort(list, new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { return o2.getAge()-o1.getAge(); } });*/ Collections.sort(list); System.out.println(list); } }
第十章.增强for
1.增强for的介绍以及基本使用
1.作用:主要是遍历集合和数组的
2.格式:
for(元素的类型 变量名:集合或者数组名){
变量名接收的就是集合或者数组中的每一个元素
}
public class Test01 {
public static void main(String[] args) {
// method01();
method02();
}
private static void method02() {
int[] arr = {1,2,3,4,5,6};
for (int i : arr) {
System.out.println(i);
}
}
public static void method01() {
ArrayList<String> list = new ArrayList<>();
list.add("樱桃小丸子");
list.add("百变小樱魔术卡");
list.add("飞天小女警");
list.add("巴拉啦小魔仙");
//普通for
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("=======================");
//迭代器
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("===========================");
//增强for->快捷键->集合名或者数组名.for
for (String s : list) {
System.out.println(s);
}
}
}
快捷键:集合名或者数组名.for
2.使用增强for的注意事项
1.注意:
如果使用增强for,遍历集合,过程中也不能随意删除添加元素,会抛出并发修改异常
2.原因:
在使用增强for遍历集合时,底层原理是迭代器
在使用增强for遍历数组时,底层原理是普通for
idea自带反编译功能:
第十一章.泛型
1.为什么要使用泛型
1.从使用的角度:统一元素的数据类型,防止类型转换异常
2.从定义的角度:使用起来很方便,可以传递任意类型,传递什么类型,我们就操作什么类型的数据,通用
2.泛型的定义
2.1含有泛型的类
1.格式:
public class 类名<E>{
}
2.什么时候确定类型:
创建对象的时候
public class ArrayList_Myself<E> {
public void add(E e){
System.out.println(e);
}
}
public class Test01 {
public static void main(String[] args) {
ArrayList_Myself<Integer> list = new ArrayList_Myself<>();
list.add(1);
}
}
2.2含有泛型的方法
1.格式:
修饰符 <E> 返回值类型 方法名(E e){}
2.什么时候确定类型
调用的时候确定类型
public class ArrayList_MySelf {
public <E> void add(E e){
System.out.println(e);
}
}
public class Test01 {
public static void main(String[] args) {
ArrayList_MySelf list = new ArrayList_MySelf();
list.add("1");
list.add(1);
}
}
2.3含有泛型的接口
1.定义:
public interface 接口名<E>{}
2.什么时候确定类型:
a.在实现类的时候就确定类型 -> Scanner
b.在实现类的时候还是不确定类型,在创建实现类对象时确定类型 -> ArrayList
public interface Iterator_Myself<E> {
public E next(E e);
}
public class Scanner_Myself implements Iterator_Myself<String>{
@Override
public String next(String s) {
return s;
}
}
public class Test01 {
public static void main(String[] args) {
Scanner_Myself scanner_myself = new Scanner_Myself();
String result = scanner_myself.next("shuru");
System.out.println("result = " + result);
}
}
public interface List_Myself <E>{
public void add(E e);
}
public class ArrayList_Myself<E> implements List_Myself<E>{
@Override
public void add(E e) {
System.out.println(e);
}
}
public class Test {
public static void main(String[] args) {
ArrayList_Myself<String> list = new ArrayList_Myself<>();
list.add("hahaha");
}
}
3.泛型的高级使用
3.1 泛型通配符 ?
1.什么时候用泛型通配符:参数位置当不知道接收什么类型时->一般用在集合方面
2.用在什么位置上:一般用在参数位置
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("郭嘉");
list1.add("诸葛亮");
list1.add("庞统");
list1.add("陆逊");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
list2.add(3);
method(list1);
method(list2);
}
public static void method(ArrayList<?> list){
for (Object o : list) {
System.out.println(o);
}
}
}
3.2 泛型的上限下限
泛型通配符的高级使用--受限泛型
1.上限:
a.格式: 类型名称<? extends 类> 对象名
b.意义: ?只能接受extends后面的本类以及子类
2.下限:
a.格式: 类型名称<? super 类> 对象名
b.意义: ?只能接受super后的本类以及父类
/*
Integer->Number->Object
String->Object
*/
public class Test02 {
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){
}
}
第十二章.斗地主案例
5.1 案例介绍
按照斗地主的规则,完成洗牌发牌的动作。 具体规则:
使用54张牌打乱顺序,三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。
5.2 案例分析
-
准备牌:
牌可以设计为一个
ArrayList<String>每个字符串为一张牌。 每张牌由花色数字两部分组成,我们可以使用花色集合与数字集合嵌套迭代完成每张牌的组装。 牌由Collections类的shuffle方法进行随机排序。 -
发牌
将每个人以及底牌设计为
ArrayList<String>,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。 -
看牌
直接打印每个集合。
5.3 代码实现
实现步骤:
准备牌组合牌:
1.定义两个集合,分别存储牌号(pokerNumber)和花色(pokerColor)
2.定义一个集合,用于存储拼接好的牌面(poker)
3.遍历pokerNumber和pokerColor,进行牌号和花色的拼接,存储到poker集合中,别忘记大小王
洗牌:
4.利用Collections中的shuffle,对poker中的元素进行打乱
发牌:
5.定义4个集合,分别表示玩家1(player1),玩家2(player2),玩家3(player3),底牌(dipai)
6.遍历poker,利用索引去%3判断
如果index%3==0,将牌存储到player1中
如果index%3==1,将牌存储到player2中
如果index%3==2,将牌存储到player3中
如果index>=51,直接放到dipai集合中
看牌:
7.遍历四个集合:player1,player2,player3,dipai
public class Poker {
public static void main(String[] args) {
//准备牌组合牌:
//1.定义两个集合,分别存储牌号(pokerNumber)和花色(pokerColor)
ArrayList<String> pokerNumber = new ArrayList<>();
for (int i = 2; i <= 10; i++) {
pokerNumber.add(i+"");
}
pokerNumber.add("J");
pokerNumber.add("Q");
pokerNumber.add("K");
pokerNumber.add("A");
ArrayList<String> pokerColor = new ArrayList<>();
pokerColor.add("♠");
pokerColor.add("♥");
pokerColor.add("♣");
pokerColor.add("♦");
//2.定义一个集合,用于存储拼接好的牌面(poker)
ArrayList<String> poker = new ArrayList<>();
//3.遍历pokerNumber和pokerColor,进行牌号和花色的拼接,存储到poker集合中,别忘记大小王
for (String color : pokerColor) {
for (String number : pokerNumber) {
String s = color+number;
poker.add(s);
}
}
poker.add("大🤡");
poker.add("小🤡");
//洗牌:
//4.利用Collections中的shuffle,对poker中的元素进行打乱
Collections.shuffle(poker);
//发牌:
//5.定义4个集合,分别表示玩家1(player1),玩家2(player2),玩家3(player3),底牌(dipai)
ArrayList<String> player1 = new ArrayList<>();
ArrayList<String> player2 = new ArrayList<>();
ArrayList<String> player3 = new ArrayList<>();
ArrayList<String> dipai = new ArrayList<>();
//6.遍历poker,利用索引去%3判断
for (int i = 0; i < poker.size(); i++) {
String pNum = poker.get(i);
//如果index>=51,直接放到dipai集合中
if (i>=51){
dipai.add(pNum);
}else{
//如果index%3==0,将牌存储到player1中
if (i%3==0){
player1.add(pNum);
}else if (i%3==1){
//如果index%3==1,将牌存储到player2中
player2.add(pNum);
}else{
//如果index%3==2,将牌存储到player3中
player3.add(pNum);
}
}
}
//看牌:
//7.遍历四个集合:player1,player2,player3,dipai
System.out.println("涛哥:"+player1);
System.out.println("翠儿:"+player2);
System.out.println("静静:"+player3);
System.out.println("底牌:"+dipai);
}
}
public class Poker_Array {
public static void main(String[] args) {
//准备牌组合牌:
//1.定义两个数组,分别存储牌号(pokerNumber)和花色(pokerColor)
String[] pokerNumber = "2-3-4-5-6-7-8-9-10-J-Q-K-A".split("-");
String[] pokerColor = "♠-♥-♣-♦".split("-");
//2.定义一个集合,用于存储拼接好的牌面(poker)
ArrayList<String> poker = new ArrayList<>();
//3.遍历pokerNumber和pokerColor,进行牌号和花色的拼接,存储到poker集合中,别忘记大小王
for (String color : pokerColor) {
for (String number : pokerNumber) {
String s = color+number;
poker.add(s);
}
}
poker.add("大🤡");
poker.add("小🤡");
//洗牌:
//4.利用Collections中的shuffle,对poker中的元素进行打乱
Collections.shuffle(poker);
//发牌:
//5.定义4个集合,分别表示玩家1(player1),玩家2(player2),玩家3(player3),底牌(dipai)
ArrayList<String> player1 = new ArrayList<>();
ArrayList<String> player2 = new ArrayList<>();
ArrayList<String> player3 = new ArrayList<>();
ArrayList<String> dipai = new ArrayList<>();
//6.遍历poker,利用索引去%3判断
for (int i = 0; i < poker.size(); i++) {
String pNum = poker.get(i);
//如果index>=51,直接放到dipai集合中
if (i>=51){
dipai.add(pNum);
}else{
//如果index%3==0,将牌存储到player1中
if (i%3==0){
player1.add(pNum);
}else if (i%3==1){
//如果index%3==1,将牌存储到player2中
player2.add(pNum);
}else{
//如果index%3==2,将牌存储到player3中
player3.add(pNum);
}
}
}
//看牌:
//7.遍历四个集合:player1,player2,player3,dipai
System.out.println("涛哥:"+player1);
System.out.println("翠儿:"+player2);
System.out.println("静静:"+player3);
System.out.println("底牌:"+dipai);
}
}
第十三章.红黑树(了解)
1.结论:加入红黑树的目的-> 查询快
第十四章.Set集合
1.Set集合介绍
1.概述:Set接口 继承自 Collection接口
Set接口中的方法,并没有对Collection接口进行扩充
底层都是依靠Map实现
2.HashSet集合的介绍和使用
1.概述:HashSet 实现 Set接口
2.特点:
元素无序
元素唯一(如果元素一样,后面的会把前面的覆盖掉)
没有索引(迭代器遍历,增强for遍历)
3.数据结构:哈希表
jdk8之前:哈希表 = 数组+链表
jdk8之后:哈希表 = 数组+链表+红黑树
加入红黑树的目的:查询快,提高效率
4.方法:
和Collection一样
public class Demo01Set {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("abc");
set.add("abc");
set.add("通话");
set.add("重地");
set.add("吕布");
set.add("貂蝉");
System.out.println(set);
//迭代器
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("======================");
//增强for
for (String s : set) {
System.out.println(s);
}
}
}
3.LinkedHashSet的介绍以及使用
1.概述:LinkedHashSet extends HashSet
2.特点:
元素有序
元素唯一(如果元素一样,后面的会把前面的覆盖掉)
没有索引(迭代器遍历,增强for遍历)
3.数据结构:哈希表+链表
4.方法:
和HashSet一样
public class Demo01Set {
public static void main(String[] args) {
LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("abc");
set.add("abc");
set.add("通话");
set.add("重地");
set.add("吕布");
set.add("貂蝉");
System.out.println(set);
//迭代器
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("======================");
//增强for
for (String s : set) {
System.out.println(s);
}
}
}
4.哈希值
1.概述:计算机计算出来的十进制数,可以理解为对象的地址值
2.获取哈希值:
调用Object类中的hashCode()方法
3.结论:
a.如果想要获取对象内容的哈希值,重写hashCode方法
b.内容一样,算出来的哈希值一定一样
c.内容不一样,算出来的哈希值也有可能一样(哈希碰撞,哈希冲突)
public class Test01 {
public static void main(String[] args) {
Person p1 = new Person("柳岩", 36);
Person p2 = new Person("柳岩", 36);
System.out.println(p1.toString());
System.out.println(p2.toString());
System.out.println(p1.hashCode());
System.out.println(Integer.toHexString(p1.hashCode()));
System.out.println(p2.hashCode());
System.out.println(Integer.toHexString(p2.hashCode()));
System.out.println("=====================");
String s = "abc";
String s1 = "abc";
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
String s2 = "通话";
String s3 = "重地";
System.out.println(s2.hashCode());//1179395
System.out.println(s3.hashCode());//1179395
}
}
5.字符串的哈希值时如何算出来的
String s = "abc";
System.out.println(s.hashCode());//96354
char[] value = {'a','b','c'}
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
第一圈:
h = 31 * h + val[i];->31*0+97 = 97
第二圈:
h = 31 * h + val[i]-> 31*97+98 = 3105
第三圈:
h = 31 * h + val[i]-> 31*3105+99 = 96354
问题:
为什么要用31去乘?
因为31是一个质数,用31,会降低哈希冲突的概率
6.HashSet的存储去重复的过程
1.先计算元素的哈希值,然后比较哈希值
2.如果哈希值不一样,直接存储
3.如果哈希值一样,再比较元素内容
4.如果哈希值一样,内容不一样,直接存
5.如果哈希值一样,内容也一样,直接去重复,后面的会把前面的覆盖掉
HashSet<String> set = newHashSet<>();
set.add("abc");
set.add("abc");
set.add("通话");
set.add("重地");
set.add("吕布");
set.add("貂蝉");
System.out.println(set);
7.HashSet存储自定义类型如何去重复
set集合存储自定义对象,想要去重复,应该重写hashCode和equals方法,去比较属性的哈希值和内容
public class 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='" + name + ''' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
/**
* 重写之后,比较的是对象中属性的哈希值
* @return
*/
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class Test02 {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
set.add(new Person("柳岩",36));
set.add(new Person("柳岩",36));
set.add(new Person("涛哥",16));
System.out.println(set);
}
}
第十五章.Map集合
1.Map的介绍
1.概述:Map接口,是双列集合的顶级接口
2.特点:
a.无序(除了LinkedHashMap)
b.无索引
c.元素都是键值对形式: key(键) = value(值)
d.key唯一,value可以重复(如果key重复了,后面的会把前面的覆盖掉)
2.HashMap的介绍以及使用
1.概述:HashMap 实现 Map接口
2.特点:
a.无序
b.元素都是key value形式
c.key唯一,value可重复
d.无索引
3.数据结构:
哈希表
4.常用方法:
V put(K key, V value) -> 存储元素
V remove(Object key) ->根据key删除对应的键值对
V get(Object key) -> 根据key获取对应的value
boolean containsKey(Object key) ->判断Map中是否包含指定的key
Collection<V> values() -> 将Map中所有的value存储到Collection集合中
Set<K> keySet() -> 将Map中所有的key获取出来存到Set集合中
Set<Map.Entry<K,V>> entrySet() -> 获取Map中所有的键值对对象,放到set集合中
5.注意:
如果key重复了,后面的会把前面的覆盖掉,去重复过程和set一毛一样
public class Test01_HashMap {
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<>();
//V put(K key, V value) -> 存储元素
hashMap.put("涛哥","翠儿");
hashMap.put("黄晓明","杨颖");
hashMap.put("文章","马伊琍");
hashMap.put("陈羽凡","白百何");
hashMap.put("王宝强","马蓉");
hashMap.put("涛哥","涛嫂");
hashMap.put(null,null);//HashMap可以存储null键 null值
//V remove(Object key) ->根据key删除对应的键值对,返回的是被删除的value
String value1 = hashMap.remove("涛哥");
System.out.println(value1);
// V get(Object key) -> 根据key获取对应的value
String value2 = hashMap.get("文章");
System.out.println(value2);
// boolean containsKey(Object key) ->判断Map中是否包含指定的key
boolean result01 = hashMap.containsKey("王宝强");
System.out.println(result01);
//Collection<V> values() -> 将Map中所有的value存储到Collection集合中
Collection<String> collection = hashMap.values();
System.out.println(collection);
System.out.println(hashMap);
}
}
3.HashMap的两种遍历方式
3.1 方式1:获取key,然后根据key获取value
Set<K> keySet() -> 将Map中所有的key获取出来存到Set集合中
public class Test02_HashMap {
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("黄晓明","杨颖");
hashMap.put("贾乃亮","李小璐");
hashMap.put("李睿","罗玉凤");
hashMap.put("征牛","乔碧萝");
Set<String> set = hashMap.keySet();
//遍历set集合将key遍历出来
for (String key : set) {
//根据key获取value
String value = hashMap.get(key);
System.out.println(key+"..."+value);
}
}
}
3.2 方式2:同时获取key和value
Set<Map.Entry<K,V>> entrySet() -> 获取Map中所有的键值对对象,放到set集合中
public class Test03_HashMap {
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("黄晓明","杨颖");
hashMap.put("贾乃亮","李小璐");
hashMap.put("李睿","罗玉凤");
hashMap.put("征牛","乔碧萝");
//先获取记录这key和value的结婚证-> Map.Entry->将Map.Entry对象放到Set集合中
Set<Map.Entry<String, String>> set = hashMap.entrySet();
//遍历set集合,将Map.Entry获取出来
for (Map.Entry<String, String> entry : set) {
//利用Map.Entry中的getKey方法获取key
String key = entry.getKey();
//利用Map.Entry中的getValue方法获取value
String value = entry.getValue();
System.out.println(key+"..."+value);
}
}
}
4.HashMap存储自定义对象
1.key存储自定义对象, value类型随意
2.要想让自定义对象作为key保持唯一,自定义对象需要重写hashCode和equals方法,比较的是属性值
public class 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='" + name + ''' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class Test04_HashMap {
public static void main(String[] args) {
HashMap<Person, String> map = new HashMap<>();
map.put(new Person("涛哥",14),"廊坊");
map.put(new Person("涛哥",14),"霸州");
map.put(new Person("翠儿",45),"北京");
map.put(new Person("柳岩",36),"湖南");
Set<Person> set = map.keySet();
for (Person person : set) {
System.out.println(person.getName()+"..."+person.getAge());
}
System.out.println("============================");
//遍历获取value
Set<Map.Entry<Person, String>> set1 = map.entrySet();
for (Map.Entry<Person, String> entry : set1) {
Person person = entry.getKey();
String value = entry.getValue();
System.out.println(person.getName()+"..."+person.getAge()+"..."+value);
}
}
}
5.Map的练习
需求:利用HashMap集合统计字符串中字符出现的次数
实现步骤:
1.使用Scanner键盘录入一个字符串
2.创建一个Map集合 key保存字符 value保存字符个数
3.遍历字符串,将每一个字符遍历出来
4.判断,map中是否包含遍历出来的字符
5.如果不包含,直接将字符 和 1存进去
6.如果包含,根据字符将value获取出来,进行加1
7.再将此字符,和变化之后的value重新存进去
public class Test05_HashMap {
public static void main(String[] args) {
//1.使用Scanner键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请你输入一个字符串:");
String data = sc.next();
//2.创建一个Map集合 key保存字符 value保存字符个数
HashMap<String, Integer> map = new HashMap<>();
//3.遍历字符串,将每一个字符遍历出来
char[] chars = data.toCharArray();
for (char aChar : chars) {
String key = aChar+"";
//4.判断,map中是否包含遍历出来的字符
if (!map.containsKey(key)){
//5.如果不包含,直接将字符 和 1存进去
map.put(key,1);
}else{
//6.如果包含,根据字符将value获取出来,进行加1
Integer value = map.get(key);
value++;
//7.再将此字符,和变化之后的value重新存进去
map.put(key,value);
}
}
System.out.println(map);
}
}
6.LinkedHashMap
1.概述:LinkedHashMap extends HashMap
2.特点:
a.有序
b.key唯一
c.无索引
d.元素为key value形式
3.数据结构:
哈希表+双链表
4.使用,和LHashMap一样
public class Test06_LinkedHashMap {
public static void main(String[] args) {
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("黄晓明","杨颖");
map.put("贾乃亮","李小璐");
map.put("李睿","罗玉凤");
map.put("征牛","乔碧萝");
System.out.println(map);
Set<String> set = map.keySet();
for (String key : set) {
String value = map.get(key);
System.out.println(key+"="+value);
}
System.out.println("===================");
Set<Map.Entry<String, String>> set1 = map.entrySet();
for (Map.Entry<String, String> entry : set1) {
System.out.println(entry.getKey()+"..."+entry.getValue());
}
}
}
7.斗地主_Map版本
public class Test07_Poker {
public static void main(String[] args) {
//1.创建HashMap集合
HashMap<Integer, String> poker = new HashMap<>();
//2.准备花色和牌号
String[] pokerNumber = "2-3-4-5-6-7-8-9-10-J-Q-K-A".split("-");
String[] pokerColor = "♠-♥-♣-♦".split("-");
//3.创建一个专门存储key的ArrayList集合
ArrayList<Integer> list = new ArrayList<>();
int index = 2;
for (String number : pokerNumber) {
for (String color : pokerColor) {
String element = color+number;
poker.put(index,element);
list.add(index);
index++;
}
}
//4.专门存大小王
poker.put(0,"大💀");
poker.put(1,"小💀");
list.add(0);
list.add(1);
//5.洗牌
Collections.shuffle(list);
//6.发牌
ArrayList<Integer> player1 = new ArrayList<>();
ArrayList<Integer> player2 = new ArrayList<>();
ArrayList<Integer> player3 = new ArrayList<>();
ArrayList<Integer> dipai = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
Integer key = list.get(i);
if (i>=51){
dipai.add(key);
}else{
if (i%3==0){
player1.add(key);
}else if(i%3==1){
player2.add(key);
}else{
player3.add(key);
}
}
}
//7.排序
Collections.sort(player1);
Collections.sort(player2);
Collections.sort(player3);
Collections.sort(dipai);
look("涛哥",player1,poker);
look("翠儿",player2,poker);
look("静静",player3,poker);
look("底牌",dipai,poker);
}
public static void look(String name,ArrayList<Integer> list,HashMap<Integer, String> map){
System.out.print(name+":");
for (Integer key : list) {
String poker = map.get(key);
System.out.print(poker+"\t");
}
System.out.println();
}
}
第十六章.TreeSet
1.概述:TreeSet是Set接口的实现类
2.特点:
a.可以对元素进行排序
b.元素唯一
c.无索引
3.数据结构:
红黑树
构造:
TreeSet() -> 对元素进行自然排序
TreeSet(Comparator<? super E> comparator) -> 对元素按照指定的规则进行排序
public class Test01_TreeSet {
public static void main(String[] args) {
//TreeSet() -> 对元素进行自然排序
TreeSet<String> treeSet = new TreeSet<>();
treeSet.add("d");
treeSet.add("c");
treeSet.add("a");
treeSet.add("b");
System.out.println(treeSet);
}
}
public class 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='" + name + ''' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class Test02_TreeSet {
public static void main(String[] args) {
// TreeSet(Comparator<? super E> comparator) -> 对元素按照指定的规则进行排序
TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge()-o2.getAge();
}
});
treeSet.add(new Person("柳岩",36));
treeSet.add(new Person("涛哥",18));
treeSet.add(new Person("翠儿",16));
System.out.println(treeSet);
}
}
第十七章.TreeMap
1.概述:TreeMap 是 Map的实现类
2.特点:
a.可以对key进行排序
b.元素都是key value形式
c.无索引
d.key唯一
3.底层数据结构:
红黑树
TreeMap() -> 可以对key进行自然排序
TreeMap(Comparator<? super K> comparator) -> 对key进行指定规则的排序
public class Test03_TreeMap {
public static void main(String[] args) {
TreeMap<String, String> treeMap = new TreeMap<>();
treeMap.put("d","低头思故乡");
treeMap.put("b","疑是地上霜");
treeMap.put("a","床前明月光");
treeMap.put("c","举头望明月");
System.out.println(treeMap);
}
}
public class 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='" + name + ''' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class Test04_TreeMap {
public static void main(String[] args) {
TreeMap<Person, String> treeMap = new TreeMap<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge()-o2.getAge();
}
});
treeMap.put(new Person("柳岩",36),"湖南");
treeMap.put(new Person("涛哥",18),"河北");
treeMap.put(new Person("翠儿",45),"北京");
System.out.println(treeMap);
}
}
第十八章.HashTable和Vector集合(了解)
1.HashTable集合
1.概述:开始于JDK1.0 ,从Java 2 平台 v1.2起,此类就被改进以实现 Map 接口
2.特点:
a.key唯一
b.无索引
c.无序
d.线程安全,效率低
3.数据结构:
哈希表
4.使用:
和HashMap一毛一样
public class Test01_HashTable {
public static void main(String[] args) {
Hashtable<String, String> hashtable = new Hashtable<>();
hashtable.put("张三","李四");
hashtable.put("王五","赵六");
hashtable.put("田七","猪八");
hashtable.put("涛哥","柳岩");
hashtable.put("涛哥","杨幂");
System.out.println(hashtable);
Set<String> set = hashtable.keySet();
for (String key : set) {
String value = hashtable.get(key);
System.out.println(key+"="+value);
}
System.out.println("=======================");
Set<Map.Entry<String, String>> set1 = hashtable.entrySet();
for (Map.Entry<String, String> entry : set1) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
}
}
2.Vector集合
1.概述:出现在jdk1.0版本,从 Java 2 平台 v1.2 开始,此类改进为可以实现 List 接口
2.特点:
a.有序
b.有索引
c.元素可重复
d.线程安全,效率低
3.数据结构:
数组
4.使用:和ArrayList一样
5.底层分析:
a.Vector一new底层就会直接产生一个长度为10的空数组
b.数组扩容:Arrays.copyOf
扩容2倍
public class Test02_Vector {
public static void main(String[] args) {
Vector<Integer> vector = new Vector<>();
vector.add(1);
vector.add(2);
System.out.println(vector);
}
}
笔试题:Hashtable和HashMap区别
1.相同点: 都是哈希表结构,都是key唯一,无索引,无序 2.不同点: HashMap:线程不安全,效率高,能存储null键,null值 Hashtable:线程安全,效率低,不能存储null键,null值
第十九章.Properties集合(属性集)
1.概述:Properties extends Hashtable
2.特点:
a.无序
b.无索引
c.key唯一
d.key value 固定都是String
e.不能存储null键 null值
f.线程安全,效率低
3.数据结构:
哈希表
4.使用:和HashMap一样,HashMap中的方法Properties集合都能使用
5.这里我不学HashMap的方法,我们要学Properties的特有方法
Object setProperty(String key, String value) -> 存储键值对
String getProperty(String key) -> 根据key获取value
Set<String> stringPropertyNames() -> 获取所有的key,存放到Set集合中
void load(InputStream inStream) -> 将流中的数据信息加载到Properties集合中 (IO流部分讲)
public class Test01 {
public static void main(String[] args) {
Properties properties = new Properties();
//Object setProperty(String key, String value) -> 存储键值对
properties.setProperty("username","root");
properties.setProperty("password","1234");
System.out.println(properties);
//String getProperty(String key) -> 根据key获取value
System.out.println(properties.getProperty("username"));
//Set<String> stringPropertyNames() -> 获取所有的key,存放到Set集合中,类似于keySet方法
Set<String> set = properties.stringPropertyNames();
for (String key : set) {
System.out.println(properties.getProperty(key));
}
}
}
Properties的使用场景:配合IO流解析配置文件中的数据
我们可以将一些硬数据,放到配置文件中,然后动态解析配置文件,读取配置文件中的数据,也可以更好的降低耦合度1.创建一个后缀名为.properties的文件->properties文件 2.在配置文件中写key=value username=root password=1234public class Test02 { public static void main(String[] args) throws Exception { //创建字节输入流,读取配置文件 FileInputStream fis = new FileInputStream("day18\pro.properties"); //创建properties集合 Properties properties = new Properties(); // void load(InputStream inStream) -> 将流中的数据信息加载到Properties集合中 (IO流部分讲) properties.load(fis); System.out.println(properties); } }
第二十章.集合嵌套
1.List嵌套List
需求:创建2个List集合,每个集合中分别存储一些字符串,将2个集合存储到第3个List集合中
public class Test01_List_in_List {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("杨过");
list1.add("尹志平");
list1.add("小龙女");
ArrayList<String> list2 = new ArrayList<>();
list2.add("周芷若");
list2.add("张无忌");
list2.add("赵敏");
//创建第三个集合
ArrayList<ArrayList<String>> list = new ArrayList<>();
list.add(list1);
list.add(list2);
//遍历,先遍历大list,将list1和list2遍历出来
for (ArrayList<String> arrayList : list) {
//遍历list1和list2
for (String s : arrayList) {
System.out.println(s);
}
}
}
}
2.List嵌套Map
1班级有第三名同学,学号和姓名分别为:1=张三,2=李四,3=王五,2班有三名同学,学号和姓名分别为:1=黄晓明,2=杨颖,3=刘德华,请将同学的信息以键值对的形式存储到2个Map集合中,在将2个Map集合存储到List集合中。
public class Test02_List_in_Map {
public static void main(String[] args) {
//创建两个map集合
HashMap<Integer, String> map1 = new HashMap<>();
map1.put(1,"张三");
map1.put(2,"李四");
HashMap<Integer, String> map2 = new HashMap<>();
map2.put(1,"黄晓明");
map2.put(2,"刘德华");
//创建List集合,存储两个map
ArrayList<HashMap<Integer, String>> list = new ArrayList<>();
list.add(map1);
list.add(map2);
//遍历List集合,将小Map获取出来
for (HashMap<Integer, String> map : list) {
//遍历小map,将key value获取出来
Set<Map.Entry<Integer, String>> set = map.entrySet();
for (Map.Entry<Integer, String> entry : set) {
System.out.println(entry.getKey()+"="+entry.getValue());
}
}
}
}
3.Map嵌套Map
- JavaSE 集合 存储的是 学号 键,值学生姓名
- 1 张三
- 2 李四
- JavaEE 集合 存储的是 学号 键,值学生姓名
- 1 王五
- 2 赵六
public class Test03_Map_in_Map {
public static void main(String[] args) {
//创建小map
HashMap<Integer, String> map1 = new HashMap<>();
map1.put(1,"张三");
map1.put(2,"李四");
HashMap<Integer, String> map2 = new HashMap<>();
map2.put(1,"王五");
map2.put(2,"赵六");
HashMap<String, HashMap<Integer, String>> map = new HashMap<>();
map.put("javase",map1);
map.put("javaee",map2);
//遍历大map
Set<String> set = map.keySet();
for (String key : set) {
HashMap<Integer, String> hashMap = map.get(key);
//遍历小map
Set<Map.Entry<Integer, String>> entries = hashMap.entrySet();
for (Map.Entry<Integer, String> entry : entries) {
System.out.println(entry.getKey()+"="+entry.getValue());
}
}
}
}
第二十一章.正则表达式
1.正则表达式的概念及演示
1.概述:是字符串表示的一个规则
2.作用:用于校验
3.需求:QQ号
a.开头不能是0
b.必须都是数字
c.QQ号必须是5-15位
正则表达式:[1-9][0-9]{4,14}
4.String中有一个方法:
boolean matches(String regex)->判断某个字符串是否符合regex正则表达式规则
public class Demo01_Regex {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请你输入一个QQ号:");
String QQ = sc.next();
//boolean result = method(QQ);
//System.out.println("result = " + result);
boolean result01 = method01(QQ);
System.out.println("result01 = " + result01);
}
private static boolean method01(String qq) {
boolean result = qq.matches("[1-9][0-9]{4,14}");
return result;
}
/*
a.开头不能是0
b.必须都是数字
c.QQ号必须是5-15位
*/
private static boolean method(String qq) {
//a.开头不能是0
if (qq.startsWith("0")){
return false;
}
// b.必须都是数字
char[] chars = qq.toCharArray();
for (char aChar : chars) {
if (aChar<'0' || aChar>'9'){
return false;
}
}
//QQ号必须是5-15位
if (qq.length()<5 || qq.length()>15){
return false;
}
return true;
}
}
2.正则表达式-字符类
java.util.regex.Pattern:正则表达式的编译表示形式。
正则表达式-字符类:[]表示一个区间,范围可以自己定义
语法示例:
1. [abc]:代表a或者b,或者c字符中的一个。
2. [^abc]:代表除a,b,c以外的任何字符。
3. [a-z]:代表a-z的所有小写字符中的一个。
4. [A-Z]:代表A-Z的所有大写字符中的一个。
5. [0-9]:代表0-9之间的某一个数字字符。
6. [a-zA-Z0-9]:代表a-z或者A-Z或者0-9之间的任意一个字符。
7. [a-dm-p]:a 到 d 或 m 到 p之间的任意一个字符
public class Demo02_Regex {
public static void main(String[] args) {
//1.验证字符串是否以h开头,d结尾,中间是aeiou的某一个字符
boolean result01 = "hyd".matches("[h][aeiou][d]");
System.out.println(result01);
//2.验证字符串是否以h开头,d结尾,中间不是aeiou的某一个字符
boolean result02 = "hyd".matches("[h][^aeiou][d]");
System.out.println(result02);
//3.验证字符串是否是a-z的任意一个小写字母开头,后面是ad
boolean result03 = "aad".matches("[a-z][a][d]");
System.out.println("result03 = " + result03);
}
}
3.正则表达式-逻辑运算符
正则表达式-逻辑运算符
语法示例:
1. &&:并且
2. | :或者
public class Demo03_Regex {
public static void main(String[] args) {
//1.要求字符串是小写[a-z],并且字符[^aeiou]开头,后面跟ad
boolean result01 = "aad".matches("[[a-z]&&[^aeiou]][a][d]");
System.out.println("result01 = " + result01);
//2.要求字符串是aeiou中的某一个字母开头,后跟ad
boolean result02 = "add".matches("[a|e|i|o|u][a][d]");
System.out.println("result02 = " + result02);
}
}
4.正则表达式-预定义字符
正则表达式-预定义字符
语法示例:
1. "." : 匹配任何字符。(重点)
2. "\d":任何数字[0-9]的简写;(重点)
3. "\D":任何非数字[^0-9]的简写;
4. "\s": 空白字符:[ \t\n\x0B\f\r] 的简写
5. "\S": 非空白字符:[^\s] 的简写
6. "\w":单词字符:[a-zA-Z_0-9]的简写(重点)
7. "\W":非单词字符:[^\w]
public class Demo04_Regex {
public static void main(String[] args) {
//1.验证字符串是否是三位数字
boolean result01 = "111".matches("\d\d\d");
System.out.println("result01 = " + result01);
//2.验证手机号:1开头 第二位 3 5 8 剩下的9位都是0-9的数字
boolean result02 = "13838381438".matches("[1][358]\d\d\d\d\d\d\d\d\d");
System.out.println("result02 = " + result02);
//3.验证字符串是否以h开头,d结尾,中间是任意一个字符
boolean result03 = "had".matches("[h].[d]");
System.out.println("result03 = " + result03);
}
}
5. 正则表达式-数量词
正则表达式-数量词
语法示例:x代表字符
1. X? : x出现的数量为 0次或1次
2. X* : x出现的数量为 0次到多次 任意次
3. X+ : x出现的数量为 1次或多次 X>=1次
4. X{n} : x出现的数量为 恰好n次 X=n次
5. X{n,} : x出现的数量为 至少n次 X>=n次 x{3,}
6. X{n,m}: x出现的数量为 n到m次(n和m都是包含的) n=<X<=m
public class Demo05_Regex {
public static void main(String[] args) {
//1.验证字符串是否是三位数字
boolean result01 = "1111".matches("\d{3}");
System.out.println("result01 = " + result01);
//2.验证手机号:1开头 第二位 3 5 8 剩下的9位都是0-9的数字
boolean result02 = "13838381438".matches("[1][358]\d{9}");
System.out.println("result02 = " + result02);
//3.qq号:不能是0开头 都是数字 5-15
boolean result03 = "11111111".matches("[1-9][0-9]{4,14}");
System.out.println("result03 = " + result03);
}
}
6.正则表达式-分组括号( )
正则表达式-分组括号( )
public class Demo06_Regex {
public static void main(String[] args) {
//校验字符串abc可以出现任意次
boolean result01 = "abcabcabcabc".matches("(abc)*");
System.out.println("result01 = " + result01);
}
}
7.String类中和正则表达式相关的方法
String类中和正则表达式相关的方法
boolean matches(String regex) 判断字符串是否匹配给定的正则表达式。
String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串。
String replaceAll(String regex, String replacement)把满足正则表达式的字符串,替换为新的字符
public class Demo07_Regex {
public static void main(String[] args) {
//String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串。
String[] s = "abc haha 呵呵呵".split(" +");
System.out.println(Arrays.toString(s));
//String replaceAll(String regex, String replacement)把满足正则表达式的字符串,替换为新的字符
String s1= "abc haha 诶嘿IEhi 哈哈哈哈哈";
String s2 = s1.replaceAll(" +", "z");
System.out.println(s2);
}
}
8.正则表达式生成网址:
https://www.sojson.com/regex/generate