本文章参考B站 Java入门基础视频教程,java零基础自学首选黑马程序员Java入门教程(含Java项目和Java真题),仅供个人学习使用,部分内容为本人自己见解,与黑马程序员无关。
什么是API
Object类的作用
Object类的常用方法
方法名
说明
public String toString()
默认是返回当前对象在堆内存中的地址信息:类的全限名@内存地址
public boolean equals(Object o)
默认是比较当前对象与另一个对象的地址是否相同,相同返回true,不同返回false
代码展示
import java.util.Objects;
public class Student { //extends Object{
private String name;
private char sex;
private int age;
public Student() {
}
public Student(String name, char sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
/**
目标:掌握Object类中toString方法的使用。
*/
public class Test1 {
public static void main(String[] args) {
Student s = new Student("周雄", '男', 19);
// String rs = s.toString();
// System.out.println(rs);
// System.out.println(s.toString());
// 直接输出对象变量,默认可以省略toString调用不写的
System.out.println(s);
}
}
输出结果
com.itheima.d9_api_object.Student@1b6d3586
问题引出
toString() 存在的意义
toString 方法本身是无意义的
父类 toString 方法存在的意义就是为了被子类重写,以便返回对象的内容信息,而不是地址信息!!
代码改进
Student 类重写 toString 方法
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", sex=" + sex +
", age=" + age +
'}';
}
输出结果
Student{name='周雄', sex=男, age=19}
代码展示
/**
目标:掌握Object类中equals方法的使用。
*/
public class Test2 {
public static void main(String[] args) {
Student s1 = new Student("周雄", '男', 19);
Student s2 = new Student("周雄", '男', 19);
// equals默认是比较2个对象的地址是否相同,子类重写后会调用子类重写的来比较内容是否相同。
System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
System.out.println(Objects.equals(s1, s2));
}
}
输出结果
false
false
false
问题思考
equals 存在的意义
父类 equals 方法存在的意义就是为了被子类重写,以便子类自己来定制比较规则。
代码改进
Student 类中重写 equals 方法
/**
定制相等规则。
两个对象的内容一样就认为是相等的
s1.equals(s2)
比较者:s1 == this
被比较者: s2 ==> o
*/
@Override
public boolean equals(Object o) {
// 1、判断是否是同一个对象比较,如果是返回true。
if (this == o) return true;
// 2、如果o是null返回false 如果o不是学生类型返回false ...Student != ..Pig
if (o == null || this.getClass() != o.getClass()) return false;
// 3、说明o一定是学生类型而且不为null
Student student = (Student) o;
return sex == student.sex && age == student.age && Objects.equals(name, student.name);
}
输出结果
true
false
true
概述
常见方法
方法名
说明
public static boolean equals(Object a, Object b)
比较两个对象的,底层会先进行非空判断,从而可以避免空指针异常。再进行equals比较
public static boolean isNull(Object obj)
判断变量是否为null ,为null返回true ,反之
Object.equals 方法缺陷
代码演示
import java.util.Objects;
/**
目标:掌握objects类的常用方法:equals
*/
public class Test {
public static void main(String[] args) {
String s1 = null;
String s2 = new String("itheima");
// System.out.println(s1.equals(s2)); // 留下了隐患,可能出现空指针异常。
System.out.println(Objects.equals(s1, s2)); // 更安全,结果也是对的!
/**
Objects:
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
*/
System.out.println(Objects.isNull(s1)); // true
System.out.println(s1 == null); // true
System.out.println(Objects.isNull(s2)); // false
System.out.println(s2 == null); // false
}
}
输出结果
false
true
true
false
false
对象进行内容比较的时候建议使用什么?为什么?
源码分析
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
可以发现 equals 方法已经做了非空判断。
StringBuilder 概述
StringBuilder 构造器
名称
说明
public StringBuilder()
创建一个空白的可变的字符串对象,不包含任何内容
public StringBuilder(String str)
创建一个指定字符串内容的可变字符串对象
StringBuilder常用方法
方法名称
说明
public StringBuilder append(任意类型)
添加数据并返回StringBuilder对象本身
public StringBuilder reverse()
将对象的内容反转
public int length()
返回对象内容长度
public String toString()
通过toString()就可以实现把StringBuilder转换为String
代码展示
/**
目标:学会使用StringBuilder操作字符串,最终还需要知道它性能好的原因
*/
public class StringBuilderDemo1 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder(); // ""
sb.append("a");
sb.append("b");
sb.append("c");
sb.append(1);
sb.append(false);
sb.append(3.3);
sb.append("abc");
System.out.println(sb);
StringBuilder sb1 = new StringBuilder();
// 支持链式编程
sb1.append("a").append("b").append("c").append("我爱你中国");
System.out.println(sb1);
// 反转
sb1.reverse().append("110");
System.out.println(sb1);
System.out.println(sb1.length());
// 注意:StringBuilder只是拼接字符串的手段:效率好。
// 最终的目的还是要恢复成String类型。
StringBuilder sb2 = new StringBuilder();
sb2.append("123").append("456");
// 恢复成String类型
String rs = sb2.toString();
check(rs);
}
public static void check(String data){
System.out.println(data);
}
}
输出结果
abc1false3.3abc
abc我爱你中国
国中你爱我cba110
11
123456
为什么拼接、反转字符串建议使用 StringBuilder
原理展示


案例:打印整型数组内容
需求:
分析:
代码展示
public class StringBuilderTest2 {
public static void main(String[] args) {
int[] arr1 = null;
System.out.println(toString(arr1));
int[] arr2 = {10, 88, 99};
System.out.println(toString(arr2));
int[] arr3 = {};
System.out.println(toString(arr3));
}
/**
1、定义方法接收任意整型数组,返回数组内容格式
*/
public static String toString(int[] arr){
if(arr != null){
// 2、开始拼接内容。
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i] ).append(i == arr.length - 1 ? "" : ", ");
}
sb.append("]");
return sb.toString();
}else {
return null;
}
}
}
输出结果
null
[10, 88, 99]
[]
Math类
Math 类的常用方法
方法名
说明
public static int abs(int a)
获取参数绝对值
public static double ceil(double a)
向上取整
public static double floor(double a)
向下取整
public static int round(float a)
四舍五入
public static int max(int a,int b)
获取两个int值中的较大值
public static double pow(double a,double b)
返回a的b次幂的值
public static double random()
返回值为double的随机值,范围[0.0,1.0)
代码展示
/**
目标:Math类的使用。
Math用于做数学运算。
Math类中的方法全部是静态方法,直接用类名调用即可。
方法:
方法名 说明
public static int abs(int a) 获取参数a的绝对值:
public static double ceil(double a) 向上取整
public static double floor(double a) 向下取整
public static double pow(double a, double b) 获取a的b次幂
public static long round(double a) 四舍五入取整
小结:
记住。
*/
public class MathDemo {
public static void main(String[] args) {
// 1.取绝对值:返回正数
System.out.println(Math.abs(10)); // 10
System.out.println(Math.abs(-10.3)); // 10.3
// 2.向上取整: 5
System.out.println(Math.ceil(4.00000001)); // 5.0
System.out.println(Math.ceil(4.0)); // 4.0
// 3.向下取整:4
System.out.println(Math.floor(4.99999999)); // 4.0
System.out.println(Math.floor(4.0)); // 4.0
// 4.求指数次方
System.out.println(Math.pow(2 , 3)); // 2^3 = 8.0
// 5.四舍五入 10
System.out.println(Math.round(4.49999)); // 4
System.out.println(Math.round(4.500001)); // 5
System.out.println(Math.random()); // 0.0 - 1.0 (包前不包后)
// 拓展: 3 - 9 之间的随机数 (0 - 6) + 3
// [0 - 6] + 3
int data = (int)(Math.random() * 7) + 3;
System.out.println(data);
}
}
输出结果
10
10.3
5.0
4.0
4.0
4.0
8.0
4
5
0.7219171930691749
3
System 类概述
System 类的常用方法
方法名
说明
public static void exit(int status)
终止当前运行的 Java 虚拟机,非零表示异常终止
public static long currentTimeMillis()
返回当前系统的时间毫秒值形式
public static void arraycopy(数据源数组, 起始索引, 目的地数组, 起始索引, 拷贝个数)
数组拷贝
时间毫秒值
原因
代码展示
import java.util.Arrays;
/**
目标:System系统类的使用。
System代表当前系统。(虚拟机系统)
静态方法:
1.public static void exit(int status):终止JVM虚拟机,非0是异常终止。
2.public static long currentTimeMillis():获取当前系统此刻时间毫秒值。(重点)
3.可以做数组的拷贝。
arraycopy(Object var0, int var1, Object var2, int var3, int var4);
* 参数一:原数组
* 参数二:从原数组的哪个位置开始赋值。
* 参数三:目标数组
* 参数四:赋值到目标数组的哪个位置
* 参数五:赋值几个。
*/
public class SystemDemo {
public static void main(String[] args) {
System.out.println("程序开始。。。");
// System.exit(0); // JVM终止!
// 2、计算机认为时间有起源:返回1970-1-1 00:00:00 走到此刻的总的毫秒值:时间毫秒值。
long time = System.currentTimeMillis();
System.out.println(time);
long startTime = System.currentTimeMillis();
// 进行时间的计算:性能分析
for (int i = 0; i < 100000; i++) {
System.out.println("输出:" + i);
}
long endTime = System.currentTimeMillis();
System.out.println((endTime - startTime)/1000.0 + "s");
// 3、做数组拷贝(了解)
/**
arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length)
参数一:被拷贝的数组
参数二:从哪个索引位置开始拷贝
参数三:复制的目标数组
参数四:粘贴位置
参数五:拷贝元素的个数
*/
int[] arr1 = {10, 20, 30, 40, 50, 60, 70};
int[] arr2 = new int[6]; // [0, 0, 0, 0, 0, 0] ==> [0, 0, 40, 50, 60, 0]
System.arraycopy(arr1, 3, arr2, 2, 3);
System.out.println(Arrays.toString(arr2));
System.out.println("-------------------");
double i = 10.0;
double j = 3.0;
//
// System.out.println(k1);
System.out.println("程序结束。。。。");
}
}
BigDecimal 作用

使用步骤
创建对象BigDecimal封装浮点型数据(最好的方式是调用方法)
public static BigDecimal valueOf(double val); // 包装浮点数成为BigDecimal对象。
valueOf 源码还是调用了 toString
BigDecima常用API
方法名
说明
public BigDecimal add(BigDecimal b)
加法
public BigDecimal subtract(BigDecimal b)
减法
public BigDecimal multiply(BigDecimal b)
乘法
public BigDecimal divide(BigDecimal b)
除法
public BigDecimal divide (另一个BigDecimal对象,精确几位,舍入模式)
除法
代码展示
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
目标:BigDecimal大数据类。
引入:
浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)。
BigDecimal可以解决浮点型运算数据失真的问题。
BigDicimal类:
包:java.math.
创建对象的方式(最好的方式:)
public static BigDecimal valueOf(double val) :包装浮点数成为大数据对象。
方法声明
public BigDecimal add(BigDecimal value) 加法运算
public BigDecimal subtract(BigDecimal value) 减法运算
public BigDecimal multiply(BigDecimal value) 乘法运算
public BigDecimal divide(BigDecimal value) 除法运算
public double doubleValue(): 把BigDecimal转换成double类型。
*/
public class BigDecimalDemo {
public static void main(String[] args) {
// 浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)。
System.out.println(0.09 + 0.01);
System.out.println(1.0 - 0.32);
System.out.println(1.015 * 100);
System.out.println(1.301 / 100);
System.out.println("-------------------------");
double a = 0.1;
double b = 0.2;
double c = a + b;
System.out.println(c);
System.out.println("--------------------------");
// 包装浮点型数据成为大数据对象 BigDeciaml
BigDecimal a1 = BigDecimal.valueOf(a);
BigDecimal b1 = BigDecimal.valueOf(b);
BigDecimal c1 = a1.add(b1);
// BigDecimal c1 = a1.subtract(b1);
// BigDecimal c1 = a1.multiply(b1);
// BigDecimal c1 = a1.divide(b1);
System.out.println(c1);
// 目的:double
double rs = c1.doubleValue();
System.out.println(rs);
// 注意事项:BigDecimal是一定要精度运算的
BigDecimal a11 = BigDecimal.valueOf(10.0);
BigDecimal b11 = BigDecimal.valueOf(3.0);
/**
参数一:除数 参数二:保留小数位数 参数三:舍入模式
*/
BigDecimal c11 = a11.divide(b11, 2, RoundingMode.HALF_UP); // 3.3333333333
System.out.println(c11);
System.out.println("-------------------");
}
}
输出结果
0.09999999999999999
0.6799999999999999
101.49999999999999
0.013009999999999999
-------------------------
0.30000000000000004
--------------------------
0.3
0.3
3.33
-------------------
除法问题
除法可能会导致结果为无限循环或无限不循环小数,故需要指定小数点精确到多少位,选择什么样的舍入模式
BigDecimal divide = bd1.divide(参与运算的对象, 小数点后精确到多少位, 舍入模式);
参数1 ,表示参与运算的 BigDecimal 对象。
参数2 ,表示小数点后面精确到多少位
参数3 ,舍入模式:
BigDecimal.ROUND_UP 进一法 BigDecimal.ROUND_FLOOR 去尾法 BigDecimal.ROUND_HALF_UP 四舍五入
Date 类概述
Date的构造器
名称
说明
public Date()
创建一个Date对象,代表的是系统当前此刻日期时间。
public Date(long time)
把时间毫秒值转换成Date日期对象。
Date的常用方法
名称
说明
public long getTime()
返回从1970年1月1日 00:00:00走到此刻的总的毫秒数
public void setTime(long time)
设置日期对象的时间为当前时间毫秒值对应的时间
代码展示
import java.util.Date;
/**
目标:学会使用Date类处理时间,获取时间的信息
*/
public class DateDemo1 {
public static void main(String[] args) {
// 1、创建一个Date类的对象:代表系统此刻日期时间对象
Date d = new Date();
System.out.println(d);
// 2、获取时间毫秒值
long time = d.getTime();
System.out.println(time);
// long time1 = System.currentTimeMillis();
// System.out.println(time1);
System.out.println("----------------------------");
// 1、得到当前时间
Date d1 = new Date();
System.out.println(d1);
// 2、当前时间往后走 1小时 121s
long time2 = System.currentTimeMillis();
time2 += (60 * 60 + 121) * 1000;
// 3、把时间毫秒值转换成对应的日期对象。
// Date d2 = new Date(time2);
// System.out.println(d2);
Date d3 = new Date();
d3.setTime(time2);
System.out.println(d3);
}
}
输出结果
Sat Apr 02 21:43:24 CST 2022
1648907004470
----------------------------
Sat Apr 02 21:43:24 CST 2022
Sat Apr 02 22:45:25 CST 2022



SimpleDateFormat 类作用

构造器
构造器
说明
public SimpleDateFormat(String pattern)
构造一个SimpleDateFormat,使用指定的格式
格式化方法
格式化方法
说明
public final String format(Date date)
将日期格式化成日期/时间字符串
public final String format(Object time)
将时间毫秒值式化成日期/时间字符串
格式化的时间形式的常用的模式对应关系

代码展示
import java.text.SimpleDateFormat;
import java.util.Date;
/**
目标:SimpleDateFormat简单日期格式化类的使用
格式化时间
解析时间
*/
public class SimpleDateFormatDemo01 {
public static void main(String[] args) {
// 1、日期对象
Date d = new Date();
System.out.println(d);
// 2、格式化这个日期对象 (指定最终格式化的形式)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
// 3、开始格式化日期对象成为喜欢的字符串形式
String rs = sdf.format(d);
System.out.println(rs);
System.out.println("----------------------------");
// 4、格式化时间毫秒值
// 需求:请问121秒后的时间是多少
long time1 = System.currentTimeMillis() + 121 * 1000;
String rs2 = sdf.format(time1);
System.out.println(rs2);
System.out.println("------------解析字符串时间,下个代码---------------");
}
}
输出结果
Sat Apr 02 21:48:06 CST 2022
2022年04月02日 21:48:06 星期六 下午
----------------------------
2022年04月02日 21:50:07 星期六 下午
------------解析字符串时间,下个代码---------------
解析字符串时间成为日期对象
解析方法
说明
public Date parse(String source)
从给定字符串的开始解析文本以生成日期
案例
代码展示
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatDemo2 {
public static void main(String[] args) throws ParseException {
// 目标: 学会使用SimpleDateFormat解析字符串时间成为日期对象。
// 有一个时间 2021年08月06日 11:11:11 往后 2天 14小时 49分 06秒后的时间是多少。
// 1、把字符串时间拿到程序中来
String dateStr = "2021年08月06日 11:11:11";
// 2、把字符串时间解析成日期对象(本节的重点):形式必须与被解析时间的形式完全一样,否则运行时解析报错!
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date d = sdf.parse(dateStr);
// 3、往后走2天 14小时 49分 06秒
long time = d.getTime() + (2L*24*60*60 + 14*60*60 + 49*60 + 6) * 1000;
// 4、格式化这个时间毫秒值就是结果
System.out.println(sdf.format(time));
}
}
输出结果
2021年08月09日 02:00:17
案例:秒杀活动
需求:
某购物网站举办秒杀活动,开始时间和结束时间如左图所示,当前活动结束后,系统记录到2位用户的付款时间分别如下:
小贾下单并付款的时间为:2020年11月11日 0:03:47
小皮下单并付款的时间为:2020年11月11日 0:10:11
规则:顾客的付款时间必须在秒杀时间之内,请判断出两位顾客是否秒杀成功。
分析:
代码展示
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatTest3 {
public static void main(String[] args) throws ParseException {
// 1、开始 和 结束时间
String startTime = "2021-11-11 00:00:00";
String endTime = "2021-11-11 00:10:00";
// 2、小贾 小皮
String xiaoJia = "2021-11-11 00:03:47";
String xiaoPi = "2021-11-11 00:10:11";
// 3、解析他们的时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d1 = sdf.parse(startTime);
Date d2 = sdf.parse(endTime);
Date d3 = sdf.parse(xiaoJia);
Date d4 = sdf.parse(xiaoPi);
if(d3.after(d1) && d3.before(d2)){
System.out.println("小贾秒杀成功,可以发货了!");
}else {
System.out.println("小贾秒杀失败!");
}
if(d4.after(d1) && d4.before(d2)){
System.out.println("小皮秒杀成功,可以发货了!");
}else {
System.out.println("小皮秒杀失败!");
}
}
}
输出结果
小贾秒杀成功,可以发货了!
小皮秒杀失败!
Calendar概述
Calendar日历类创建日历对象的方法:
方法名
说明
public static Calendar getInstance()
获取当前日历对象
Calendar常用方法
方法名
说明
public int get(int field)
取日期中的某个字段信息。
public void set(int field,int value)
修改日历的某个字段信息。
public void add(int field,int amount)
为某个字段增加/减少指定的值
public final Date getTime()
拿到此刻日期对象。
public long getTimeInMillis()
拿到此刻时间毫秒值
注意
代码展示
import java.util.Calendar;
import java.util.Date;
/**
目标:日历类Calendar的使用,可以得到更加丰富的信息。
Calendar代表了系统此刻日期对应的日历对象。
Calendar是一个抽象类,不能直接创建对象。
Calendar日历类创建日历对象的语法:
Calendar rightNow = Calendar.getInstance();
Calendar的方法:
1.public static Calendar getInstance(): 返回一个日历类的对象。
2.public int get(int field):取日期中的某个字段信息。
3.public void set(int field,int value):修改日历的某个字段信息。
4.public void add(int field,int amount):为某个字段增加/减少指定的值
5.public final Date getTime(): 拿到此刻日期对象。
6.public long getTimeInMillis(): 拿到此刻时间毫秒值
小结:
记住。
*/
public class CalendarDemo{
public static void main(String[] args) {
// 1、拿到系统此刻日历对象
Calendar cal = Calendar.getInstance();
System.out.println(cal);
// 2、获取日历的信息:public int get(int field):取日期中的某个字段信息。
int year = cal.get(Calendar.YEAR);
System.out.println(year);
int mm = cal.get(Calendar.MONTH) + 1;
System.out.println(mm);
int days = cal.get(Calendar.DAY_OF_YEAR) ;
System.out.println(days);
// 3、public void set(int field,int value):修改日历的某个字段信息。
// cal.set(Calendar.HOUR , 12);
// System.out.println(cal);
// 4.public void add(int field,int amount):为某个字段增加/减少指定的值
// 请问64天后是什么时间
cal.add(Calendar.DAY_OF_YEAR , 64);
cal.add(Calendar.MINUTE , 59);
// 5.public final Date getTime(): 拿到此刻日期对象。
Date d = cal.getTime();
System.out.println(d);
// 6.public long getTimeInMillis(): 拿到此刻时间毫秒值
long time = cal.getTimeInMillis();
System.out.println(time);
}
}
输出结果
java.util.GregorianCalendar[time=1648908569874,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2022,MONTH=3,WEEK_OF_YEAR=14,WEEK_OF_MONTH=1,DAY_OF_MONTH=2,DAY_OF_YEAR=92,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=10,HOUR_OF_DAY=22,MINUTE=9,SECOND=29,MILLISECOND=874,ZONE_OFFSET=28800000,DST_OFFSET=0]
2022
4
92
Sun Jun 05 23:08:29 CST 2022
1654441709874
概述

构建对象的方式

LocalDate、LocalTime、LocalDateTime 获取信息的方法
方法名
说明
public int geYear()
获取年
public int getMonthValue()
获取月份(1-12)
Public int getDayOfMonth()
获取月中第几天乘法
Public int getDayOfYear()
获取年中第几天
Public DayOfWeek getDayOfWeek()
获取星期
转换相关的API

修改相关的API
方法名
说明
plusDays, plusWeeks, plusMonths, plusYears
向当前 LocalDate 对象添加几天、 几周、几个月、几年
minusDays, minusWeeks, minusMonths, minusYears
从当前 LocalDate 对象减去几天、 几周、几个月、几年
withDayOfMonth, withDayOfYear, withMonth, withYear
将月份天数、年份天数、月份、年 份 修 改 为 指 定 的 值 并 返 回 新 的 LocalDate 对象
isBefore, isAfter
比较两个 LocalDate
代码展示
LocalDate
import java.time.LocalDate;
import java.time.Month;
public class Demo01LocalDate {
public static void main(String[] args) {
// 1、获取本地日期对象。
LocalDate nowDate = LocalDate.now();
System.out.println("今天的日期:" + nowDate);//今天的日期:
int year = nowDate.getYear();
System.out.println("year:" + year);
int month = nowDate.getMonthValue();
System.out.println("month:" + month);
int day = nowDate.getDayOfMonth();
System.out.println("day:" + day);
//当年的第几天
int dayOfYear = nowDate.getDayOfYear();
System.out.println("dayOfYear:" + dayOfYear);
//星期
System.out.println(nowDate.getDayOfWeek());
System.out.println(nowDate.getDayOfWeek().getValue());
//月份
System.out.println(nowDate.getMonth());//AUGUST
System.out.println(nowDate.getMonth().getValue());//8
System.out.println("------------------------");
LocalDate bt = LocalDate.of(1991, 11, 11);
System.out.println(bt);//直接传入对应的年月日
System.out.println(LocalDate.of(1991, Month.NOVEMBER, 11));//相对上面只是把月换成了枚举
}
}
输出结果
今天的日期:2022-04-02
year:2022
month:4
day:2
dayOfYear:92
SATURDAY
6
APRIL
4
------------------------
1991-11-11
1991-11-11
LocalTime
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
public class Demo02LocalTime {
public static void main(String[] args) {
// 1、获取本地时间对象。
LocalTime nowTime = LocalTime.now();
System.out.println("今天的时间:" + nowTime);//今天的时间:
int hour = nowTime.getHour();//时
System.out.println("hour:" + hour);//hour:
int minute = nowTime.getMinute();//分
System.out.println("minute:" + minute);//minute:
int second = nowTime.getSecond();//秒
System.out.println("second:" + second);//second:
int nano = nowTime.getNano();//纳秒
System.out.println("nano:" + nano);//nano:
System.out.println("-----");
System.out.println(LocalTime.of(8, 20));//时分
System.out.println(LocalTime.of(8, 20, 30));//时分秒
System.out.println(LocalTime.of(8, 20, 30, 150));//时分秒纳秒
LocalTime mTime = LocalTime.of(8, 20, 30, 150);
System.out.println("---------------");
System.out.println(LocalDateTime.of(1991, 11, 11, 8, 20));
System.out.println(LocalDateTime.of(1991, Month.NOVEMBER, 11, 8, 20));
System.out.println(LocalDateTime.of(1991, 11, 11, 8, 20, 30));
System.out.println(LocalDateTime.of(1991, Month.NOVEMBER, 11, 8, 20, 30));
System.out.println(LocalDateTime.of(1991, 11, 11, 8, 20, 30, 150));
System.out.println(LocalDateTime.of(1991, Month.NOVEMBER, 11, 8, 20, 30, 150));
}
}
输出结果
今天的时间:22:18:20.462
hour:22
minute:18
second:20
nano:462000000
-----
08:20
08:20:30
08:20:30.000000150
---------------
1991-11-11T08:20
1991-11-11T08:20
1991-11-11T08:20:30
1991-11-11T08:20:30
1991-11-11T08:20:30.000000150
1991-11-11T08:20:30.000000150
LocalDateTime
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Demo03LocalDateTime {
public static void main(String[] args) {
// 日期 时间
LocalDateTime nowDateTime = LocalDateTime.now();
System.out.println("今天是:" + nowDateTime);//今天是:
System.out.println(nowDateTime.getYear());//年
System.out.println(nowDateTime.getMonthValue());//月
System.out.println(nowDateTime.getDayOfMonth());//日
System.out.println(nowDateTime.getHour());//时
System.out.println(nowDateTime.getMinute());//分
System.out.println(nowDateTime.getSecond());//秒
System.out.println(nowDateTime.getNano());//纳秒
//日:当年的第几天
System.out.println("dayOfYear:" + nowDateTime.getDayOfYear());//dayOfYear:249
//星期
System.out.println(nowDateTime.getDayOfWeek());//THURSDAY
System.out.println(nowDateTime.getDayOfWeek().getValue());//4
//月份
System.out.println(nowDateTime.getMonth());//SEPTEMBER
System.out.println(nowDateTime.getMonth().getValue());//9
LocalDate ld = nowDateTime.toLocalDate();
System.out.println(ld);
LocalTime lt = nowDateTime.toLocalTime();
System.out.println(lt.getHour());
System.out.println(lt.getMinute());
System.out.println(lt.getSecond());
}
}
输出结果
今天是:2022-04-02T22:19:33.222
2022
4
2
22
19
33
222000000
dayOfYear:92
SATURDAY
6
APRIL
4
2022-04-02
22
19
33
UpdateTime
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.MonthDay;
public class Demo04UpdateTime {
public static void main(String[] args) {
LocalTime nowTime = LocalTime.now();
System.out.println(nowTime);//当前时间
System.out.println(nowTime.minusHours(1));//一小时前
System.out.println(nowTime.minusMinutes(1));//一分钟前
System.out.println(nowTime.minusSeconds(1));//一秒前
System.out.println(nowTime.minusNanos(1));//一纳秒前
System.out.println("----------------");
System.out.println(nowTime.plusHours(1));//一小时后
System.out.println(nowTime.plusMinutes(1));//一分钟后
System.out.println(nowTime.plusSeconds(1));//一秒后
System.out.println(nowTime.plusNanos(1));//一纳秒后
System.out.println("------------------");
// 不可变对象,每次修改产生新对象!
System.out.println(nowTime);
System.out.println("---------------");
LocalDate myDate = LocalDate.of(2018, 9, 5);
LocalDate nowDate = LocalDate.now();
System.out.println("今天是2018-09-06吗? " + nowDate.equals(myDate));//今天是2018-09-06吗? false
System.out.println(myDate + "是否在" + nowDate + "之前? " + myDate.isBefore(nowDate));//2018-09-05是否在2018-09-06之前? true
System.out.println(myDate + "是否在" + nowDate + "之后? " + myDate.isAfter(nowDate));//2018-09-05是否在2018-09-06之后? false
System.out.println("---------------------------");
// 判断今天是否是你的生日
LocalDate birDate = LocalDate.of(1996, 8, 5);
LocalDate nowDate1 = LocalDate.now();
MonthDay birMd = MonthDay.of(birDate.getMonthValue(), birDate.getDayOfMonth());
MonthDay nowMd = MonthDay.from(nowDate1);
System.out.println("今天是你的生日吗? " + birMd.equals(nowMd));//今天是你的生日吗? false
}
}
输出结果
22:21:42.399
21:21:42.399
22:20:42.399
22:21:41.399
22:21:42.398999999
----------------
23:21:42.399
22:22:42.399
22:21:43.399
22:21:42.399000001
------------------
22:21:42.399
---------------
今天是2018-09-06吗? false
2018-09-05是否在2022-04-02之前? true
2018-09-05是否在2022-04-02之后? false
---------------------------
今天是你的生日吗? false
Instant 时间戳
JDK8获取时间戳特别简单,且功能更丰富。Instant类由一个静态的工厂方法now()可以返回当前时间戳。
Instant instant = Instant.now();
System.out.println(“当前时间戳是:” + instant);
Date date = Date.from(instant);
System.out.println(“当前时间戳是:” + date);
instant = date.toInstant();
System.out.println(instant);
时间戳是包含日期和时间的,与 java.util.Date 很类似,事实上 Instant 就是类似 JDK8 以前的 Date。
Instant 和 Date 这两个类可以进行转换。
代码展示
import java.time.Instant;
import java.time.ZoneId;
import java.util.Date;
public class Demo05Instant {
public static void main(String[] args) {
// 1、得到一个Instant时间戳对象
Instant instant = Instant.now();
System.out.println(instant);
// 2、系统此刻的时间戳怎么办?
Instant instant1 = Instant.now();
System.out.println(instant1.atZone(ZoneId.systemDefault()));
// 3、如何去返回Date对象
Date date = Date.from(instant);
System.out.println(date);
Instant i2 = date.toInstant();
System.out.println(i2);
}
}
输出结果
2022-04-02T14:26:12.737Z
2022-04-02T22:26:12.863+08:00[Asia/Shanghai]
Sat Apr 02 22:26:12 CST 2022
2022-04-02T14:26:12.737Z
在JDK8中,引入了一个全新的日期与时间格式器DateTimeFormatter。
正反都能调用format方法。
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);//2021-03-01T15:09:17.444190900
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”);
String ldtStr = ldt.format(dtf);
System.out.println(ldtStr);//2021-03-01 15:09:17
String ldtStr1 = dtf.format(ldt);
System.out.println(ldtStr1);//2021-03-01 15:09:17
代码展示
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Demo06DateTimeFormat {
public static void main(String[] args) {
// 本地此刻 日期时间 对象
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
// 解析/格式化器
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss EEE a");
// 正向格式化
System.out.println(dtf.format(ldt));
// 逆向格式化
System.out.println(ldt.format(dtf));
// 解析字符串时间
DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 解析当前字符串时间成为本地日期时间对象
LocalDateTime ldt1 = LocalDateTime.parse("2019-11-11 11:11:11" , dtf1);
System.out.println(ldt1);
System.out.println(ldt1.getDayOfYear());
}
}
输出结果
2022-04-02T22:31:23.910
2022-04-02 22:31:23 星期六 下午
2022-04-02 22:31:23 星期六 下午
2019-11-11T11:11:11
315
代码展示
import java.time.LocalDate;
import java.time.Period;
public class Demo07Period {
public static void main(String[] args) {
// 当前本地 年月日
LocalDate today = LocalDate.now();
System.out.println(today);//
// 生日的 年月日
LocalDate birthDate = LocalDate.of(1998, 10, 13);
System.out.println(birthDate);
Period period = Period.between(birthDate, today);//第二个参数减第一个参数
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
}
}
输出结果
2022-04-02
1998-10-13
23
5
20
代码展示
import java.time.Duration;
import java.time.LocalDateTime;
public class Demo08Duration {
public static void main(String[] args) {
// 本地日期时间对象。
LocalDateTime today = LocalDateTime.now();
System.out.println(today);
// 出生的日期时间对象
LocalDateTime birthDate = LocalDateTime.of(2021,8,06,01,00,00);
System.out.println(birthDate);
Duration duration = Duration.between(birthDate, today);//第二个参数减第一个参数
System.out.println(duration.toDays());//两个时间差的天数
System.out.println(duration.toHours());//两个时间差的小时数
System.out.println(duration.toMinutes());//两个时间差的分钟数
System.out.println(duration.toMillis());//两个时间差的毫秒数
System.out.println(duration.toNanos());//两个时间差的纳秒数
}
}
输出结果
2022-04-02T22:36:53.207
2021-08-06T01:00
239
5757
345456
20727413207
20727413207000000
java.time.temporal.ChronoUnit
代码展示
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class Demo09ChronoUnit {
public static void main(String[] args) {
// 本地日期时间对象:此刻的
LocalDateTime today = LocalDateTime.now();
System.out.println(today);
// 生日时间
LocalDateTime birthDate = LocalDateTime.of(1990,10,1,
10,50,59);
System.out.println(birthDate);
System.out.println("相差的年数:" + ChronoUnit.YEARS.between(birthDate, today));
System.out.println("相差的月数:" + ChronoUnit.MONTHS.between(birthDate, today));
System.out.println("相差的周数:" + ChronoUnit.WEEKS.between(birthDate, today));
System.out.println("相差的天数:" + ChronoUnit.DAYS.between(birthDate, today));
System.out.println("相差的时数:" + ChronoUnit.HOURS.between(birthDate, today));
System.out.println("相差的分数:" + ChronoUnit.MINUTES.between(birthDate, today));
System.out.println("相差的秒数:" + ChronoUnit.SECONDS.between(birthDate, today));
System.out.println("相差的毫秒数:" + ChronoUnit.MILLIS.between(birthDate, today));
System.out.println("相差的微秒数:" + ChronoUnit.MICROS.between(birthDate, today));
System.out.println("相差的纳秒数:" + ChronoUnit.NANOS.between(birthDate, today));
System.out.println("相差的半天数:" + ChronoUnit.HALF_DAYS.between(birthDate, today));
System.out.println("相差的十年数:" + ChronoUnit.DECADES.between(birthDate, today));
System.out.println("相差的世纪(百年)数:" + ChronoUnit.CENTURIES.between(birthDate, today));
System.out.println("相差的千年数:" + ChronoUnit.MILLENNIA.between(birthDate, today));
System.out.println("相差的纪元数:" + ChronoUnit.ERAS.between(birthDate, today));
}
}
输出结果
2022-04-02T22:38:45.180
1990-10-01T10:50:59
相差的年数:31
相差的月数:378
相差的周数:1643
相差的天数:11506
相差的时数:276155
相差的分数:16569347
相差的秒数:994160866
相差的毫秒数:994160866180
相差的微秒数:994160866180000
相差的纳秒数:994160866180000000
相差的半天数:23012
相差的十年数:3
相差的世纪(百年)数:0
相差的千年数:0
相差的纪元数:0
包装类
基本数据类型
引用数据类型
byte
Byte
short
Short
int
Integer
long
Long
char
Character
float
Float
double
Double
boolean
Boolean
为什么提供包装类?
自动装箱
自动拆箱
包装类的特有功能
代码演示
/**
目标:明白包装类的概念,并使用。
*/
public class Test {
public static void main(String[] args) {
int a = 10;
Integer a1 = 11;
Integer a2 = a; // 自动装箱
System.out.println(a);
System.out.println(a1);
Integer it = 100;
int it1 = it; // 自动拆箱
System.out.println(it1);
System.out.println(it1 == it);
double db = 99.5;
Double db2 = db; // 自动装箱了
double db3 = db2; // 自动拆箱
System.out.println(db3);
System.out.println(db == db2);
// int age = null; // 报错了!
Integer age1 = null;
Integer age2 = 0;
System.out.println("-----------------");
// 1、包装类可以把基本类型的数据转换成字符串形式。(没啥用)
Integer i3 = 23;
String rs = i3.toString();
System.out.println(rs + 1);
String rs1 = Integer.toString(i3);
System.out.println(rs1 + 1);
// 可以直接+字符串得到字符串类型
String rs2 = i3 + "";
System.out.println(rs2 + 1);
System.out.println("-----------------");
String number = "23";
//转换成整数
// int age = Integer.parseInt(number);
int age = Integer.valueOf(number);
System.out.println(age + 1);
String number1 = "99.9";
//转换成小数
// double score = Double.parseDouble(number1);
double score = Double.valueOf(number1);
System.out.println(score + 0.1);
}
}
输出结果
10
11
100
true
99.5
true
-----------------
231
231
231
-----------------
24
100.0
装箱拆箱后的值是相等的
System.out.println(it1 == it); // true
System.out.println(db == db2); // true
**需求:**假如现在要求校验一个qq号码是否正确,6位及20位之内,必须全部是数字 。
代码展示
public class RegexDemo1 {
public static void main(String[] args) {
// 需求:校验qq号码,必须全部数字 6 - 20位
System.out.println(checkQQ("251425998"));
System.out.println(checkQQ("2514259a98"));
System.out.println(checkQQ(null));
System.out.println(checkQQ("2344"));
System.out.println("-------------------------");
// 正则表达式的初体验:
System.out.println(checkQQ2("251425998"));
System.out.println(checkQQ2("2514259a98"));
System.out.println(checkQQ2(null));
System.out.println(checkQQ2("2344"));
}
public static boolean checkQQ2(String qq){
return qq != null && qq.matches("\d{6,20}");
}
public static boolean checkQQ(String qq){
// 1、判断qq号码的长度是否满足要求
if(qq == null || qq.length() < 6 || qq.length() > 20 ) {
return false;
}
// 2、判断qq中是否全部是数字,不是返回false
// 251425a87
for (int i = 0; i < qq.length(); i++) {
// 获取每位字符
char ch = qq.charAt(i);
// 判断这个字符是否不是数字,不是数字直接返回false
if(ch < '0' || ch > '9') {
return false;
}
}
return true; // 肯定合法了!
}
}
输出结果
true
false
false
false
-------------------------
true
false
false
false

代码展示
/**
目标:全面、深入学习正则表达式的规则
*/
public class RegexDemo02 {
public static void main(String[] args) {
//public boolean matches(String regex):判断是否与正则表达式匹配,匹配返回true
// 只能是 a b c
System.out.println("a".matches("[abc]")); // true
System.out.println("z".matches("[abc]")); // false
// 不能出现a b c
System.out.println("a".matches("[^abc]")); // false
System.out.println("z".matches("[^abc]")); // true
System.out.println("a".matches("\d")); // false
System.out.println("3".matches("\d")); // true
System.out.println("333".matches("\d")); // false
System.out.println("z".matches("\w")); // true
System.out.println("2".matches("\w")); // true
System.out.println("21".matches("\w")); // false
System.out.println("你".matches("\w")); //false
System.out.println("你".matches("\W")); // true
System.out.println("---------------------------------");
// 以上正则匹配只能校验单个字符。
// 校验密码
// 必须是数字 字母 下划线 至少 6位
System.out.println("2442fsfsf".matches("\w{6,}"));
System.out.println("244f".matches("\w{6,}"));
// 验证码 必须是数字和字符 必须是4位
System.out.println("23dF".matches("[a-zA-Z0-9]{4}"));
System.out.println("23_F".matches("[a-zA-Z0-9]{4}"));
System.out.println("23dF".matches("[\w&&[^_]]{4}"));
System.out.println("23_F".matches("[\w&&[^_]]{4}"));
}
}
输出结果:
true
false
true
false
true
true
false
false
true
---------------------------------
true
false
true
false
true
false
需求:
分析:
代码展示
public static void checkTel(){
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请您输入您的电话号码:");
String tel = sc.next();
// 判断邮箱格式是否正确 027-3572457 0273572457
if(tel.matches("0\d{2,6}-?\d{5,20}")){
System.out.println("格式正确,注册完成!");
break;
}else {
System.out.println("格式有误!");
}
}
}
public static void checkEmail(){
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请您输入您的注册邮箱:");
String email = sc.next();
// 判断邮箱格式是否正确 3268847878@qq.com
// 判断邮箱格式是否正确 3268847dsda878@163.com
// 判断邮箱格式是否正确 3268847dsda878@pci.com.cn
if(email.matches("\w{1,30}@[a-zA-Z0-9]{2,20}(\.[a-zA-Z0-9]{2,20}){1,2}")){
System.out.println("邮箱格式正确,注册完成!");
break;
}else {
System.out.println("格式有误!");
}
}
}
public static void checkPhone(){
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请您输入您的注册手机号码:");
String phone = sc.next();
// 判断手机号码的格式是否正确
if(phone.matches("1[3-9]\d{9}")){
System.out.println("手机号码格式正确,注册完成!");
break;
}else {
System.out.println("格式有误!");
}
}
方法名
说明
public String replaceAll(String regex,String newStr)
按照正则表达式匹配的内容进行替换
public String[] split(String regex):
按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。
代码展示
/**
目标:正则表达式在方法中的应用。
public String[] split(String regex):
-- 按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。
public String replaceAll(String regex,String newStr)
-- 按照正则表达式匹配的内容进行替换
*/
public class RegexDemo04 {
public static void main(String[] args) {
String names = "小路dhdfhdf342蓉儿43fdffdfbjdfaf小何";
String[] arrs = names.split("\w+");
for (int i = 0; i < arrs.length; i++) {
System.out.println(arrs[i]);
}
String names2 = names.replaceAll("\w+", " ");
System.out.println(names2);
}
}
输出结果
小路
蓉儿
小何
小路 蓉儿 小何
代码展示
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
拓展:正则表达式爬取信息中的内容。(了解)
*/
public class RegexDemo05 {
public static void main(String[] args) {
String rs = "来黑马程序学习Java,电话020-43422424,或者联系邮箱" +
"itcast@itcast.cn,电话18762832633,0203232323" +
"邮箱bozai@itcast.cn,400-100-3233 ,4001003232";
// 需求:从上面的内容中爬取出 电话号码和邮箱。
// 1、定义爬取规则,字符串形式
String regex = "(\w{1,30}@[a-zA-Z0-9]{2,20}(\.[a-zA-Z0-9]{2,20}){1,2})|(1[3-9]\d{9})" +
"|(0\d{2,6}-?\d{5,20})|(400-?\d{3,9}-?\d{3,9})";
// 2、把这个爬取规则编译成匹配对象。
Pattern pattern = Pattern.compile(regex);
// 3、得到一个内容匹配器对象
Matcher matcher = pattern.matcher(rs);
// 4、开始找了
while (matcher.find()) {
String rs1 = matcher.group();
System.out.println(rs1);
}
}
}
输出结果
020-43422424
itcast@itcast.cn
18762832633
0203232323
bozai@itcast.cn
400-100-3233
4001003232
Arrays类的常用API
方法名
说明
public static String toString(类型[] a)
返回数组的内容(字符串形式)
public static void sort(类型[] a)
对数组进行默认升序排序
public static void sort(类型[] a, Comparator< super T> c)
使用比较器对象自定义排序
public static int binarySearch(int[] a, int key)
二分搜索数组中的数据,存在返回索引,不存在返回-1
数组与 ArrayList 的区别
ArrayList 底层已经默认调用了 toString()。
代码展示
import java.util.ArrayList;
import java.util.Arrays;
public class ArraysDemo1 {
public static void main(String[] args) {
// 目标:学会使用Arrays类的常用API ,并理解其原理
int[] arr = {10, 2, 55, 23, 24, 100};
System.out.println(arr);
ArrayList list = new ArrayList<>();
list.add("迪丽热巴");
list.add("古力娜扎");
list.add("超人迪加");
// ArrayList 输出结果
[I@1b6d3586
[迪丽热巴, 古力娜扎, 超人迪加]
[10, 2, 55, 23, 24, 100]
[2, 10, 23, 24, 55, 100]
4
-3
-7
Arrays类的排序方法
方法名
说明
public static void sort(类型[] a)
对数组进行默认升序排序
public static void sort(类型[] a, Comparator< super T> c)
使用比较器对象自定义排序
自定义排序规则
代码展示
学生对象
public class Student {
private String name;
private int age;
private double height;
public Student() {
}
public Student(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
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;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", age=" + age +
", height=" + height +
'}';
}
}
测试类
import java.util.Arrays;
import java.util.Comparator;
public class ArraysDemo2 {
public static void main(String[] args) {
// 目标:自定义数组的排序规则:Comparator比较器对象。
// 1、Arrays的sort方法对于有值特性的数组是默认升序排序
int[] ages = {34, 12, 42, 23};
Arrays.sort(ages);
System.out.println(Arrays.toString(ages));
// 2、需求:降序排序!(自定义比较器对象,只能支持引用类型的排序!!)
Integer[] ages1 = {34, 12, 42, 23};
/**
参数一:被排序的数组 必须是引用类型的元素
参数二:匿名内部类对象,代表了一个比较器对象。
*/
Arrays.sort(ages1, new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
// 指定比较规则。
// if(o1 > o2){
// return 1;
// }else if(o1 < o2){
// return -1;
// }
// return 0;
// return o1 - o2; // 默认升序
return o2 - o1; // 降序
}
});
System.out.println(Arrays.toString(ages1));
System.out.println("-------------------------");
Student[] students = new Student[3];
students[0] = new Student("吴磊",23 , 175.5);
students[1] = new Student("谢鑫",18 , 185.5);
students[2] = new Student("王亮",20 , 195.5);
System.out.println(Arrays.toString(students));
// Arrays.sort(students); // 直接运行奔溃
Arrays.sort(students, new Comparator() {
@Override
public int compare(Student o1, Student o2) {
// 自己指定比较规则
// return o1.getAge() - o2.getAge(); // 按照年龄升序排序!
// return o2.getAge() - o1.getAge(); // 按照年龄降序排序!!
// return Double.compare(o1.getHeight(), o2.getHeight()); // 比较浮点型可以这样写 升序
return Double.compare(o2.getHeight(), o1.getHeight()); // 比较浮点型可以这样写 降序
}
});
System.out.println(Arrays.toString(students));
}
}
输出结果
[12, 23, 34, 42]
[42, 34, 23, 12]
-------------------------
[Student{name='吴磊', age=23, height=175.5}, Student{name='谢鑫', age=18, height=185.5}, Student{name='王亮', age=20, height=195.5}]
[Student{name='王亮', age=20, height=195.5}, Student{name='谢鑫', age=18, height=185.5}, Student{name='吴磊', age=23, height=175.5}]


代码展示
import java.util.Arrays;
/**
目标:学会使用选择排序的方法对数组进行排序。
*/
public class Test1 {
public static void main(String[] args) {
// 1、定义数组
int[] arr = {5, 1, 3, 2};
// 0 1 2 3
// 2、定义一个循环控制选择几轮: arr.length - 1
for (int i = 0; i < arr.length - 1; i++) {
// i = 0 j = 1 2 3
// i = 1 j = 2 3
// i = 2 j = 3
// 3、定义内部循环,控制选择几次
for (int j = i + 1; j < arr.length; j++) {
// 当前位:arr[i]
// 如果有比当前位数据更小的,则交换
if(arr[i] > arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
输出结果
[1, 2, 3, 5]
代码展示
/**
目标:理解二分搜索的原理并实现。
*/
public class Test2 {
public static void main(String[] args) {
// 1、定义数组
int[] arr = {10, 14, 16, 25, 28, 30, 35, 88, 100};
// r
// l
//
System.out.println(binarySearch(arr , 35));
System.out.println(binarySearch(arr , 350));
}
/**
* 二分查找算法的实现
* @param arr 排序的数组
* @param data 要找的数据
* @return 索引,如果元素不存在,直接返回-1
*/
public static int binarySearch(int[] arr, int data){
// 1、定义左边位置 和 右边位置
int left = 0;
int right = arr.length - 1;
// 2、开始循环,折半查询。
while (left <= right){
// 取中间索引
int middleIndex = (left + right) / 2;
// 3、判断当前中间位置的元素和要找的元素的大小情况
if(data > arr[middleIndex]) {
// 往右边找,左位置更新为 = 中间索引+1
left = middleIndex + 1;
}else if(data < arr[middleIndex]) {
// 往左边找,右边位置 = 中间索引 - 1
right = middleIndex - 1;
}else {
return middleIndex;
}
}
return -1; // 查无此元素
}
}
输出结果
6
-1

简化过程
public class LambdaDemo2 {
public static void main(String[] args) {
// 目标:学会使用Lambda的标准格式简化匿名内部类的代码形式
// 注意:Lambda只能简化接口中只有一个抽象方法的匿名内部类形式(函数式接口)
// Swimming s1 = new Swimming() {
// @Override
// public void swim() {
// System.out.println("老师游泳贼溜~~~~~");
// }
// };
// Swimming s1 = () -> {
// System.out.println("老师游泳贼溜~~~~~");
// };
Swimming s1 = () -> System.out.println("老师游泳贼溜~~~~~");
go(s1);
System.out.println("---------------------");
// go(new Swimming() {
// @Override
// public void swim() {
// System.out.println("学生游泳很开心~~~");
// }
// });
// go(() ->{
// System.out.println("学生游泳很开心~~~");
// });
go(() -> System.out.println("学生游泳很开心~~~"));
}
public static void go(Swimming s){
System.out.println("开始。。。");
s.swim();
System.out.println("结束。。。");
}
}
@FunctionalInterface // 一旦加上这个注解必须是函数式接口,里面只能有一个抽象方法
interface Swimming{
void swim();
}
Lambda表达式有什么使用前提?
必须是接口的匿名内部类,接口中只能有一个抽象方法。
Lambda表达式简化Comparator接口的匿名形式

Lambda表达式简化按钮监听器ActionListener的匿名内部类形式

简化过程
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Comparator;
public class LambdaDemo3 {
public static void main(String[] args) {
Integer[] ages1 = {34, 12, 42, 23};
/**
参数一:被排序的数组 必须是引用类型的元素
参数二:匿名内部类对象,代表了一个比较器对象。
*/
// Arrays.sort(ages1, new Comparator() {
// @Override
// public int compare(Integer o1, Integer o2) {
// return o2 - o1; // 降序
// }
// });
// Arrays.sort(ages1, (Integer o1, Integer o2) -> {
// return o2 - o1; // 降序
// });
// Arrays.sort(ages1, ( o1, o2) -> {
// return o2 - o1; // 降序
// });
Arrays.sort(ages1, ( o1, o2 ) -> o2 - o1 );
System.out.println(Arrays.toString(ages1));
System.out.println("---------------------------");
JFrame win = new JFrame("登录界面");
JButton btn = new JButton("我是一个很大的按钮");
// btn.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// System.out.println("有人点我,点我,点我!!");
// }
// });
// btn.addActionListener((ActionEvent e) -> {
// System.out.println("有人点我,点我,点我!!");
// });
// btn.addActionListener(( e) -> {
// System.out.println("有人点我,点我,点我!!");
// });
// btn.addActionListener( e -> {
// System.out.println("有人点我,点我,点我!!");
// });
btn.addActionListener( e -> System.out.println("有人点我,点我,点我!!") );
win.add(btn);
win.setSize(400, 300);
win.setVisible(true);
}
}
Lambda表达式的省略写法(进一步在Lambda表达式的基础上继续简化)
集合和数组都是容器。
数组的特点
集合的特点
数组与集合的比较
1、数组和集合的元素存储的个数问题。
2、数组和集合存储元素的类型问题。
3、数组和集合适合的场景



代码演示
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
/**
目标:明确Collection集合体系的特点
*/
public class CollectionDemo1 {
public static void main(String[] args) {
// 有序 可重复 有索引
Collection list = new ArrayList();
list.add("Java");
list.add("Java");
list.add("Mybatis");
list.add(23);
list.add(23);
list.add(false);
list.add(false);
System.out.println(list);
// 无序 不重复 无索引
Collection list1 = new HashSet();
list1.add("Java");
list1.add("Java");
list1.add("Mybatis");
list1.add(23);
list1.add(23);
list1.add(false);
list1.add(false);
System.out.println(list1);
// Collection list2 = new ArrayList();
Collection list2 = new ArrayList<>(); // JDK 7开始之后后面类型申明可以不写
list2.add("Java");
// list2.add(23);
list2.add("黑马");
// 集合和泛型不支持基本数据类型,只能支持引用数据类型
// Collection list3 = new ArrayList<>();
Collection list3 = new ArrayList<>();
list3.add(23);
list3.add(233);
list3.add(2333);
Collection list4 = new ArrayList<>();
list4.add(23.4);
list4.add(233.0);
list4.add(233.3);
}
}
输出结果
[Java, Java, Mybatis, 23, 23, false, false]
[Java, false, 23, Mybatis]
Collection 集合
Collection 是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
Collection API
方法名称
说明
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()
把集合中的元素,存储到数组中
代码演示
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
/**
目标:Collection集合的常用API.
Collection是集合的祖宗类,它的功能是全部集合都可以继承使用的,所以要学习它。
Collection API如下:
- 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(): 把集合中的元素,存储到数组中。
小结:
记住以上API。
*/
public class CollectionDemo {
public static void main(String[] args) {
// HashSet:添加的元素是无序,不重复,无索引。
Collection c = new ArrayList<>();
// 1.添加元素, 添加成功返回true。
c.add("Java");
c.add("HTML");
System.out.println(c.add("HTML"));
c.add("MySQL");
c.add("Java");
System.out.println(c.add("黑马"));
System.out.println(c); // [Java, HTML, HTML, MySQL, Java, 黑马]
// 2.清空集合的元素。
// c.clear();
// System.out.println(c);
// 3.判断集合是否为空 是空返回true,反之。
// System.out.println(c.isEmpty());
// 4.获取集合的大小。
System.out.println(c.size());
// 5.判断集合中是否包含某个元素。
System.out.println(c.contains("Java")); // true
System.out.println(c.contains("java")); // false
System.out.println(c.contains("黑马")); // true
// 6.删除某个元素:如果有多个重复元素默认删除前面的第一个!
System.out.println(c.remove("java")); // false
System.out.println(c);
System.out.println(c.remove("Java")); // true
System.out.println(c);
// 7.把集合转换成数组 [HTML, HTML, MySQL, Java, 黑马]
Object[] arrs = c.toArray();
System.out.println("数组:" + Arrays.toString(arrs));
System.out.println("----------------------拓展----------------------");
Collection c1 = new ArrayList<>();
c1.add("java1");
c1.add("java2");
Collection c2 = new ArrayList<>();
c2.add("赵敏");
c2.add("殷素素");
// addAll把c2集合的元素全部倒入到c1中去。
c1.addAll(c2);
System.out.println(c1);
System.out.println(c2);
}
}
输出结果
true
true
[Java, HTML, HTML, MySQL, Java, 黑马]
6
true
false
true
false
[Java, HTML, HTML, MySQL, Java, 黑马]
true
[HTML, HTML, MySQL, Java, 黑马]
数组:[HTML, HTML, MySQL, Java, 黑马]
----------------------拓展----------------------
[java1, java2, 赵敏, 殷素素]
[赵敏, 殷素素]
迭代器遍历概述
Collection 集合获取迭代器
方法名称
说明
Iterator iterator()
返回集合中的迭代器对象,该迭代器对象默认指向当前集合的0索引
Iterator中的常用方法
方法名称
说明
boolean hasNext()
询问当前位置是否有元素存在,存在返回true ,不存在返回false
E next()
获取当前位置的元素,并同时将迭代器对象移向下一个位置,注意防止取出越界。
代码演示
import java.util.ArrayList;
import java.util.Iterator;
/**
目标:Collection集合的遍历方式。
什么是遍历? 为什么开发中要遍历?
遍历就是一个一个的把容器中的元素访问一遍。
开发中经常要统计元素的总和,找最值,找出某个数据然后干掉等等业务都需要遍历。
Collection集合的遍历方式是全部集合都可以直接使用的,所以我们学习它。
Collection集合的遍历方式有三种:
(1)迭代器。
(2)foreach(增强for循环)。
(3)JDK 1.8开始之后的新技术Lambda表达式(了解)
a.迭代器遍历集合。
-- 方法:
public Iterator iterator(): 获取集合对应的迭代器,用来遍历集合中的元素的
boolean hasNext():判断是否有下一个元素,有返回true ,反之。
E next():获取下一个元素值!
--流程:
1.先获取当前集合的迭代器
Iterator it = lists.iterator();
2.定义一个while循环,问一次取一次。
通过it.hasNext()询问是否有下一个元素,有就通过
it.next()取出下一个元素。
小结:
记住代码。
*/
public class CollectionDemo01 {
public static void main(String[] args) {
ArrayList lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("素素");
lists.add("灭绝");
System.out.println(lists);
// [赵敏, 小昭, 素素, 灭绝]
// it
// 1、得到当前集合的迭代器对象。
Iterator it = lists.iterator();
// String ele = it.next();
// System.out.println(ele);
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next()); // NoSuchElementException 出现无此元素异常的错误
// 2、定义while循环
while (it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
}
}
输出结果
[赵敏, 小昭, 素素, 灭绝]
赵敏
小昭
素素
灭绝
注意点
1、迭代器的默认位置在哪里?
2、迭代器如果取元素越界会出现什么问题?
代码演示
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
/**
目标:Collection集合的遍历方式。
什么是遍历? 为什么开发中要遍历?
遍历就是一个一个的把容器中的元素访问一遍。
开发中经常要统计元素的总和,找最值,找出某个数据然后干掉等等业务都需要遍历。
Collection集合的遍历方式是全部集合都可以直接使用的,所以我们学习它。
Collection集合的遍历方式有三种:
(1)迭代器。
(2)foreach(增强for循环)。
(3)JDK 1.8开始之后的新技术Lambda表达式。
b.foreach(增强for循环)遍历集合。
foreach是一种遍历形式,可以遍历集合或者数组。
foreach遍历集合实际上是迭代器遍历集合的简化写法。
foreach遍历的关键是记住格式:
for(被遍历集合或者数组中元素的类型 变量名称 : 被遍历集合或者数组){
}
*/
public class CollectionDemo02 {
public static void main(String[] args) {
Collection lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("殷素素");
lists.add("周芷若");
System.out.println(lists);
// [赵敏, 小昭, 殷素素, 周芷若]
// ele
for (String ele : lists) {
System.out.println(ele);
}
System.out.println("------------------");
double[] scores = {100, 99.5 , 59.5};
for (double score : scores) {
System.out.println(score);
// if(score == 59.5){
// score = 100.0; // 修改无意义,不会影响数组的元素值。
// }
}
System.out.println(Arrays.toString(scores));
}
}
输出结果
[赵敏, 小昭, 殷素素, 周芷若]
赵敏
小昭
殷素素
周芷若
------------------
100.0
99.5
59.5
[100.0, 99.5, 59.5]
增强for可以遍历哪些容器?
既可以遍历集合也可以遍历数组。

简化过程
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
/**
目标:Collection集合的遍历方式。
什么是遍历? 为什么开发中要遍历?
遍历就是一个一个的把容器中的元素访问一遍。
开发中经常要统计元素的总和,找最值,找出某个数据然后干掉等等业务都需要遍历。
Collection集合的遍历方式是全部集合都可以直接使用的,所以我们学习它。
Collection集合的遍历方式有三种:
(1)迭代器。
(2)foreach(增强for循环)。
(3)JDK 1.8开始之后的新技术Lambda表达式。
c.JDK 1.8开始之后的新技术Lambda表达式。
*/
public class CollectionDemo03 {
public static void main(String[] args) {
Collection lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("殷素素");
lists.add("周芷若");
System.out.println(lists);
// [赵敏, 小昭, 殷素素, 周芷若]
// s
lists.forEach(new Consumer() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
// lists.forEach(s -> {
// System.out.println(s);
// });
// lists.forEach(s -> System.out.println(s) );
lists.forEach(System.out::println );
}
}
案例:影片信息在程序中的表示
需求:
分析:
代码演示
Movie类
public class Movie {
private String name;
private double score;
private String actor;
public Movie() {
}
public Movie(String name, double score, String actor) {
this.name = name;
this.score = score;
this.actor = actor;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public String getActor() {
return actor;
}
public void setActor(String actor) {
this.actor = actor;
}
@Override
public String toString() {
return "Movie{" +
"name='" + name + ''' +
", score=" + score +
", actor='" + actor + ''' +
'}';
}
}
测试类
import java.util.ArrayList;
import java.util.Collection;
public class TestDemo {
public static void main(String[] args) {
// 1、定义一个电影类
// 2、定义一个集合对象存储3部电影对象
Collection movies = new ArrayList<>();
movies.add(new Movie("《你好,李焕英》", 9.5, "张小斐,贾玲,沈腾,陈赫"));
movies.add(new Movie("《唐人街探案》", 8.5, "王宝强,刘昊然,美女"));
movies.add(new Movie("《刺杀小说家》",8.6, "雷佳音,杨幂"));
System.out.println(movies);
// 3、遍历集合容器中的每个电影对象
for (Movie movie : movies) {
System.out.println("片名:" + movie.getName());
System.out.println("得分:" + movie.getScore());
System.out.println("主演:" + movie.getActor());
}
}
}
输出结果
[Movie{name='《你好,李焕英》', score=9.5, actor='张小斐,贾玲,沈腾,陈赫'}, Movie{name='《唐人街探案》', score=8.5, actor='王宝强,刘昊然,美女'}, Movie{name='《刺杀小说家》', score=8.6, actor='雷佳音,杨幂'}]
片名:《你好,李焕英》
得分:9.5
主演:张小斐,贾玲,沈腾,陈赫
片名:《唐人街探案》
得分:8.5
主演:王宝强,刘昊然,美女
片名:《刺杀小说家》
得分:8.6
主演:雷佳音,杨幂
内存原理

集合中存储的是元素的什么信息
集合中存储的是元素对象的地址。
数据结构概述



链表加入元素

链表删除元素

链表的种类

二叉树概述

二叉树的特点

二叉查找树对比普通二叉树

二叉树查找树添节点

二叉树查找存在的问题

平衡二叉树

平衡二叉树的要求

平衡二叉树在添加元素后可能导致不平衡
红黑树概述

红黑规则

添加节点

红黑树小结

List系列集合特点
List集合特有方法
List集合因为支持索引,所以多了很多索引操作的独特api,其他Collection的功能List也都继承了。
方法名称
说明
void add(int index,E element)
在此集合中的指定位置插入指定的元素
E remove(int index)
删除指定索引处的元素,返回被删除的元素
E set(int index,E element)
修改指定索引处的元素,返回被修改的元素
E get(int index)
返回指定索引处的元素
List的实现类的底层原理
代码演示
import java.util.ArrayList;
/**
目标:ArrayList集合。
Collection集合的体系
Collection(接口)
/
Set(接口) List(接口)
/ /
HashSet(实现类) TreeSet(实现类) LinkedList(实现类) Vector(线程安全) ArrayList(实现类)
/
LinkedHashSet(实现类)
Collection集合体系的特点:
Set系列集合: 添加的元素,是无序,不重复,无索引的。
-- HashSet:添加的元素,是无序,不重复,无索引的。
-- LinkedHashSet:添加的元素,是有序,不重复,无索引的。
List系列集合:添加的元素,是有序,可重复,有索引的。
-- LinkedList: 添加的元素,是有序,可重复,有索引的。
-- ArrayList: 添加的元素,是有序,可重复,有索引的。
-- Vector 是线程安全的,速度慢,工作中很少使用。
1、List集合继承了Collection集合的全部功能,"同时因为List系列集合有索引",
2、因为List集合多了索引,所以多了很多按照索引操作元素的功能:
3、ArrayList实现类集合底层基于数组存储数据的,查询快,增删慢!
- public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。
- public E get(int index):返回集合中指定位置的元素。
- public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
- public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回更新前的元素值。
小结:
ArrayList集合的底层是基于数组存储数据。查询快,增删慢!(相对的)
*/
public class ListDemo01 {
public static void main(String[] args) {
// 1.创建一个ArrayList集合对象:
// List:有序,可重复,有索引的。
ArrayList list = new ArrayList<>(); // 一行经典代码!
list.add("Java");
list.add("Java");
list.add("HTML");
list.add("HTML");
list.add("MySQL");
list.add("MySQL");
// 2.在某个索引位置插入元素。
list.add(2, "黑马");
System.out.println(list);
// 3.根据索引删除元素,返回被删除元素
System.out.println(list.remove(1));
System.out.println(list);
// 4.根据索引获取元素:public E get(int index):返回集合中指定位置的元素。
System.out.println(list.get(1));
// 5.修改索引位置处的元素: public E set(int index, E element)
System.out.println(list.set(1, "传智教育"));
System.out.println(list);
}
}
输出结果
[Java, Java, 黑马, HTML, HTML, MySQL, MySQL]
Java
[Java, 黑马, HTML, HTML, MySQL, MySQL]
黑马
黑马
[Java, 传智教育, HTML, HTML, MySQL, MySQL]
List集合的遍历方式
代码演示
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
拓展:List系列集合的遍历方式有:4种。
List系列集合多了索引,所以多了一种按照索引遍历集合的for循环。
List遍历方式:
(1)for循环。(独有的,因为List有索引)。
(2)迭代器。
(3)foreach。
(4)JDK 1.8新技术。
*/
public class ListDemo02 {
public static void main(String[] args) {
List lists = new ArrayList<>();
lists.add("java1");
lists.add("java2");
lists.add("java3");
/** (1)for循环。 */
System.out.println("-----------------------");
for (int i = 0; i < lists.size(); i++) {
String ele = lists.get(i);
System.out.println(ele);
}
/** (2)迭代器。 */
System.out.println("-----------------------");
Iterator it = lists.iterator();
while (it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
/** (3)foreach */
System.out.println("-----------------------");
for (String ele : lists) {
System.out.println(ele);
}
/** (4)JDK 1.8开始之后的Lambda表达式 */
System.out.println("-----------------------");
lists.forEach(s -> {
System.out.println(s);
});
}
}
ArrayList集合的底层原理
为何ArrayList查询快、增删元素相对较慢。
因为数组在插入时需要对元素进行迁移
List集合存储的元素要超过容量怎么办?
创建一个新数组,默认为原数组的1.5倍,然后把旧元素迁移过去
底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有API。
LinkedList 集合的特有功能
方法名称
说明
public void addFirst(E e)
在该列表开头插入指定的元素
public void addLast(E e)
将指定的元素追加到此列表的末尾
public E getFirst()
返回此列表中的第一个元素
public E getLast()
返回此列表中的最后一个元素
public E removeFirst()
从此列表中删除并返回第一个元素
public E removeLast()
从此列表中删除并返回最后一个元素
代码演示
import java.util.LinkedList;
/**
目标:LinkedList集合。
Collection集合的体系:
Collection(接口)
/
Set(接口) List(接口)
/ /
HashSet(实现类) LinkedList(实现类) Vector(实现类) ArrayList(实现类)
/
LinkedHashSet(实现类)
Collection集合体系的特点:
Set系列集合: 添加的元素,是无序,不重复,无索引的。
-- HashSet:添加的元素,是无序,不重复,无索引的。
-- LinkedHashSet:添加的元素,是有序,不重复,无索引的。
List系列集合:添加的元素,是有序,可重复,有索引的。
-- LinkedList: 添加的元素,是有序,可重复,有索引的。
-- Vector: 添加的元素,是有序,可重复,有索引的。线程安全(淘汰了)
-- ArrayList: 添加的元素,是有序,可重复,有索引的。
LinkedList也是List的实现类:底层是基于双链表的,增删比较快,查询慢!!
LinkedList是支持双链表,定位前后的元素是非常快的,增删首尾的元素也是最快的
所以LinkedList除了拥有List集合的全部功能还多了很多操作首尾元素的特殊功能:
- 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):将元素推入此列表所表示的堆栈。
小结:
LinkedList是支持双链表,定位前后的元素是非常快的,增删首尾的元素也是最快的。
所以提供了很多操作首尾元素的特殊API可的实以做栈和队列现。
如果查询多而增删少用ArrayList集合。(用的最多的)
如果查询少而增删首尾较多用LinkedList集合。
*/
public class ListDemo03 {
public static void main(String[] args) {
// LinkedList可以完成队列结构,和栈结构 (双链表)
// 1、做一个队列:
LinkedList queue = new LinkedList<>();
// 入队
queue.addLast("1号");
queue.addLast("2号");
queue.addLast("3号");
System.out.println(queue);
// 出队
// System.out.println(queue.getFirst());
System.out.println(queue.removeFirst());
System.out.println(queue.removeFirst());
System.out.println(queue);
// 2、做一个栈
LinkedList stack = new LinkedList<>();
// 入栈 压栈 (push)
stack.push("第1颗子弹");
stack.push("第2颗子弹");
stack.push("第3颗子弹");
stack.push("第4颗子弹");
System.out.println(stack);
// 出栈 弹栈 pop
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack);
}
}
输出结果
[1号, 2号, 3号]
1号
2号
[3号]
[第4颗子弹, 第3颗子弹, 第2颗子弹, 第1颗子弹]
第4颗子弹
第3颗子弹
第2颗子弹
[第1颗子弹]
push 底层调用了 addFirst()

问题引出
当我们从集合中找出某个元素并删除的时候可能出现一种并发修改异常问题。
哪些遍历存在问题?
哪种遍历且删除元素不出问题
代码演示
import java.util.ArrayList;
import java.util.Iterator;
/**
目标:研究集合遍历并删除元素可能出现的:并发修改异常问题。
*/
public class Test {
public static void main(String[] args) {
// 1、准备数据
ArrayList list = new ArrayList<>();
list.add("黑马");
list.add("Java");
list.add("Java");
list.add("赵敏");
list.add("赵敏");
list.add("素素");
System.out.println(list);
// [黑马, Java, Java, 赵敏, 赵敏, 素素]
// it
// 需求:删除全部的Java信息。
// a、迭代器遍历删除
Iterator it = list.iterator();
// while (it.hasNext()){
// String ele = it.next();
// if("Java".equals(ele)){
// // 删除Java
// // list.remove(ele); // 集合删除会出毛病
// it.remove(); // 删除迭代器所在位置的元素值(没毛病)
// }
// }
// System.out.println(list);
// b、foreach遍历删除 (会出现问题,这种无法解决的,foreach不能边遍历边删除,会出bug)
// for (String s : list) {
// if("Java".equals(s)){
// list.remove(s);
// }
// }
// c、lambda表达式(会出现问题,这种无法解决的,Lambda遍历不能边遍历边删除,会出bug)
// list.forEach(s -> {
// if("Java".equals(s)){
// list.remove(s);
// }
// });
// d、for循环(边遍历边删除集合没毛病,但是必须从后面开始遍历删除才不会出现漏掉应该删除的元素)
for (int i = list.size() - 1; i >= 0 ; i--) {
String ele = list.get(i);
if("Java".equals(ele)){
list.remove(ele);
}
}
System.out.println(list);
}
}
泛型概述
泛型的好处
泛型类的概述
案例
模拟ArrayList集合自定义一个集合MyArrayList集合,完成添加和删除功能的泛型设计即可。
代码演示
MyArrayList 类
import java.util.ArrayList;
public class MyArrayList {
private ArrayList lists = new ArrayList();
public void add(E e){
lists.add(e);
}
public void remove(E e){
lists.remove(e);
}
@Override
public String toString() {
return lists.toString();
}
}
测试类
public class Test {
public static void main(String[] args) {
// 需求:模拟ArrayList定义一个MyArrayList ,关注泛型设计
MyArrayList list = new MyArrayList<>();
list.add("Java");
list.add("Java");
list.add("MySQL");
list.remove("MySQL");
System.out.println(list);
MyArrayList list2 = new MyArrayList<>();
list2.add(23);
list2.add(24);
list2.add(25);
list2.remove(25);
System.out.println(list2);
}
}
输出结果
[Java, Java]
[23, 24]
泛型类的原理
把出现泛型变量的地方全部替换成传输的真实数据类型。
泛型方法的概述
案例
给你任何一个类型的数组,都能返回它的内容。也就是实现Arrays.toString(数组)的功能!
代码演示
/**
目标:自定义泛型方法。
什么是泛型方法?
定义了泛型的方法就是泛型方法。
泛型方法的定义格式:
修饰符 <泛型变量> 返回值类型 方法名称(形参列表){
}
注意:方法定义了是什么泛型变量,后面就只能用什么泛型变量。
泛型类的核心思想:是把出现泛型变量的地方全部替换成传输的真实数据类型。
需求:给你任何一个类型的数组,都能返回它的内容。Arrays.toString(数组)的功能!
小结:
泛型方法可以让方法更灵活的接收数据,可以做通用技术!
*/
public class GenericDemo {
public static void main(String[] args) {
String[] names = {"小璐", "蓉容", "小何"};
printArray(names);
Integer[] ages = {10, 20, 30};
printArray(ages);
Integer[] ages2 = getArr(ages);
String[] names2 = getArr(names);
}
public static T[] getArr(T[] arr){
return arr;
}
public static void printArray(T[] arr){
if(arr != null){
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]).append(i == arr.length - 1 ? "" : ", ");
}
sb.append("]");
System.out.println(sb);
}else {
System.out.println(arr);
}
}
}
输出结果
[小璐, 蓉容, 小何]
[10, 20, 30]
泛型方法的原理
把出现泛型变量的地方全部替换成传输的真实数据类型。
泛型接口的概述
案例
教务系统,提供一个接口可约束一定要完成数据(学生,老师)的增删改查操作
代码演示
学生类
public class Student {
}
老师类
public class Teacher {
}
泛型接口
public interface Data {
void add(E e);
void delete(int id);
void update(E e);
E queryById(int id);
}
学生实现类
public class StudentData implements Data{
@Override
public void add(Student student) {
}
@Override
public void delete(int id) {
}
@Override
public void update(Student student) {
}
@Override
public Student queryById(int id) {
return null;
}
}
老师实现类
public class TeacherData implements Data{
@Override
public void add(Teacher teacher) {
}
@Override
public void delete(int id) {
}
@Override
public void update(Teacher teacher) {
}
@Override
public Teacher queryById(int id) {
return null;
}
}
泛型接口的原理
实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作。
通配符:
案例
开发一个极品飞车的游戏,所有的汽车都能一起参与比赛。
代码演示
import java.util.ArrayList;
/**
目标:泛型通配符。?
需求:开发一个极品飞车的游戏,所有的汽车都能一起参与比赛。
注意:
虽然BMW和BENZ都继承了Car
但是ArrayList和ArrayList与ArrayList没有关系的!!
通配符:?
?可以在“使用泛型”的时候代表一切类型。
E T K V 是在定义泛型的时候使用的。
泛型的上下限:
? extends Car : ?必须是Car或者其子类 泛型上限
? super Car :?必须是Car或者其父类 泛型下限
小结:
通配符:?
?可以在“使用泛型”的时候代表一切类型。
*/
public class GenericDemo {
public static void main(String[] args) {
ArrayList bmws = new ArrayList<>();
bmws.add(new BMW());
bmws.add(new BMW());
bmws.add(new BMW());
go(bmws);
ArrayList benzs = new ArrayList<>();
benzs.add(new BENZ());
benzs.add(new BENZ());
benzs.add(new BENZ());
go(benzs);
ArrayList dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
// go(dogs);
}
/**
所有车比赛
*/
public static void go(ArrayList extends Car> cars){
}
}
class Dog{
}
class BENZ extends Car{
}
class BMW extends Car{
}
// 父类
class Car{
}
注意
虽然BMW和BENZ都继承了Car但是ArrayList和ArrayList与ArrayList没有关系的!
泛型的上下限

Set 系列集合特点
Set 集合实现类特点
Set集合的功能上基本上与Collection的API一致。
代码演示
import java.util.HashSet;
import java.util.Set;
public class SetDemo1 {
public static void main(String[] args) {
// 看看Set系列集合的特点: HashSet LinkedHashSet TreeSet
Set sets = new HashSet<>(); // 一行经典代码 无序不重复,无索引
sets.add("MySQL");
sets.add("MySQL");
sets.add("Java");
sets.add("Java");
sets.add("HTML");
sets.add("HTML");
sets.add("SpringBoot");
sets.add("SpringBoot");
System.out.println(sets);
}
}
输出结果
[Java, MySQL, HTML, SpringBoot]
哈希值
是 JDK 根据对象的地址,按照某种规则算出来的int类型的数值。
Object 类的 API
public int hashCode():返回对象的哈希值
对象的哈希值特点
代码演示
public class SetDemo2 {
public static void main(String[] args) {
// 目标:学会获取对象的哈希值,并确认一下
String name = "itheima";
System.out.println(name.hashCode());
System.out.println(name.hashCode());
String name1 = "itheima1";
System.out.println(name1.hashCode());
System.out.println(name1.hashCode());
String name3 = "itheima";
System.out.println(name3.hashCode());
System.out.println(name3.hashCode());
}
}
输出结果
2118746965
2118746965
1256646524
1256646524
2118746965
2118746965
HashSet 元素无序的底层原理
JDK1.7 版本 HashSet 原理解析
1. 底层结构:哈希表(数组、链表的结合体)
创建一个默认长度16的数组,数组名table
根据元素的哈希值跟数组的长度求余计算出应存入的位置(哈希算法)
判断当前位置是否为null,如果是null直接存入
如果位置不为null,表示有元素,则调用equals方法比较
如果一样,则不存,如果不一样,则存入数组
JDK 7新元素占老元素位置,指向老元素
JDK 8中新元素挂在老元素下面
**结论:**哈希表是一种对于增删改查数据性能都较好的结构。
JDK1.8 版本开始 HashSet 原理解析
**结论:**JDK8开始后,哈希表对于红黑树的引入进一步提高了操作数据的性能。
哈希表的详细流程
HashSet 去重复原理解析
**结论:**如果希望Set集合认为2个内容一样的对象是重复的,必须重写对象的hashCode()和equals()方法
案例:Set集合去重复
需求:
分析:
代码演示
学生类
import java.util.Objects;
public class Student {
private String name;
private int age;
private char sex;
public Student() {
}
public Student(String name, int age, char sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
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;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
/**
只要2个对象内容一样,结果一定是true
* @param o
* @return
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && sex == student.sex && Objects.equals(name, student.name);
}
/**
s1 = new Student("无恙", 20, '男')
s2 = new Student("无恙", 20, '男')
s3 = new Student("周雄", 21, '男')
*/
@Override
public int hashCode() {
return Objects.hash(name, age, sex);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", age=" + age +
", sex=" + sex +
'}';
}
}
测试类
import java.util.HashSet;
import java.util.Set;
/**
目标:让Set集合把重复内容的对象去掉一个(去重复)
*/
public class SetDemo3 {
public static void main(String[] args) {
// Set集合去重复原因:先判断哈希值算出来的存储位置是否相同 再判断equals
Set sets = new HashSet<>();
Student s1 = new Student("无恙", 20, '男');
Student s2 = new Student("无恙", 20, '男');
Student s3 = new Student("周雄", 21, '男');
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
sets.add(s1);
sets.add(s2);
sets.add(s3);
System.out.println(sets);
}
}
输出结果
800712763
800712763
680875133
[Student{name='无恙', age=20, sex=男}, Student{name='周雄', age=21, sex=男}]

LinkedHashSet集合概述和特点
代码演示
import java.util.LinkedHashSet;
import java.util.Set;
public class SetDemo1 {
public static void main(String[] args) {
// 看看Set系列集合的特点: HashSet LinkedHashSet TreeSet
// Set sets = new HashSet<>(); // 一行经典代码 无序不重复,无索引
Set sets = new LinkedHashSet<>(); // 有序 不重复 无索引
sets.add("MySQL");
sets.add("MySQL");
sets.add("Java");
sets.add("Java");
sets.add("HTML");
sets.add("HTML");
sets.add("SpringBoot");
sets.add("SpringBoot");
System.out.println(sets);
}
}
输出结果
[MySQL, Java, HTML, SpringBoot]
TreeSet集合概述和特点
TreeSet集合默认的规则
结论:想要使用TreeSet存储自定义类型,需要制定排序规则。
自定义排序规则
TreeSet集合存储对象的的时候有2种方式可以设计自定义比较规则
补充
两种方式中,关于返回值的规则:
如果认为第一个元素大于第二个元素返回正整数即可。
如果认为第一个元素小于第二个元素返回负整数即可。
如果认为第一个元素等于第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两者重复。
注意:如果TreeSet集合存储的对象有实现比较规则,集合也自带比较器,默认使用集合自带的比较器排序。
代码演示
苹果类
public class Apple implements Comparable{
private String name;
private String color;
private double price;
private int weight;
public Apple() {
}
public Apple(String name, String color, double price, int weight) {
this.name = name;
this.color = color;
this.price = price;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + ''' +
", color='" + color + ''' +
", price=" + price +
", weight=" + weight +
'}';
}
/**
方式一:类自定义比较规则
o1.compareTo(o2)
* @param o
* @return
*/
@Override
public int compareTo(Apple o) {
// 按照重量进行比较的
return this.weight - o.weight ; // 去重重量重复的元素
// return this.weight - o.weight >= 0 ? 1 : -1; // 保留重量重复的元素
}
}
测试类
import java.util.Set;
import java.util.TreeSet;
/**
目标:观察TreeSet对于有值特性的数据如何排序。
学会对自定义类型的对象进行指定规则排序
*/
public class SetDemo5 {
public static void main(String[] args) {
Set sets = new TreeSet<>(); // 不重复 无索引 可排序
sets.add(23);
sets.add(24);
sets.add(12);
sets.add(8);
System.out.println(sets);
Set sets1 = new TreeSet<>(); // 不重复 无索引 可排序
sets1.add("Java");
sets1.add("Java");
sets1.add("angela");
sets1.add("黑马");
sets1.add("Java");
sets1.add("About");
sets1.add("Python");
sets1.add("UI");
sets1.add("UI");
System.out.println(sets1);
System.out.println("------------------------------");
// 方式二:集合自带比较器对象进行规则定制
//
// Set apples = new TreeSet<>(new Comparator() {
// @Override
// public int compare(Apple o1, Apple o2) {
// // return o1.getWeight() - o2.getWeight(); // 升序
// // return o2.getWeight() - o1.getWeight(); // 降序
// // 注意:浮点型建议直接使用Double.compare进行比较
// // return Double.compare(o1.getPrice() , o2.getPrice()); // 升序
// return Double.compare(o2.getPrice() , o1.getPrice()); // 降序
// }
// });
Set apples = new TreeSet<>(( o1, o2) -> Double.compare(o2.getPrice() , o1.getPrice()) );
// Set apples = new TreeSet<>();
apples.add(new Apple("红富士", "红色", 9.9, 500));
apples.add(new Apple("青苹果", "绿色", 15.9, 300));
apples.add(new Apple("绿苹果", "青色", 29.9, 400));
apples.add(new Apple("黄苹果", "黄色", 9.8, 500));
System.out.println(apples);
}
}
输出结果
[8, 12, 23, 24]
[About, Java, Python, UI, angela, 黑马]
------------------------------
[Apple{name='绿苹果', color='青色', price=29.9, weight=400}, Apple{name='青苹果', color='绿色', price=15.9, weight=300}, Apple{name='红富士', color='红色', price=9.9, weight=500}, Apple{name='黄苹果', color='黄色', price=9.8, weight=500}]
如果希望元素可以重复,又有索引,索引查询要快?
如果希望元素可以重复,又有索引,增删首尾操作快?
如果希望增删改查都快,但是元素不重复、无序、无索引。
如果希望增删改查都快,但是元素不重复、有序、无索引。
如果要对对象进行排序。
假如需要定义一个方法求和,该方法可以灵活的完成如下需求:
可变参数
可变参数的作用
可变参数的注意事项
代码演示
import java.util.Arrays;
/**
目标:可变参数。
可变参数用在形参中可以接收多个数据。
可变参数的格式:数据类型...参数名称
可变参数的作用:
传输参数非常灵活,方便。
可以不传输参数。
可以传输一个参数。
可以传输多个参数。
可以传输一个数组。
可变参数在方法内部本质上就是一个数组。
可变参数的注意事项:
1.一个形参列表中可变参数只能有一个!!
2.可变参数必须放在形参列表的最后面!!
小结:
记住。
*/
public class MethodDemo {
public static void main(String[] args) {
sum(); // 1、不传参数
sum(10); // 2、可以传输一个参数
sum(10, 20, 30); // 3、可以传输多个参数
sum(new int[]{10, 20, 30, 40, 50}); // 4、可以传输一个数组
}
/**
注意:一个形参列表中只能有一个可变参数,可变参数必须放在形参列表的最后面
* @param nums
*/
public static void sum(int...nums){
// 注意:可变参数在方法内部其实就是一个数组。 nums
System.out.println("元素个数:" + nums.length);
System.out.println("元素内容:" + Arrays.toString(nums));
}
}
输出结果
元素个数:0
元素内容:[]
元素个数:1
元素内容:[10]
元素个数:3
元素内容:[10, 20, 30]
元素个数:5
元素内容:[10, 20, 30, 40, 50]
Collections 集合工具类
Collections 常用的API
方法名称
说明
public static boolean addAll(Collection< super T> c, T… elements)
给集合对象批量添加元素
public static void shuffle(List<> list)
打乱List集合元素的顺序
Collections排序相关API
使用范围:只能对于List集合的排序。
排序方式1:
方法名称
说明
public static void sort(List list)
将集合中元素按照默认规则排序
注意:本方式不可以直接对自定义类型的List集合排序,除非自定义类型实现了比较规则Comparable接口
代码演示
import java.util.*;
/**
目标:Collections工具类的使用。
java.utils.Collections:是集合工具类
Collections并不属于集合,是用来操作集合的工具类。
Collections有几个常用的API:
- public static boolean addAll(Collection super T> c, T... elements)
给集合对象批量添加元素!
- public static void shuffle(List> list) :打乱集合顺序。
- public static void sort(List list):将集合中元素按照默认规则排序。
- public static void sort(List list,Comparator super T> c):将集合中元素按照指定规则排序。
*/
public class CollectionsDemo01 {
public static void main(String[] args) {
List names = new ArrayList<>();
//names.add("楚留香");
//names.add("胡铁花");
//names.add("张无忌");
//names.add("陆小凤");
Collections.addAll(names, "楚留香","胡铁花", "张无忌","陆小凤");
System.out.println(names);
// 2、public static void shuffle(List> list) :打乱集合顺序。
Collections.shuffle(names);
System.out.println(names);
// 3、 public static void sort(List list):将集合中元素按照默认规则排序。 (排值特性的元素)
List list = new ArrayList<>();
Collections.addAll(list, 12, 23, 2, 4);
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}
输出结果
[楚留香, 胡铁花, 张无忌, 陆小凤]
[陆小凤, 胡铁花, 楚留香, 张无忌]
[12, 23, 2, 4]
[2, 4, 12, 23]
排序方式2:
方法名称
说明
public static void sort(List list,Comparator< super T> c)
将集合中元素按照指定规则排序
代码演示
Apple 类
public class Apple implements Comparable{
private String name;
private String color;
private double price;
private int weight;
public Apple() {
}
public Apple(String name, String color, double price, int weight) {
this.name = name;
this.color = color;
this.price = price;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + ''' +
", color='" + color + ''' +
", price=" + price +
", weight=" + weight +
'}';
}
/**
方式一:类自定义比较规则
o1.compareTo(o2)
* @param o
* @return
*/
@Override
public int compareTo(Apple o) {
// 按照重量进行比较的
return this.weight - o.weight ; // List集存储相同大小的元素 会保留!
}
}
实现类
import java.util.*;
/**
目标:引用数据类型的排序。
字符串按照首字符的编号升序排序!
自定义类型的比较方法API:Collections
- public static void sort(List list):
将集合中元素按照默认规则排序。
对于自定义的引用类型的排序人家根本不知道怎么排,直接报错!
- public static void sort(List list,Comparator super T> c):
将集合中元素按照指定规则排序,自带比较器
*/
public class CollectionsDemo02 {
public static void main(String[] args) {
List apples = new ArrayList<>(); // 可以重复!
apples.add(new Apple("红富士", "红色", 9.9, 500));
apples.add(new Apple("青苹果", "绿色", 15.9, 300));
apples.add(new Apple("绿苹果", "青色", 29.9, 400));
apples.add(new Apple("黄苹果", "黄色", 9.8, 500));
// Collections.sort(apples); // 方法一:可以的,Apple类已经重写了比较规则
// System.out.println(apples);
// 方式二:sort方法自带比较器对象
// Collections.sort(apples, new Comparator() {
// @Override
// public int compare(Apple o1, Apple o2) {
// return Double.compare(o1.getPrice() , o2.getPrice()); // 按照价格排序!!
// }
// });
Collections.sort(apples, ( o1, o2) -> Double.compare(o1.getPrice() , o2.getPrice()) );
System.out.println(apples);
}
}
案例:斗地主游戏
需求:
分析:
代码演示
Card 类
public class Card {
private String size;
private String color;
private int index; // 牌的真正大小
public Card(){
}
public Card(String size, String color, int index) {
this.size = size;
this.color = color;
this.index = index;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
@Override
public String toString() {
return size + color;
}
}
实现类
import java.util.*;
/**
目标:斗地主游戏的案例开发。
业务需求分析:
斗地主的做牌, 洗牌, 发牌, 排序(拓展知识), 看牌。
业务: 总共有54张牌。
点数: "3","4","5","6","7","8","9","10","J","Q","K","A","2"
花色: "?", "?", "?", "?"
大小王: "??" , "??"
点数分别要组合4种花色,大小王各一张。
斗地主:发出51张牌,剩下3张作为底牌。
功能:
1.做牌。
2.洗牌。
3.定义3个玩家
4.发牌。
5.排序(拓展,了解,作业)
6.看牌
*/
public class GameDemo {
/**
1、定义一个静态的集合存储54张牌对象
*/
public static List allCards = new ArrayList<>();
/**
2、做牌:定义静态代码块初始化牌数据
*/
static {
// 3、定义点数:个数确定,类型确定,使用数组
String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
// 4、定义花色:个数确定,类型确定,使用数组
String[] colors = {"?", "?", "?", "?"};
// 5、组合点数和花色
int index = 0; // 记录牌的大小
for (String size : sizes) {
index++;
for (String color : colors) {
// 6、封装成一个牌对象。
Card c = new Card(size, color, index);
// 7、存入到集合容器中去
allCards.add(c);
}
}
// 8 大小王存入到集合对象中去 "??" , "??"
Card c1 = new Card("" , "??", ++index);
Card c2 = new Card("" , "??",++index);
Collections.addAll(allCards , c1 , c2);
System.out.println("新牌:" + allCards);
}
public static void main(String[] args) {
// 9、洗牌
Collections.shuffle(allCards);
System.out.println("洗牌后:" + allCards);
// 10、发牌(定义三个玩家,每个玩家的牌也是一个集合容器)
List linhuchong = new ArrayList<>();
List jiumozhi = new ArrayList<>();
List renyingying = new ArrayList<>();
// 11、开始发牌(从牌集合中发出51张牌给三个玩家,剩余3张作为底牌)
// allCards = [??, A?, 5?, 2?, 2?, Q?, ??, Q? ...
// i 0 1 2 3 4 5 6 7 % 3
for (int i = 0; i < allCards.size() - 3; i++) {
// 先拿到当前牌对象
Card c = allCards.get(i);
if(i % 3 == 0) {
// 请阿冲接牌
linhuchong.add(c);
}else if(i % 3 == 1){
// 请阿鸠
jiumozhi.add(c);
}else if(i % 3 == 2){
// 请盈盈接牌
renyingying.add(c);
}
}
// 12、拿到最后三张底牌(把最后三张牌截取成一个子集合)
List lastThreeCards = allCards.subList(allCards.size() - 3 , allCards.size());
// 13、给玩家的牌排序(从大到小 可以自己先试试怎么实现)
sortCards(linhuchong);
sortCards(jiumozhi);
sortCards(renyingying);
// 14、输出玩家的牌:
System.out.println("啊冲:" + linhuchong);
System.out.println("啊鸠:" + jiumozhi);
System.out.println("盈盈:" + renyingying);
System.out.println("三张底牌:" + lastThreeCards);
}
/**
给牌排序
* @param cards
*/
private static void sortCards(List cards) {
// cards = [J?, A?, 3?, ??, 5?, Q?, 2?
Collections.sort(cards, new Comparator() {
@Override
public int compare(Card o1, Card o2) {
// o1 = J?
// o2 = A?
// 知道牌的大小,才可以指定规则
return o2.getIndex() - o1.getIndex();
}
});
}
}
输出结果
新牌:[3?, 3?, 3?, 3?, 4?, 4?, 4?, 4?, 5?, 5?, 5?, 5?, 6?, 6?, 6?, 6?, 7?, 7?, 7?, 7?, 8?, 8?, 8?, 8?, 9?, 9?, 9?, 9?, 10?, 10?, 10?, 10?, J?, J?, J?, J?, Q?, Q?, Q?, Q?, K?, K?, K?, K?, A?, A?, A?, A?, 2?, 2?, 2?, 2?, ??, ??]
洗牌后:[9?, A?, 4?, J?, 5?, 6?, K?, Q?, 10?, K?, 10?, 10?, 9?, 8?, 9?, 2?, A?, 4?, 5?, A?, 4?, Q?, J?, 3?, 4?, 3?, 7?, 7?, K?, K?, 2?, 8?, Q?, ??, 10?, A?, 2?, 6?, 8?, 7?, 6?, 2?, J?, 3?, Q?, 7?, 5?, 3?, 8?, 9?, 5?, J?, 6?, ??]
啊冲:[??, 2?, 2?, 2?, K?, K?, Q?, J?, J?, 9?, 9?, 8?, 7?, 7?, 7?, 5?, 4?]
啊鸠:[A?, A?, A?, K?, Q?, J?, 10?, 10?, 9?, 8?, 8?, 6?, 6?, 5?, 5?, 3?, 3?]
盈盈:[2?, A?, K?, Q?, Q?, 10?, 10?, 9?, 8?, 7?, 6?, 5?, 4?, 4?, 4?, 3?, 3?]
三张底牌:[J?, 6?, ??]
Map集合概述和使用
Map集合整体格式
Map集合的使用场景之一:购物车系统
分析:
{商品1=2 , 商品2=3 , 商品3 =2 , 商品4=3}

Map集合体系特点
Map集合实现类特点
代码演示
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
目标:认识Map体系的特点:按照键无序,不重复,无索引。值不做要求。
*/
public class MapDemo1 {
public static void main(String[] args) {
// 1、创建一个Map集合对象
// Map maps = new HashMap<>(); // 一行经典代码 {null=null, Java=100, 枸杞=100, 鸿星尔克=3}
Map maps = new LinkedHashMap<>(); // {鸿星尔克=3, Java=100, 枸杞=100, null=null}
maps.put("鸿星尔克", 3);
maps.put("Java", 1);
maps.put("枸杞", 100);
maps.put("Java", 100); // 覆盖前面的数据
maps.put(null, null);
System.out.println(maps);
}
}
Map是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的。
方法名称
说明
V put(K key,V value)
添加元素
V remove(Object key)
根据键删除键值对元素
void clear()
移除所有的键值对元素
boolean containsKey(Object key)
判断集合是否包含指定的键
boolean containsValue(Object value)
判断集合是否包含指定的值
boolean isEmpty()
判断集合是否为空
int size()
集合的长度,也就是集合中键值对的个数
代码演示
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
目标:Map集合的常用API(重点中的重点)
- public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
- public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
- public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
- public Set keySet(): 获取Map集合中所有的键,存储到Set集合中。
- public Set> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。
- public boolean containKey(Object key):判断该集合中是否有此键。
- public boolean containValue(Object value):判断该集合中是否有此值。
*/
public class MapDemo {
public static void main(String[] args) {
// 1.添加元素: 无序,不重复,无索引。
Map maps = new HashMap<>();
maps.put("iphoneX",10);
maps.put("娃娃",20);
maps.put("iphoneX",100);// Map集合后面重复的键对应的元素会覆盖前面重复的整个元素!
maps.put("huawei",100);
maps.put("生活用品",10);
maps.put("手表",10);
// {huawei=100, 手表=10, 生活用品=10, iphoneX=100, 娃娃=20}
System.out.println(maps);
// 2.清空集合
// maps.clear();
// System.out.println(maps);
// 3.判断集合是否为空,为空返回true ,反之!
System.out.println(maps.isEmpty());
// 4.根据键获取对应值:public V get(Object key)
Integer key = maps.get("huawei");
System.out.println(key);
System.out.println(maps.get("生活用品")); // 10
System.out.println(maps.get("生活用品2")); // null
// 5.根据键删除整个元素。(删除键会返回键的值)
System.out.println(maps.remove("iphoneX"));
System.out.println(maps);
// 6.判断是否包含某个键 ,包含返回true ,反之
System.out.println(maps.containsKey("娃娃")); // true
System.out.println(maps.containsKey("娃娃2")); // false
System.out.println(maps.containsKey("iphoneX")); // false
// 7.判断是否包含某个值。
System.out.println(maps.containsValue(100)); //
System.out.println(maps.containsValue(10)); //
System.out.println(maps.containsValue(22)); //
// {huawei=100, 手表=10, 生活用品=10, 娃娃=20}
// 8.获取全部键的集合:public Set keySet()
Set keys = maps.keySet();
System.out.println(keys);
System.out.println("------------------------------");
// 9.获取全部值的集合:Collection values();
Collection values = maps.values();
System.out.println(values);
// 10.集合的大小
System.out.println(maps.size()); // 4
// 11.合并其他Map集合。(拓展)
Map map1 = new HashMap<>();
map1.put("java1", 1);
map1.put("java2", 100);
Map map2 = new HashMap<>();
map2.put("java2", 1);
map2.put("java3", 100);
map1.putAll(map2); // 把集合map2的元素拷贝一份到map1中去
System.out.println(map1);
System.out.println(map2);
}
}
输出结果
{huawei=100, 手表=10, 生活用品=10, iphoneX=100, 娃娃=20}
false
100
10
null
100
{huawei=100, 手表=10, 生活用品=10, 娃娃=20}
true
false
false
true
true
false
[huawei, 手表, 生活用品, 娃娃]
------------------------------
[100, 10, 10, 20]
4
{java3=100, java2=1, java1=1}
{java3=100, java2=1}
键找值涉及到的API
方法名称
说明
Set keySet()
获取所有键的集合
V get(Object key)
根据键获取值
代码演示
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
目标:Map集合的遍历方式一:键找值
Map集合的遍历方式有:3种。
(1)“键找值”的方式遍历:先获取Map集合全部的键,再根据遍历键找值。
(2)“键值对”的方式遍历:难度较大。
(3)JDK 1.8开始之后的新技术:Lambda表达式。(暂时了解)
a.“键找值”的方式遍历Map集合。
1.先获取Map集合的全部键的Set集合。
2.遍历键的Set集合,然后通过键找值。
小结:
代码简单,需要记住!
*/
public class MapDemo01 {
public static void main(String[] args) {
Map maps = new HashMap<>();
// 1.添加元素: 无序,不重复,无索引。
maps.put("娃娃",30);
maps.put("iphoneX",100);
maps.put("huawei",1000);
maps.put("生活用品",10);
maps.put("手表",10);
System.out.println(maps);
// maps = {huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=30}
// 1、键找值:第一步:先拿到集合的全部键。
Set keys = maps.keySet();
// 2、第二步:遍历每个键,根据键提取值
for (String key : keys) {
int value = maps.get(key);
System.out.println(key + "===>" + value);
}
}
}
输出结果
{huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=30}
huawei===>1000
手表===>10
生活用品===>10
iphoneX===>100
娃娃===>30
键值对涉及到的API
方法名称
说明
Set
获取所有键值对对象的集合
K getKey()
获得键
V getValue()
获取值
代码演示
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
目标:Map集合的遍历方式。
Map集合的遍历方式有:3种。
(1)“键找值”的方式遍历:先获取Map集合全部的键,再根据键找值。
(2)“键值对”的方式遍历:难度较大。
(3)JDK 1.8开始之后的新技术:Lambda表达式。
b.“键值对”的方式遍历:
1.把Map集合转换成一个Set集合:Set> entrySet();
2.此时键值对元素的类型就确定了,类型是键值对实体类型:Map.Entry
3.接下来就可以用foreach遍历这个Set集合,类型用Map.Entry
*/
public class MapDemo02 {
public static void main(String[] args) {
Map maps = new HashMap<>();
// 1.添加元素: 无序,不重复,无索引。
maps.put("娃娃",30);
maps.put("iphoneX",100);
maps.put("huawei",1000);
maps.put("生活用品",10);
maps.put("手表",10);
System.out.println(maps);
// maps = {huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=30}
/**
maps = {huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=30}
??
使用foreach遍历map集合.发现Map集合的键值对元素直接是没有类型的。所以不可以直接foreach遍历集合。
??
可以通过调用Map的方法 entrySet把Map集合转换成Set集合形式 maps.entrySet();
??
Set> entries = maps.entrySet();
[(huawei=1000), (手表=10), (生活用品=10), (iphoneX=100), (娃娃=30)]
entry
??
此时可以使用foreach遍历
*/
// 1、把Map集合转换成Set集合
Set> entries = maps.entrySet();
// 2、开始遍历
for(Map.Entry entry : entries){
String key = entry.getKey();
int value = entry.getValue();
System.out.println(key + "====>" + value);
}
}
}
Map结合Lambda遍历的API
方法名称
说明
default void forEach(BiConsumer< super K, super V> action)
结合lambda遍历Map集合

代码演示
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
/**
目标:Map集合的遍历方式。
Map集合的遍历方式有:3种。
(1)“键找值”的方式遍历:先获取Map集合全部的键,再根据键找值。
(2)“键值对”的方式遍历:难度较大。
(3)JDK 1.8开始之后的新技术:Lambda表达式。
c.JDK 1.8开始之后的新技术:Lambda表达式。(暂时了解)
*/
public class MapDemo03 {
public static void main(String[] args) {
Map maps = new HashMap<>();
// 1.添加元素: 无序,不重复,无索引。
maps.put("娃娃",30);
maps.put("iphoneX",100);// Map集合后面重复的键对应的元素会覆盖前面重复的整个元素!
maps.put("huawei",1000);
maps.put("生活用品",10);
maps.put("手表",10);
System.out.println(maps);
// maps = {huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=30}
// maps.forEach(new BiConsumer() {
// @Override
// public void accept(String key, Integer value) {
// System.out.println(key + "--->" + value);
// }
// });
maps.forEach((k, v) -> {
System.out.println(k + "--->" + v);
});
}
}
底层原理

统计投票人数
需求:
分析:
代码演示
import java.util.*;
/**
需求:统计投票人数
*/
public class MapTest1 {
public static void main(String[] args) {
// 1、把80个学生选择的数据拿进来。
String[] selects = {"A" , "B", "C", "D"};
StringBuilder sb = new StringBuilder();
Random r = new Random();
for (int i = 0; i < 80; i++) {
sb.append(selects[r.nextInt(selects.length)]);
}
System.out.println(sb);
// 2、定义一个Map集合记录最终统计的结果: A=30 B=20 C=20 D=10 键是景点 值是选择的数量
Map infos = new HashMap<>(); //
// 3、遍历80个学生选择的数据
for (int i = 0; i < sb.length(); i++) {
// 4、提取当前选择景点字符
char ch = sb.charAt(i);
// 5、判断Map集合中是否存在这个键
if(infos.containsKey(ch)){
// 让其值 + 1
infos.put(ch , infos.get(ch) + 1);
}else {
// 说明此景点是第一次被选
infos.put(ch , 1);
}
}
// 4、输出集合
System.out.println(infos);
}
}
输出结果
DCBAACDACAACAABAAADAABDACCCADACABBAADBCACDBCBCACCBCDCDDBDBDAAADCABCAACCDABABBACD
{A=29, B=15, C=21, D=15}

HashMap 的特点
实际上:Set系列集合的底层就是Map实现的,只是Set集合中的元素只要键数据,不要值数据而已。

HashMap 的底层原理
案例:HashMap 集合存储自定义对象并遍历
需求:
思路:
代码演示
学生类
import java.util.Objects;
public class Student {
private String name;
private int age;
private char sex;
public Student() {
}
public Student(String name, int age, char sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
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;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
/**
只要2个对象内容一样,结果一定是true
* @param o
* @return
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && sex == student.sex && Objects.equals(name, student.name);
}
/**
s1 = new Student("无恙", 20, '男')
s2 = new Student("无恙", 20, '男')
s3 = new Student("周雄", 21, '男')
*/
@Override
public int hashCode() {
return Objects.hash(name, age, sex);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", age=" + age +
", sex=" + sex +
'}';
}
}
测试类
import java.util.HashMap;
import java.util.Map;
public class HashMapDemo1 {
public static void main(String[] args) {
// Map集合是根据键去除重复元素
Map maps = new HashMap<>();
Student s1 = new Student("无恙", 20, '男');
Student s2 = new Student("无恙", 20, '男');
Student s3 = new Student("周雄", 21, '男');
maps.put(s1, "北京");
maps.put(s2, "上海");
maps.put(s3, "广州");
System.out.println(maps);
}
}
输出结果
{Student{name='无恙', age=20, sex=男}=上海, Student{name='周雄', age=21, sex=男}=广州}
LinkedHashMap集合概述和特点
代码演示
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapDemo2 {
public static void main(String[] args) {
// 1、创建一个Map集合对象
Map maps = new LinkedHashMap<>();
maps.put("鸿星尔克", 3);
maps.put("Java", 1);
maps.put("枸杞", 100);
maps.put("Java", 100); // 覆盖前面的数据
maps.put(null, null);
System.out.println(maps);
}
}
输出结果
{鸿星尔克=3, Java=100, 枸杞=100, null=null}
TreeMap集合概述和特点
TreeMap集合自定义排序规则
代码演示
Apple 类
public class Apple implements Comparable{
private String name;
private String color;
private double price;
private int weight;
public Apple() {
}
public Apple(String name, String color, double price, int weight) {
this.name = name;
this.color = color;
this.price = price;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + ''' +
", color='" + color + ''' +
", price=" + price +
", weight=" + weight +
'}';
}
/**
方式一:类自定义比较规则
o1.compareTo(o2)
* @param o
* @return
*/
@Override
public int compareTo(Apple o) {
// 按照重量进行比较的
return this.weight - o.weight ; // 去重重量重复的元素
// return this.weight - o.weight >= 0 ? 1 : -1; // 保留重量重复的元素
}
}
测试类
public class TreeMapDemo3 {
public static void main(String[] args) {
Map maps1 = new TreeMap<>();
maps1.put(13 , "王麻子");
maps1.put(1 , "张三");
maps1.put(3 , "县长");
System.out.println(maps1);
// TreeMap集合自带排序。 可排序 不重复(只要大小规则一样就认为重复) 无索引
Map maps2 = new TreeMap<>(new Comparator() {
@Override
public int compare(Apple o1, Apple o2) {
return Double.compare(o2.getPrice() , o1.getPrice()); // 按照价格降序排序!
}
});
maps2.put(new Apple("红富士", "红色", 9.9, 500), "山东" );
maps2.put(new Apple("青苹果", "绿色", 15.9, 300), "广州");
maps2.put(new Apple("绿苹果", "青色", 29.9, 400), "江西");
maps2.put(new Apple("黄苹果", "黄色", 9.8, 500), "湖北");
System.out.println(maps2);
}
}
输出结果
{1=张三, 3=县长, 13=王麻子}
{Apple{name='绿苹果', color='青色', price=29.9, weight=400}=江西, Apple{name='青苹果', color='绿色', price=15.9, weight=300}=广州, Apple{name='红富士', color='红色', price=9.9, weight=500}=山东, Apple{name='黄苹果', color='黄色', price=9.8, weight=500}=湖北}
Map集合实现类特点
Map集合案例-统计投票人数
需求:
分析:
代码演示
import java.util.*;
/**
需求:统计投票人数
*/
public class MapTest4 {
public static void main(String[] args) {
// 1、要求程序记录每个学生选择的情况。
// 使用一个Map集合存储。
Map> data = new HashMap<>();
// 2、把学生选择的数据存入进去。
List selects = new ArrayList<>();
Collections.addAll(selects, "A", "C");
data.put("罗勇", selects);
List selects1 = new ArrayList<>();
Collections.addAll(selects1, "B", "C" , "D");
data.put("胡涛", selects1);
List selects2 = new ArrayList<>();
Collections.addAll(selects2 , "A", "B", "C" , "D");
data.put("刘军", selects2);
System.out.println(data);
// 3、统计每个景点选择的人数。
Map infos = new HashMap<>(); // {}
// 4、提取所有人选择的景点的信息。
Collection> values = data.values();
System.out.println(values);
// values = [[A, B, C, D], [B, C, D], [A, C]]
// value
for (List value : values) {
for (String s : value) {
// 有没有包含这个景点
if(infos.containsKey(s)){
infos.put(s, infos.get(s) + 1);
}else {
infos.put(s , 1);
}
}
}
System.out.println(infos);
}
}
输出结果
{刘军=[A, B, C, D], 胡涛=[B, C, D], 罗勇=[A, C]}
[[A, B, C, D], [B, C, D], [A, C]]
{A=2, B=2, C=3, D=2}
什么是不可变集合?
为什么要创建不可变集合?
如何创建不可变集合?
方法名称
说明
static List of(E…elements)
创建一个具有指定元素的List集合对象
static Set of(E…elements)
创建一个具有指定元素的Set集合对象
static
创建一个具有指定元素的Map集合对象
代码演示
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
目标:不可变集合。
*/
public class CollectionDemo {
public static void main(String[] args) {
// 1、不可变的List集合
List lists = List.of(569.5, 700.5, 523.0, 570.5);
// lists.add(689.0);
// lists.set(2, 698.5);
// System.out.println(lists);
double score = lists.get(1);
System.out.println(score);
// 2、不可变的Set集合
Set names = Set.of("迪丽热巴", "迪丽热九", "马尔扎哈", "卡尔眨巴" );
// names.add("三少爷");
System.out.println(names);
// 3、不可变的Map集合
Map maps = Map.of("huawei",2, "Java开发", 1 , "手表", 1);
// maps.put("衣服", 3);
System.out.println(maps);
}
}
注意:此方法 jdk9 以上才支持

先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦