01. 集合的介绍以及和数组的区别
- 集合:集合是java中提供的一种容器,可以用来存储多个数据。
- 集合和数组的区别 数组的长度是固定的。集合的长度是可变的。 数组可以存储任意类型数据。集合存储的都是引用数据类型。
02. 集合的继承体系
参考 Java基础学习10:【Collection、泛型】中的集合的继承体系图:文章源自JAVA秀-https://www.javaxiu.com/730.html
文章源自JAVA秀-https://www.javaxiu.com/730.html
03. Collection中的常见方法
/*
Collection是所有单列集合的根接口
常见的方法:
(常用)public boolean add(E e) : 把给定的对象添加到当前集合中 。
public void clear() :清空集合中所有的元素。
public boolean remove(E e) : 把给定的对象在当前集合中删除。
public boolean contains(Object obj) : 判断当前集合中是否包含给定的对象。
public boolean isEmpty() : 判断当前集合是否为空。
(常用)public int size() : 返回集合中元素的个数。
public Object[] toArray() : 把集合中的元素,存储到数组中
*/
public class Demo01CollectionMethod {
public static void main(String[] args) {
//创建集合
Collection<String> c = new ArrayList<>();
//public boolean add(E e) : 把给定的对象添加到当前集合中
c.add("张三");
c.add("李四");
c.add("王叔叔");
System.out.println("c:" + c); //[张三, 李四, 王叔叔]
//public void clear() :清除集合中的元素
//c.clear();
//System.out.println("清除后的c:" + c);
//public boolean remove(E e) :直接删除指定的元素。 如果删除成功返回true。
//boolean flag = c.remove("李五"); //直接删除李四这个元素
//System.out.println("c:" + c);
//System.out.println("flag:" + flag);
//public boolean contains(Object obj) : 判断集合中是否包含指定的元素,如果包含返回true
//System.out.println(c.contains("李四")); //判断集合c中是否包含李四
//public boolean isEmpty():判断集合是否为空。
//c.clear();
//System.out.println(c.isEmpty());
//public int size() : 返回集合的大小,集合中有几个元素,大小就是几
//System.out.println(c.size());//3
//public Object[] toArray() :将集合转成一个数组
Object[] objs = c.toArray();
//将数组中的内容输出
System.out.println(Arrays.toString(objs));
}
}
04. 迭代器的遍历流程
我们之前都是使用for循环结合索引的方式遍历集合,但是这种方式并不适用于所有的集合,因为有些集合是没有索引的。 有一种通用的遍历方式,叫做迭代器遍历,可以适用于所有的集合。 什么是迭代器? 迭代器其实就是遍历集合的一个工具,内部有一个光标, 这个光标最开始指向集合的最开头的位置 如何获取集合的迭代器? 我们可以使用Collection中的方法iterator去获取一个迭代器对象。 Iterator<E> iterator(): 获取一个迭代器并返回。 Iterator表示迭代器,如果要使用迭代器遍历集合,那么还需要使用迭代器里面的两个方法 boolean hasNext(): 判断是否还有没有元素可以获取。如果还有元素可以获取,返回true。 E next(): 获取当前位置的元素,然后把光标向后移动。 迭代器的遍历流程: 1. 先调用集合的iterator方法,获取迭代器对象。 2. 调用迭代器的hashNext方法,判断当前位置是否有元素可以获取。 3. 如果有元素可以获取,那么就调用迭代器的next方法获取元素,并把光标向后移动。
05. 迭代器的代码实现
public class Demo01Iterator {
public static void main(String[] args) {
//定义集合
Collection<String> c = new ArrayList<>();
//添加元素
c.add("诸葛亮");
c.add("周瑜");
c.add("王朗");
//开始使用迭代器遍历
//先调用集合的iterator方法,获取迭代器对象。
Iterator<String> iterator = c.iterator();
//使用循环改进
while(iterator.hasNext()) {//条件判断集合中是否有元素可以获取,因为只有集合中有元素可以获取,那么我们才获取元素。
//如果条件成立,表示有元素可以获取,那么我们就在循环体中获取元素
System.out.println(iterator.next());
}
/*
//调用迭代器的hashNext方法,判断当前位置是否有元素可以获取。
System.out.println(iterator.hasNext()); //true
//如果有元素可以获取,那么就调用迭代器的next方法获取元素,并把光标向后移动。
System.out.println(iterator.next()); //诸葛亮
System.out.println(iterator.hasNext());//true
System.out.println(iterator.next());//周瑜
System.out.println(iterator.hasNext()); //true
System.out.println(iterator.next());//王朗
System.out.println(iterator.hasNext());//false
System.out.println(iterator.next());//NoSuchElementException
*/
}
}
06. 并发修改异常
/*
并发修改异常(ConcurrentModificationException)
当我们使用迭代器遍历集合的时候, 同时使用集合的方法向集合中添加元素或者删除元素,将来就会引发并发修改异常。
*/
public class Demo02Iterator {
public static void main(String[] args) {
//创建集合,并添加元素
Collection<String> c = new ArrayList<>();
c.add("hello");
c.add("java");
c.add("world");
//使用迭代器遍历集合
Iterator<String> iterator = c.iterator();
//使用while循环遍历
while(iterator.hasNext()) {
System.out.println(iterator.next());
//c.add("你好");
}
}
}
07. 迭代器的源码分析
参考 Java基础学习10:【Collection、泛型】中的源码分析图:文章源自JAVA秀-https://www.javaxiu.com/730.html
文章源自JAVA秀-https://www.javaxiu.com/730.html
08. 增强for遍历数组
/*
在JDK5的时候,多了一个新特性,叫做增强for循环, 可以遍历数组和集合。
格式:
for(数据类型 变量名 : 容器) {
//循环体
}
格式解析:
数据类型: 要遍历的容器中保存的是什么类型的数据,这个数据类型就写什么。
变量名: 该变量表示容器中的每一个元素。
容器: 可以是数组,也可以是集合。
增强for其实是一个语法糖, 语法糖指的是本质没有变,但是语法更加的简写。
增强for遍历数组本质还是普通for循环。
*/
public class Demo01Foreach {
public static void main(String[] args) {
//定义一个int数组
int[] intArr = {11, 22, 33, 44, 55};
//使用增强for循环进行遍历。
for(int num : intArr) {
//num表示数组中的每一个元素
System.out.println(num);
}
System.out.println("========================");
//定义double数组
double[] doubleArr = {10.1, 20.2, 30.3, 40.4, 50.5};
//使用增强for循环进行遍历
for(double num : doubleArr) {
System.out.println(num);
}
System.out.println("========================");
//定义一个数组
int[] arr = {10, 20, 30, 40, 50};
//使用增强for遍历数组,把里面的每一个元素都改为原来的2倍
for(int num : arr) {
num *= 2;
}
//输出数组中的每一个元素
System.out.println(Arrays.toString(arr));
}
}
09. 增强for遍历集合
/*
增强for遍历集合
格式:
for(数据类型 变量名 : 集合) {
//循环体
}
增强for遍历集合本质还是使用的迭代器进行的遍历。
增强for的好处缺点:
优点: 省略了索引的操作, 语法更加简洁。
缺点: 不能操作索引, 如果在遍历的过程中需要操作索引,那么还需要使用普通for循环
*/
public class Demo02Foreach {
public static void main(String[] args) {
//定义集合,用来保存字符串
Collection<String> c = new ArrayList<>();
//添加元素
c.add("hello");
c.add("world");
c.add("java");
//使用增强for遍历集合
for(String s : c) {
//s表示集合中的每一个元素
System.out.println(s);
}
System.out.println("=======================");
//定义集合,用来保存学生,然后遍历。
Collection<Student> c2 = new ArrayList<>();
c2.add(new Student("王宝强", 20));
c2.add(new Student("贾乃亮", 25));
c2.add(new Student("陈羽凡", 30));
//使用增强for遍历
for(Student stu : c2) {
System.out.println(stu);
}
}
}
/*
泛型就是一种未知的,不确定的数据类型。
比如:ArrayList<E>,这个E就是泛型, 当我们使用这个类(创建对象)的时候,那么这个E表示的类型才能确定。
泛型可以省略,泛型如果省略,相当于泛型是Object
泛型的好处:
1. 泛型可以省略向下转型的代码。
2. 可以将问题从运行时期提前到编译时期。
*/
public class Demo01Generic {
public static void main(String[] args) {
//定义集合,不指定泛型
ArrayList list = new ArrayList();
//添加数据
//list.add(100); 运行时期报错
list.add("hello");
list.add("world");
list.add("java");
//遍历集合,输出集合中每一个字符串的长度
for (Object obj : list) {
//obj表示的就是集合中的每一个元素。
//向下转型
String str = (String) obj;
//输出每一个字符串的长度
System.out.println(str.length());
}
System.out.println("=======================");
//定义集合,指定泛型为String
ArrayList<String> list2 = new ArrayList<>();
//添加数据
//list2.add(100); 编译时期报错
list2.add("hello");
list2.add("world");
list2.add("java");
//遍历集合,输出每一个字符串的长度
for(String str : list2) {
System.out.println(str.length());
}
}
}
11. 泛型擦除
/*
泛型擦除。
Java中的泛型都是伪泛型,泛型只在源代码阶段有效,一旦编译,泛型就会消失。
*/
public class Demo02Generic {
public static void main(String[] args) {
//定义集合
ArrayList<String> list = new ArrayList<>();
//添加元素
list.add("你好");
list.add("我好");
list.add("大家好");
//使用增强for遍历集合
for(String str : list) {
System.out.println(str);
}
}
}
12. 泛型类的定义
/*
泛型是一种未知的,不确定的数据类型。
如果在定义类的时候类名后面加上<T>, 此时就表示定义了一个泛型类, T可以使用任何字母代替.
并且这个T表示了在类中定义了一个不确定的数据类型T, 这个不确定的,未知的数据类型,需要我们使用这个类的时候才能确定。
*/
public class Factory<T> {
/*
定义方法,修理任何东西
*/
public T method(T t) {
//修理...
return t;
}
}
测试类:文章源自JAVA秀-https://www.javaxiu.com/730.html
/*
演示泛型类
*/
public class Demo03Generic {
public static void main(String[] args) {
//创建Factory对象
Factory<Phone> f = new Factory<>();
//调用method方法
Phone p = f.method(new Phone());
//调用call方法
p.call();
}
}
13. 泛型方法的定义
/*
如果想要缩小泛型的使用范围,延后泛型的确认时间,可以使用泛型方法。
在泛型方法中定义的泛型, 需要等到调用方法的时候才能确定。
泛型方法的定义格式:
修饰符 <泛型> 返回值类型 方法名(参数列表) {
方法体;
}
*/
public class Factory<T> {
/*
定义方法,接收什么类型的参数,就得到什么类型的结果。
*/
public <E> E getSame(E e) {
return e;
}
}
测试类:文章源自JAVA秀-https://www.javaxiu.com/730.html
/*
演示泛型方法
*/
public class Demo04Generic {
public static void main(String[] args) {
//创建Factory对象
Factory<Phone> f = new Factory<>();
//调用getSame方法
Phone phone = f.getSame(new Phone());
Pad pad = f.getSame(new Pad());
}
}
14. 泛型接口的定义
/*
泛型接口。
如果在接口名后面加上<T>, 那么这个接口就变成了泛型接口。
在泛型接口中定义的泛型类型,可以在整个接口中使用。
泛型接口的使用:
1. 在实现类实现接口的时候,直接明确接口中的泛型类型是什么。
2. 实现类在实现接口的时候,不指定泛型,等到使用实现类的时候再指定。
*/
public interface MyInterface<T> { //定义了一个未知的,不确定的数据类型T。
//定义方法
T method(T t);
}
/*
实现类在实现接口的时候在接口名后面加上<>,明确接口中的泛型类型。
*/
public class MyClassA implements MyInterface<Phone>{
public Phone method(Phone phone) {
return null;
}
}
/*
实现类在实现接口的时候不指定泛型。
只要定义类或者接口的时候,在当前类或者接口的名字后面写的<T>,才表示在定义泛型T
*/
public class MyClassB<T> implements MyInterface<T>{
public T method(T t) {
return null;
}
}
/*
泛型接口的测试类
*/
public class Demo05Generic {
public static void main(String[] args) {
//创建MyClassA对象
MyClassA ma = new MyClassA();
Phone p = ma.method(new Phone());
//创建MyClassB对象
MyClassB<Pad> mb = new MyClassB<>();
Pad pad = mb.method(new Pad());
}
}
15. 泛型通配符的使用
/*
泛型之间没有继承关系
ArrayList<Object> 不是ArrayList<String>的父类
如果想要让泛型匹配任何数据类型,那么可以使用泛型通配符。
? 表示泛型通配符,可以接收任何类型的泛型。
泛型通配符只能被动匹配, 不能主动使用。
*/
public class Demo01Generic {
public static void main(String[] args) {
//定义一个集合,里面保存字符串
ArrayList<String> list = new ArrayList<>();
//添加元素
list.add("嫐"); //高富帅
list.add("嬲"); //白费没
list.add("挊"); //屌丝
//调用printArrayList方法,传递保存字符串的集合
printArrayList(list);
//定义集合,保存Date对象
ArrayList<Date> dateList = new ArrayList<>();
printArrayList(dateList);
//定义集合
//ArrayList<?> list2 = new ArrayList<>();
//list2.add();
}
/*
要求,定义一个方法,可以遍历存放任何数据的集合。
*/
public static void printArrayList(ArrayList<?> list) {
//遍历list集合
for(Object obj : list) {
System.out.println(obj);
}
}
}
16. 泛型限定
/*
泛型限定: 泛型限定可以对泛型通配符的取值范围进行限制。
<? extends A>: 泛型类型可以是A类,也可以是A类的子类。 上限。
<? super A>: 泛型类型可以是A类,也可以是A类的父类。 下限。
*/
public class Demo02Generic {
public static void main(String[] args) {
//定义集合,保存Student
ArrayList<Student> stuList = new ArrayList<>();
//添加元素
stuList.add(new Student("小明", 18));
stuList.add(new Student("小红", 28));
//调用printArrayList进行遍历
printArrayList(stuList); //参数集合的泛型要么是Person要么是Person的子类。
//定义集合,保存Person
ArrayList<Person> personList = new ArrayList<>();
printArrayList(personList);
//定义集合, 保存Object
ArrayList<Object> objList = new ArrayList<>();
//printArrayList(objList); 参数集合的泛型要么是Person,要么是Person的子类。不能是其父类
//method(stuList);//参数集合的泛型要么是Person,要么是Person的父类。不能是其子类。
method(personList);
method(objList);
}
/*
定义方法,演示泛型下限
*/
//表示参数集合的泛型要么是Person,要么是Person的父类。
public static void method(ArrayList<? super Person> list) {
}
/*
定义方法,遍历保存Person(也包括其子类比如Student,Teacher)的集合
*/
//泛型要么是Person,要么是Person的子类
public static void printArrayList(ArrayList<? extends Person> list) {
//遍历参数list集合
for(Person p : list) {
System.out.println(p);
}
}
}
17. 斗地主案例
/*
斗地主案例的分析
1. 准备牌。
a. 定义一个集合,用来保存每张扑克牌。
b. 向集合中添加54张牌
2. 洗牌
洗牌就是打乱集合中元素的顺序。
我们可以使用Collections工具类中的shuffle方法完成。
static void shuffle(List<?> list): 打乱集合中元素的顺序。
3. 发牌
a. 定义三个集合,用来保存三个玩家手里的牌。
b. 定义一个集合,用来保存底牌。
c. 根据牌在集合中的索引进行发牌。
把索引为0,3,6...的牌发给第一个玩家(索引对3取余结果是0)
把索引为1,4,7...的牌发给第二个玩家(索引对3取余结果是1)
把索引为2,5,8...的牌发给第三个玩家(索引对3取余结果是2)
4. 看牌
遍历每个玩家手中的牌。
*/
public class Demo01Game {
public static void main(String[] args) {
//1. 准备牌。
//定义一个集合,用来保存每张扑克牌。
ArrayList<String> poker = new ArrayList<>();
//向集合中添加54张牌
//定义数组,保存花色
String[] colors = {"♠", "♥", "♣", "♦"};
//定义数组,保存点数
String[] nums = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
//对花色和点数进行。 遍历保存花色和点数的数组(嵌套循环)
for (String num : nums) {
for (String color : colors) {
//将花色和点数进行组合,并添加到集合中
poker.add(color + num);
}
}
//添加大小王
poker.add("小王");
poker.add("大王");
//2. 洗牌
//使用Collections的shuffle方法完成
Collections.shuffle(poker);
//3. 发牌
//定义三个集合,用来保存三个玩家手里的牌。
ArrayList<String> playerOne = new ArrayList<>();
ArrayList<String> playerTwo = new ArrayList<>();
ArrayList<String> playerThree = new ArrayList<>();
//定义一个集合,用来保存底牌。
ArrayList<String> diPai = new ArrayList<>();
//遍历集合,拿到里面的每一张扑克牌,然后根据索引进行发牌。 因为操作索引,所以要使用普通for
for(int i = 0; i < poker.size(); i++) {
//拿到当前遍历到的扑克牌。变量i表示该扑克牌的索引。
String card = poker.get(i);
//在给玩家发牌之前进行判断,如果拿到的是最后三张牌,就放入到底牌集合
if (i >= 51) { //如果牌的索引大于等于51,那么表示是最后三张牌
//添加到底牌集合
diPai.add(card);
continue;//结束本次循环,直接开始下次循环。
}
//根据索引发牌
if(i % 3 == 0) {//把索引为0,3,6...的牌发给第一个玩家(索引对3取余结果是0)
playerOne.add(card);
} else if(i % 3 == 1) { //把索引为1,4,7...的牌发给第二个玩家(索引对3取余结果是1)
playerTwo.add(card);
} else {//否则索引对3取余结果肯定是2,那么就发给第三个玩家
playerThree.add(card);
}
}
//4. 看牌
lookCard("发哥", playerOne);
lookCard("星爷", playerTwo);
lookCard("华仔", playerThree);
lookCard("底牌", diPai);
}
/*
定义方法,用来看牌
参数: 玩家姓名,玩家手中的牌
*/
public static void lookCard(String name, ArrayList<String> list) {
//打印玩家姓名
System.out.print(name + ": ");
//遍历保存玩家扑克牌的集合
for(String card : list) {
System.out.print(card + " ");
}
//输出空换行
System.out.println();
}
}
文章源自JAVA秀-https://www.javaxiu.com/730.html继续阅读
速蛙云 - 极致体验,强烈推荐!!!购买套餐就免费送各大视频网站会员!快速稳定、独家福利社、流媒体稳定解锁!速度快,全球上网、视频、游戏加速、独立IP均支持!基础套餐性价比很高!这里不多说,我一直正在使用,推荐购买:https://www.javaxiu.com/59919.html

资源分享QQ群
本站是JAVA秀团队的技术分享社区, 会经常分享资源和教程; 分享的时代, 请别再沉默!
评论