Java
温馨提示
正在学习整理中...
Java视频教程
Java - 视频教程
Java注解 - 视频教程
JavaWeb - 视频教程
Java框架 springBoot - 视频教程
Maven - 视频教程
CMD
想要在任意路径打开相应的文件 配置环境变量 ( 右击此电脑 ==> 高级系统设置 ==> 环境变量 ==> 系统变量(Path) )
详细教程
// 如何打开cmd
// 步骤一: Win + R
// 步骤二: 输入cmd 回车
// =========== CMD 常见命令如下 ===========
// 1. 盘符名称 + 冒号 盘符切换
// 2. dir 查看当前路径下的内容
// 3. cd 目录 进入单级目录
// 4. cd .. 回退到上一级目录
// 5. cd 目录1/目录2/... 进入多级目录
// 6. cd / 回退到盘符目录
// 7. cls 清屏
// 8. exit 退出命令提示窗口
// =========== CMD 打开QQ 并配置QQ ===========
// 1.0 打开QQ对应的文件夹 eg: E:\Bin\
// 2.0 直接输入 xxxx.exe 回车
// 想要在任意路径打开相应的文件 需要配置环境变量 ( Path )
// 然后在任意目录下 直接输入 xxx.exe 回车JDK
多个JDK切换
需要配置环境变量
jdk8_jdk21为例
存储的位置
// 存储的位置
// jdk8 G:\project\javademo\jdk
// jdk21 G:\project\javademo\jdk21注意事项
- 需要多个版本的时候 最好直接下载 .zip文件就可以啦( 只需修改环境变量 ); 不然会出现下面的错误.
解决运行只出现 jdk1.8
// 步骤一: win + R 输入:cmd 回车
// 步骤二: 在命令窗口输入 where java
C:\Program Files (x86)\Common Files\Oracle\Java\javapath\java.exe
G:\project\javademo\jdk21\bin\java.exe
// 步骤三: 删除 C盘里面的 exe文件
// 即: javaws.exe javaw.exe java.exe 删除这三个文件
C:\Program Files (x86)\Common Files\Oracle\Java\javapathjdk 环境变量配置
// 步骤一: 点击此电脑 空白处右击鼠标 选择属性
// 步骤二: 点击 左侧高级系统设置
// 步骤三: 点击 右下角 环境变量
// 步骤四: 新建 系统变量
// 变量名: JAVA_HOME_21
// 变量值: G:\project\javademo\jdk21
// 配置不同的环境变量 执行不同的jdk
java -versionIDEA配置
创建一个项目
// 单项目配置 和 全局配置 选择运行程序(配置jdk)
// 并不能选择其他版本的jdk
// 所以直接选择新建项目
// 生成器选择 SpringBoot
// jdk 选择最新下载的 jdk21
// 但是 java 版本目前没有 java21
// 将服务器的URL 修改成原始的地址
// https://start.spring.io单项目配置
// 修改上面创建的一个新项目
// 步骤一: 进入项目中 点击文件 再点击设置
// 步骤二: 点击构建,执行,部署 ---> 构建工具 ---> Maven
// 步骤三: 点开Maven --> 运行程序(配置jdk)
// 步骤四: 点击编辑器 --> Java编辑器 --> 选择项目版本全局配置
// 步骤一: 打开IDEA 点击文件 选择关闭项目
// 步骤二: 点击自定义 在选择左下角的所有设置
// 步骤三: 点击构建,执行,部署 ---> 构建工具 ---> Maven
// 步骤四: 点开Maven --> 运行程序(配置jdk)
// 步骤五: 点击编辑器 --> Java编辑器 --> 选择项目版本Java8 没有选项
解决IDEA创建SpringBoot项目没有Java版本8
// 解决方案
// 方式一: 修改服务器 URL
// 原始地址 java版本有 17 21 23
// https://start.spring.io
// 修改后的地址 java版本有 8 11 17 19
// https://start.aliyun.comNotepad
打开工具 ===> 设置 ===> 首选项 ===> 新建( 格式选Windows 语言选Java 编码选ANSI(编译中文) )
Java 基础语法
Java三大分类
- JavaSE
- JavaME
- JavaEE
Java特征
- 面向对象
- 安全性
- 多线程
- 简单易学
- 开源
- 跨平台
- 编程
- 编译
- 运行
注释
// 1.单行注释: // 注释信息
// 快捷键: Ctrl + Q Ctrl + K
// 2.多行注释: /*注释信息*/
// 快捷键: Ctrl + Shift + Q Ctrl + Shift + K
//3.文档注释: /**注释信息*/关键字
全部小写
- class 用于创建一个类
字面量
| 字面量类型 | 说明 | 举例 |
|---|---|---|
| 整数类型( int ) | 不带小数点的数字 | 666, -999 |
| 小数类型( double ) | 带小数点的数据 | 13.12, -52.1 |
| 字符串类型( String ) | 用双引号括起来的内容 | "Hello Word" |
| 字符类型( char ) | 用单引号括起来, 内容只能一个 | 'a' '我' |
| 布尔类型 | 布尔值, 表示真假 | true false |
| 空类型 | 一个特殊的值, 空值 | null |
特殊字符
- '\t' 制表符
在打印的时候,把前面字符串的长度补齐到8,或者8的整数倍。最少补1个空格,最多补8个空格。
- '\r'
- '\n'
// 类名和文件名必须一样
public class HelloWord{
public static void main(String[] args){
System.out.println("hello word 你好世界");
// 整数
System.out.println(999);
System.out.println(-666);
// 小数
System.out.println(12.3);
System.out.println(-22.36);
// 字符串
System.out.println("你好 小冯同学");
// 字符
System.out.println('A');
System.out.println('1');
System.out.println('我');
// 布尔值
System.out.println(true);
System.out.println(false);
// 空值
System.out.println("null");
// '/t' 制表符的基本用法
System.out.println("name" + '\t' + "age");
System.out.println("小冯" + '\t' + "26");
}
}变量
数据类型 变量名 = 数据值;
// 变量的练习
public class Variable {
public static void main(String[] args){
// 定义变量格式
// 数据类型 变量名 = 数据值;
int a = 100;
double b = 99.98;
System.out.println(a);
System.out.println(b);
System.out.println(a+b); // 精度会丢失
a = 66;
System.out.println(a);
System.out.println(a+b); // 精度会丢失
// 一条语句可以定义多个变量
int a1 = 100, a2 = 200, a3 = 300;
System.out.println(a1);
System.out.println(a2);
System.out.println(a3);
}
}变量的注意事项
只能存一个值
int a = 100;
变量名不允许重复定义
一条语句可以定义多个变量
int a=55, b=66, c=500;
变量在使用之前要进行赋值
变量的作用范围
计算机的存储规则
在计算机中,任意数据都是以二进制的形式来存储的
// 计算机三类存储数据
// 1. Text文本{ 数字(二进制) 字母(ASCII码表 在转二进制) 汉字(GB 2312 ) }
// 2. Image 图片
// 3. Sound 声音二进制:
由0和1组成
- 逢二进一
- 借一当二
// 二进制: 0和1组成 代码中以0b开口
// 十进制: 0~9组成 前面不加任何前缀
// 八进制: 0~7组成 代码中以0开头
// 十六进制:0~9和a~f组成 代码中以0x开头进制的转化
任意进制转十进制
公式: 系数*基数的权次幂 相加
十进制转其他进制
除基取余法
数据类型
- 基本数据类型
- 整数 ( byte short int(默认) long(后缀需要加L) )
- 浮点数 ( float(后缀需要加F) double(默认) )
- 字符 char
- 布尔 boolean
- 引用数据类型
标识符
- 命名规则 --- 硬性要求
- 由数字、字母、下划线(_)和美元符($)组成
- 不能以数字开头
- 不能是关键字
- 区分大小写
- 命名规则 --- 软性建议( 见名知意 )
- 小驼峰命名法: 方法 变量 eg: name(一个单词全小写) firstName(多个单词第一个小写其余全部大写)
- 大驼峰命名法: 类名 eg: Student(一个单词首字母大写) GoodStudent(多个单词首字母都要大写
键盘录入
Java帮我们写好一个类叫Scanner,这个类就可以接收键盘输入的数字。 注意点: 只能输入整数
// 步骤一:导包---Scanner这个类在哪
import java.util.Scanner; // 导包必须在类定义的上边
// 步骤二:创建对象-一表示我要开始用Scanner这个类了
Scanner sc = new Scanner(System.in); // 只有 sc 可以变
// 步骤三:接收数据--真正开始干活了
int i = sc.nextInt(); // 只有 i 可变IDEA
IDEA项目结构介绍
- project ( 项目 )
- module ( 模块 )
- package ( 包 )
- class ( 类 )
// 创建项目
// 新建项目 ===> 新建模块 ===> 右击模块选择新建软件包 ===> 右击软件包选择新建Java类快捷键
快速生成类 ( psvm 回车 或者 main回车 )
快速生成输出语句 ( sout 回车 )
public class text { // psvm 回车 自动生成下面的语句 public static void main(String[] args) { // sout 回车 自动生成下面的语句 System.out.println(); } }快速生成变量 list.size().var 回车
运行代码 ( Ctrl+Shift+F10 )
Ctrl + Alt + l 代码格式化
数字.fori ==> 快速生产for循环 eg: 200.fori
ctrl + alt + M 自动抽取方法
alt + insert 或者 alt + fn + insert 或者 插件ptg 快速生成Javabean类
ctrl + P 创建对象查看 参数
ctrl + B 看看源码
ctrl + N 搜索源码 ctrl + F12 快速定位
类的操作
新建类
在包里面右击新建 Java类
删除类
右击 选择删除
修改类名
右击类的文件名 ==> 点击重构 ==> 重命名 Shift+F6
模块的操作
- 新建模块
- 删除模块
- 修改模块
- 导入模块
项目的操作
- 关闭项目
- 新建项目
- 打开项目
- 修改项目
运算符
算术运算符
加 +
减 -
乘 *
除 /
取模 取余 %
// 使用场景 // 1. 判断两个数是否被整除 // 2. 判断当前数是否为偶数数值拆分
// 需求: 键盘录入一个三位数, 将其拆分为个位, 十位, 百位后, 打印在控制台个位: 数值 % 10
十位: 数值 / 10 % 10
百位: 数值 / 100 % 10
千位: 数值 / 1000 % 10
......
// 源代码 package com.zkwy.demo01; // 1.键盘录入 导包 import java.util.Scanner; public class text { // psvm 回车 快速生成 public static void main(String[] args) { // 2.键盘录入 创建对象 Scanner sc = new Scanner(System.in); // 提示语 System.out.println("请输入一个三位数:"); // 3.键盘录入 接受数据 int i = sc.nextInt(); // 打印结果 System.out.println("打印出来的结果如下所示"); System.out.println(i % 10); System.out.println(i / 10 % 10); System.out.println(i / 100 % 10); } }
自增自减运算符
- 自增 ++
- 自减 --
赋值运算符
- =
- +=
- -=
- *=
- /=
- %=
关系运算符( boolean )
- ==
- !=
- >
- >=
- <
- <=
逻辑运算符
- & 逻辑与 两边都为真,结果才是真; && 短路与
- | 逻辑或 两边都为假,结果才为假; || 短路或
- ^ 逻辑异或 相同为flase 不相同为true
- ! 逻辑非 取反
三元运算符
关系表达式 ? 表达式1 : 表达式2;
运算符优先级
数据类型的转换
隐式转换( 自动类型提升 )
取值小的, 转化为取值范围大的
取值范围: byte < short < int < long < float < double
什么时候转换: 数据类型不一样, 需要转化为一样的数据类型才能计算
装换规则1: 取值范围小的, 和取值范围大的运算, 小的会先提升为大的, 在进行计算
转换规则2: byte short char 三种类型的数据在运算的时候, 都会直接先提升为 int, 然后在进行运算
强制转换
取值大的, 转化为取值范围小的
格式: 目标数据类型 变量名 = ( 目标数据类型 ) 被强转的数据;
原码、反码、补码
不太懂
控制语句
顺序结构
从上至下 执行代码
分支结构
if语句
第一种格式
if(关系表达式){ 语句体; } // 只有一句代码 {} 可以省略 if(关系表达式) 语句体;第二种格式
if(关系表达式){ 语句体1; }else{ 语句体2; }第三中格式
if(关系表达式1){ 语句体; }else if(关系表达式2){ 语句体; } ... else{ 语句体; }
switch
switch(表达式){ case 值1: 语句体1; break; case 值2: 语句体2; break; ... default: 语句体n+1; break; }// 键盘输入 判断是工作日 还是休息日 package com.zkwy.demo01; // 1. 导包 import java.util.Scanner; public class text { public static void main(String[] args) { // 需求: 判断键盘输入的是休息日(6-7)还是工作日(1-5) // 2. 创建对象 Scanner sc = new Scanner(System.in); // 3. 接受数据 int week = sc.nextInt(); System.out.println("请输入整数1-7:"); switch(week){ // 穿透性 case 1: case 2: case 3: case 4: case 5: System.out.println("工作日"); break; case 6: case 7: System.out.println("休息日"); break; default: System.out.println("输入的数字有误"); break; } } }
循环结构
for
for( 初始化语句; 条件判断语句; 条件控制语句 ){ 循环体语句; }while
初始化语句; while( 条件判断语句){ 循环体语句; 条件控制语句; }// 判断是否为 回文数 package com.zkwy.demo01; public class text { public static void main(String[] args) { // 需求: 给一个整数x 是回文数打印true 不是回文数打印false // 121是回文数 123不是回文数 // 核心思想: 现将数倒过来; 两个数进行对比 // 初始定义的值 int x = 121; // 临时存储初始值 便于比较 int temp = x; // 倒数的值 int y = 0; while (x != 0) { // 取出个位数的值 int i = x % 10; // 值自取整数 x = x / 10; // 倒数的结果 y = y * 10 + i; } // 三元运算符判断是否为回文数 System.out.println(temp == y ? true : false); } }do....while
初始化语句; do{ 循环体语句; 条件抠控制语句; }while(条件判断语句);
无限循环
for(;;){
System.out.println("学习");
}
// 最常用
while(true){
System.out.println("学习");
}
do{
System.out.println("学习");
}while(true);跳出控制语句
- continue; 跳过本次循环, 继续执行下一次循环
- break; 结束整个循环
数组
就是一个容器
数组的定义与静态初始化
// 数据类型[] 数组名 = new 数组类型[]{元素1, 元素2....};
//eg: int[] array = new int[]{11, 22, 33};
// 简写形式:
// 数据类型[] 数组名 = {元素1, 元素2..};
// eg: int[] array = {11, 12, 13};数组元素访问
// 数组的访问 数组名[索引下标]
int number = arr[索引];
// 获取数组的长度 数组名.length
int length = arr.length;数组遍历
快捷键: 数组名.for变量名
eg: arr.fori
package com.zkwy.demo01;
public class text {
public static void main(String[] args) {
// 数组数据
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
// 循环遍历
// 快捷键 arr.fori 回车
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}数组动态初始化
// 数据类型[] 数组名 = new 数据类型[数组长度];
//eg: int[] array = new int[3];数组的常见操作
求最值
package com.zkwy.demo01; public class text { public static void main(String[] args) { // 求最值 35 5 22 44 55 // 定义数据 int[] arr = {35,5,22,55,44,1,0,99}; // 定义初始值 int max = arr[0]; int min = arr[0]; for (int i = 0; i < arr.length; i++) { if(arr[i] > max) { max = arr[i]; } if(arr[i] < min){ min = arr[i]; } } System.out.println("最大值: " + max); System.out.println("最小值: " + min); } }求和并统计个数
// 随机生成10个1---100 之间的随机数存入数组 // 求所有数据的和 // 求所有数据的平均数 // 统计有多少个数据比平均数小交换数据
// 交换前 1,2,3,4,5 // 交换后 5,4,3,2,1 // 思路: 需要中间变量 temp for(i = 0 , j = arr.length ; i < j ; i++ , j--){ }打乱数据
方法
定义方法三部曲
// 1.我要干嘛
// 2.我干这件事情需要什么才能完成?
// 3.我干完了是否要把结果返回给调用处
// 如果调用处需要继续使用,那么必须返回
// 如果调用处不需要继续使用,那么可以返回也可以不返回什么是方法
// 1.什么是方法?
// 方法是程序中最小的执行单元
// 2.实际开发中,什么时候用到方法?
// 重复的代码、具有独立功能的代码可以抽取到方法中。
// 3.实际开发中,方法有什么好处?
// 可以提高代码的复用性方法的格式
public static 返回值类型 方法名(参数){
方法体;
return返回值;
}最简单的方法定义
// 最简单的方法定义格式: public static void 方法名(){ 方法体(即打包起来的代码); } // eg: 方法名: 小驼峰 public static voild playGame(){ 七个打印语句; }// 完整源码 package com.zkwy.demo01; public class text { public static void main(String[] args) { // 调用方法 palyGame(); } // 定义一个方法 public static void palyGame(){ // 方法体 System.out.println("我就是一个简单的方法"); } }带参数的方法定义
// 带参数的方法定义格式: // 单个参数 public static void 方法名(数据类型 参数){ 方法体(即打包起来的代码); } // 多个参数 使用逗号隔开 public static void 方法名(数据类型 参数1, 数据类型 参数2...){ 方法体(即打包起来的代码); } // 形参: 方法中定义的参数 // 实参: 方法调用的参数带返回值方法的定义
// 带返回值方法的定义格式: public static 返回值类型 方法名(数据类型 参数){ 方法体; return 返回值; } // 注意点: // 1. 有返回值, 返回值类型不能写void // 2. 没有返回值, 可以写成void
方法的重载
同一个类中, 方法名相同, 参数不同的方法(数量 类型). 与返回值无关.
方法练习
数组的遍历
// 需求: 设计一个方法用于数组遍历,要求遍历的结果是在一行上的。例如:[11,22,33,44,55]数组最大值
// 需求: 设计一个方法求数组的最大值,并将最大值返回判断数据是否存在
// 需求: 定义一个方法判断数组中的某一个数是否存在,将结果返回给调用处复制数组
// 需求: 定义一个方法copyOfRange(int[] arr,int from,int to) // 功能: 将数组arr中从索引lfrom(包含from)开始。 // 到索引to结束(不包含to)的元素复制到新数组中 // 将新数组返回。
案例练习
买飞机票
// 需求:
// 1.机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。
// 2.按照如下规则计算机票价格:旺季(5-10月)头等舱9折,经济舱8.5折,淡季(11月到来年4月)头等舱7折,经济舱6.5折。// 源码: 下面的步骤三可以简化
package com.zkwy.demo01;
import java.util.Scanner;
public class text {
public static void main(String[] args) {
// 需求:
// 1.机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。
// 2.按照如下规则计算机票价格:旺季(5-10月)头等舱9折,经济舱8.5折,淡季(11月到来年4月)头等舱7折,经济舱6.5折。
// 思路: 1.需要使用键盘录入 设机票原价为x 月份为y 舱为z(头等舱为0, 经济舱为1)
// 2.先判断淡季旺季 在判断坐的什么舱
Scanner sc = new Scanner(System.in);
// 步骤一: 键盘录入相关的数据
System.out.println("请输入机票原价:");
int x = sc.nextInt();
System.out.println("请输入购买的月份");
int y = sc.nextInt();
System.out.println("请输入购买的舱坐");
int z = sc.nextInt();
// 步骤二: 判断月份
if (y >= 5 && y < 10) {
// 步骤三: 判断舱坐
if (z == 0) {
x = (int) (x * 0.9);
} else if (z == 1) {
x = (int) (x * 0.85);
} else {
System.out.println("请输入0或者1");
}
} else if ((y >= 1 && y <= 4) || (y >= 11 && y <= 12)) {
// 步骤三: 判断舱坐
if (z == 0) {
x = (int) (x * 0.7);
} else if (z == 1) {
x = (int) (x * 0.65);
} else {
System.out.println("请输入0或者1");
}
} else {
System.out.println("您输入的月份不符合规范");
}
// 输出最终的机票价格
System.out.println("最终的机票价格为: " + x);
}
}// 简化后的代码
package com.zkwy.demo01;
import java.util.Scanner;
public class text {
public static void main(String[] args) {
// 需求:
// 1.机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。
// 2.按照如下规则计算机票价格:旺季(5-10月)头等舱9折,经济舱8.5折,淡季(11月到来年4月)头等舱7折,经济舱6.5折。
// 思路: 1.需要使用键盘录入 设机票原价为x 月份为y 舱为z(头等舱为0, 经济舱为1)
// 2.先判断淡季旺季 在判断坐的什么舱
Scanner sc = new Scanner(System.in);
// 步骤一: 键盘录入相关的数据
System.out.println("请输入机票原价:");
int x = sc.nextInt();
System.out.println("请输入购买的月份");
int y = sc.nextInt();
System.out.println("请输入购买的舱坐");
int z = sc.nextInt();
// 步骤二: 判断月份
if (y >= 5 && y < 10) {
// 步骤三: 判断舱坐
x = getPrice(x, z, 0.9, 0.85);
} else if ((y >= 1 && y <= 4) || (y >= 11 && y <= 12)) {
// 步骤三: 判断舱坐
x = getPrice(x, z, 0.7, 0.65);
} else {
System.out.println("您输入的月份不符合规范");
}
// 输出最终的机票价格
System.out.println("最终的机票价格为: " + x);
}
// 步骤三: 定义方法
// 形参有: 机票原价 舱坐 折扣1 折扣2
public static int getPrice(int x, int z, double v0, double v1) {
// 步骤三: 判断舱坐
if (z == 0) {
x = (int) (x * v0);
} else if (z == 1) {
x = (int) (x * v1);
} else {
System.out.println("请输入0或者1");
}
return x; // 返回最终的机票金额
}
}找质数(素数)
// 1.判断101---200之间有多少个素数,并输出所有素数
// 前提: 需要知道什么事质数
// 质数(素数):指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。// 源码
package com.zkwy.demo01;
public class text {
public static void main(String[] args) {
// 需求: 判断101---200之间有多少个素数,并输出所有素数
// 前提: 需要知道什么是质数(素数)
// 质数(素数):指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
int count = 0;
for (int i = 101; i < 201; i++) {
// 首先 假设j是一个质数
boolean flag = true;
for (int j = 2; j < i; j++) {
if (i % j == 0) {
flag = false;
break;
}
}
// 判断j的值是否为质素
if (flag) {
count++;
System.out.println("当前的数字" + i + "是质数");
}
}
System.out.println("101到200之间一共有" + count + "个质数");
}
}开发验证码
// 需求
// 1. 定义方法实现随机产生一个5位的验证码
// 2. 验证码格式:
// 2-1: 长度为5
// 2-2: 前四位是大写字母或者小写字母
// 2-3: 最后一位是数字// 源码
package com.zkwy.demo01;
import java.util.Random;
public class text {
public static void main(String[] args) {
// 需求: 定义方法实现随机产生一个5位数的随机验证码
// 规则: 1.长度为5; 2.前四位是大写字母或者小写字母; 3.最后一位是数字.
// 定义大小写字母 存在alphabet变量中
char[] alphabet = new char[52];
// ASCII码对照表
for (int i = 0; i < alphabet.length; i++) {
if (i < 26) {
alphabet[i] = (char) (i + 65);
} else {
alphabet[i] = (char) (i + 97 - 26);
}
System.out.print(alphabet[i] + " ");
}
System.out.println();// 对上面的打印进行换行
// 随机数 Randown
Random r = new Random();
// 定义一个字符串 存储最终的验证码
String result = "";
for (int i = 0; i < 4; i++) {
// 获取随机索引
int randomIndex = r.nextInt(alphabet.length);
result += alphabet[randomIndex];
System.out.println("随着的字母是: " + alphabet[randomIndex]);
}
// 生成随机的一个数
int numner = r.nextInt(10);
result += numner;
// 最终的打印结果
System.out.println("最终的验证码: " + result);
}
}// 使用方法定义随机验证码
// 将上面的代码封装在一个方法里面
// 如下所示:
package com.zkwy.demo01;
import java.util.Random;
public class text {
public static void main(String[] args) {
// 需求: 定义方法实现随机产生一个5位数的随机验证码
// 规则: 1.长度为5; 2.前四位是大写字母或者小写字母; 3.最后一位是数字.
// 随机验证码1
String result1 = getCode();
// 随机验证码2
String result2 = getCode();
// 打印
System.out.println("随机验证码1为: " + result1 );
System.out.println("随机验证码2为: " + result2 );
}
// 定义随机获取验证码
public static String getCode(){
// 定义大小写字母 存在alphabet变量中
char[] alphabet = new char[52];
// ASCII码对照表
for (int i = 0; i < alphabet.length; i++) {
if (i < 26) {
alphabet[i] = (char) (i + 65);
} else {
alphabet[i] = (char) (i + 97 - 26);
}
}
// 随机数 Randown
Random r = new Random();
// 定义一个字符串 存储最终的验证码
String result = "";
for (int i = 0; i < 4; i++) {
// 获取随机索引
int randomIndex = r.nextInt(alphabet.length);
result += alphabet[randomIndex];
}
// 生成随机的一个数
int numner = r.nextInt(10);
result += numner;
return result;
}
}数组元素的复制
// 需求: 把一个数组中的元素复制到另一个新数组中去。// 源码
package com.zkwy.demo01;
public class text {
public static void main(String[] args) {
// 需求: 数组元素的复制
// 原始数组 静态初始化
int[] arr = {1,2,3,4,5,6,7,8,9};
// 新数组 动态初始化
int[] newArr = new int[arr.length];
// 循环遍历原始数组
for (int i = 0; i < arr.length; i++) {
newArr[i] = arr[i];
}
// 循环遍历新数组
for (int i = 0; i < arr.length; i++) {
System.out.print(newArr[i] + " ");
}
}
}评委打分
// 需求: 在唱歌比赛中,有6名评委给选手打分,分数范围是[0-100]之间的整数。选手的最后得分为:去掉最高分、最低分后的4个评委的平均分,完成上述过程并计算出选手的得分。// 源码数字加密
// 数字加密需求:
// 1. 某系统的数字密码(大于0),比如1983,采用加密方式进行传输。
// 2. 规则如下:
// 先得到每位数,然后每位数都加上5,再对10求余,最后将所有数字反转,得到一串新数。
// 加密后是 8346// 源码数字解密
// 数字解密需求
// 1. 将上面的数据 8346 进行解密抽奖的两种实现方式
// 需求: 一个大V直播抽奖,奖品是现金红包,分别有{2,588,888,1000,10000}五个奖金。请使用代码模拟抽奖,打印出每个奖项,奖项的出现顺序要随机且不重复。打印效果如下:(随机顺序,不一定是下面的顺序)
// 888元的奖金被抽出
// 588元的奖金被抽出
// 10000元的奖金被抽出
// 1000元的奖金被抽出
// 2元的奖金被抽出// 源码双色球彩票系统
// 需求
// 投注号码由6个红色球号码和1个蓝色球号码组成。红色球号码从1一33中选择;蓝色球号码从1一16中选择二维数组
静态初始化
// 格式: 数据类型[][] 数组名 = new 数据类型[][]{ {元素1,元素2},{元素1,元素2} }; // 范例: int[][] arr = int[][]{ {1,2,3}, {4,5,6} }; // 简化格式: 数据类型[][] 数组名 = { {元素1,元素2},{元素1,元素2} }; // 数组的获取 数组名[索引下标][索引下标]动态初始化
// 格式: 数据类型[][] 数组名 = new 数据类型[m][n]; m表示这个二维数组,可以存放多少个一维数组 n表示每一个一维数组,可以存放多少个元素 // 范例 int[][] arr = new int[4][6];
// 需求:
// 某商城每个季度的营业额如下:单位(万元)
// 第一季度:22,66,44
// 第二季度:77,33,88
// 第三季度:25,45,65
// 第四季度:11,66,99
// 要求计算出每个季度的总营业额和全年的总营业额// 源码
package com.zkwy.demo01;
import java.util.Random;
public class text {
public static void main(String[] args) {
// 某商城每个季度的营业额如下:单位(万元)
// 第一季度:22,66,44
// 第二季度:77,33,88
// 第三季度:25,45,65
// 第四季度:11,66,99
// 要求计算出每个季度的总营业额和全年的总营业额
// 1.静态初始化: 数据类型[][] 数据名 = { {},{} }
// 2.动态初始化: 数据类型[][] 数据名 = new 数据类型[m][n]
int[][] yearArr = {
{22,66,44},
{77,33,88},
{25,45,65},
{11,66,99},
};
// 全年的销售额
int yearSum = 0;
for (int i = 0; i < yearArr.length; i++) {
int sum = getSum(yearArr[i]);
yearSum += sum;
System.out.println("第"+i+"个季度的销售额为: " + sum);
}
System.out.println("全年的销售总额为: " + yearSum );
}
// 定义一个方面, 计算每一个季度销售额
public static int getSum(int[] arr){
// 定义一个变量 存储一个季度的销售额
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
}面向对象
设计对象并使用
// 1. 类和对象
// 类: 是对象共同特征的描述;
// 对象: 是真实存在的具体东西.
// 在Java中,必须先设计类,才能获得对象
// 类的名称: 使用大驼峰规则.
// 2.1 如何定义类
public class 类名 {
// 1.成员变量( 属性 ) 名词
// 2.成员方法( 行为 ) 动词
// 3.构造器
// 4.代码块
// 5.内部类
}
// 2.2 如何得到类的对象
类名 对象名 = new 类名();
eg: Phone p = new Phone();
// 3. 如何使用对象
访问属性:对象名.成员变量
访问行为:对象名.方法名(...)
// 定义类的补充注意事项
// 1.用来描述一类事物的类,专业叫做:Javabean类。
// 在Javabean类中,是不写main方法的。
// 2.在以前,编写main方法的类,叫做测试类.
// 我们可以在测试类中创建javabean类的对象并进行赋值调用.- Javabean类
- 测试类
// 1.定义类有哪些建议,有什么需要注意的?
// 类名首字母建议大写、英文、有意义,满足驼峰模式,不能用关键字,满足标志符规定;
// 一个代码文件中可以定义多个类,但是只能一个类是public修饰的,public修饰的类名必须是Java代码的文件名称。
// 2.成员变量的格式是什么样的,有什么特点?
// 成员变量的完整定义格式是:修饰符 数据类型 变量名称 = 初始化值;
// 一般无需指定初始化值。// 练习
// 1.女朋友类
// 编写女朋友类,创建女朋友类的对象
// 给女朋友的属性赋值并调用女朋友类中的方法
// 自己思考,女朋友类中有哪些属性,有哪些行为?封装
面向对象的三大特征:
封装
继承
多态
对象代表什么,就得封装对应的数据,并提供数据对应的行为
// 对象代表什么,就得封装对应的数据,并提供数据对应的行为private关键字
是一个权限修饰符
可以修饰成员(成员变量和成员方法)
被private修饰的成员只能在本类中才能访问
针对private修饰的成员变量,如果需要被其他类使用,提供相应的操作
供“setXxx(参数)”方法,用于给成员变量赋值,方法用public修饰
供“getXxx()”方法,用于获取成员变量的值,方法用public修饰
// Javabean类 源码 package com.zkwy.demo01; public class Phone { // 成员变量(属性) private String brand; private int price; // setXxx方法赋值 public void setBrand(String brand) { this.brand = brand; } public void setPrice(int price) { if (0 < price && price < 30000) { this.price = price; } else { System.out.println("数据非法录入"); } } // getXxx方法获取 public String getBrand() { return this.brand; } public int getPrice() { return this.price; } // 成员方法(行为) public void call() { System.out.println("手机在打电话"); } public void playGame() { System.out.println("手机在打游戏"); } }// 测试类 源码 package com.zkwy.demo01; public class PhoneTest { public static void main(String[] args) { // 创建手机的对象 Phone p = new Phone(); // 给手机赋值 p.setBrand("华为"); p.setPrice(5000); // 获取手机对象的值 System.out.println(p.getBrand()); System.out.println(p.getPrice()); // 调用手机中的方法 p.call(); p.playGame(); } }
this关键字
成员变量
类中方法外的变量
局部变量
方法中的变量
就近原则
System.out.println(age); System.out.println(this.age);this的作用?
// 可以区别成员变量和局部变量this的本质和内存图
构造方法
创造对象的时候,虚拟机会自动调用构造方法,作用是给成员变量进行初始化的。
// 格式
public class Student{
// 构造方法
修饰符 类名(参数){
方法体;
}
}
// 特点:
// 1.方法名与类名相同,大小写也要一致
// 2.没有返回值类型,连void都没有
// 3.没有具体的返回值(不能由retrun带回结果数据)1.构造方法的定义
- 如果没有定义构造方法,系统将给出一个默认的无参数构造方法
- 如果定义了构造方法,系统将不再提供默认的构造方法
2.构造方法的重载
- 带参构造方法,和无参数构造方法,两者方法名相同,但是参数不同,这叫做构造方法的重载
3.推荐的使用方式
- 无论是否使用,都手动书写无参数构造方法,和带全部参数的构造方法
// 总结
// 1.构造方法的作用?
创造对象的时候,由虚拟机自动调用,给成员变量进行初始化的。
// 2.构造方法有几种,各自的作用是什么?
无参数构造方法:初始化的对象时,成员变量的数据均采用默认值。
有参数构造方法:在初始化对象的时候,同时可以为对象进行赋值。
// 3.构造方法有哪些注意事项?
任何类定义出来,默认就自带了无参数构造器,写不写都有。
一旦定义了有参数构造器,无参数构造器就没有了,此时就需要自己写无参数构造器了。
建议在任何时候都手动写上空参和带全部参数的构造方法标准JavaBean
快捷键: alt + insert 或者 alt + fn + insert 或者 插件ptg(推荐) 快速生成Javabean类
1.类名需要见名知意
2.成员变量使用private修饰
3.提供至少两个构造方法
- 无参构造方法
- 带全部参数的构造方法
4.成员方法
- 提供每一个成员变量对应的setXxx()/getXxx()
- 如果还有其他行为,也需要写上
// 1.类名见名知意
// 2.所有的成员变量都需要私有
// 3.构造方法(空参带全部参数的构造)
// 4.get/set对象内存图
基本数据类型
数据值是存储在自己的空间中
- 整数类型
- 浮点数类型
- 布尔类型
- 字符类型
引用数据类型
数据值是存储在其他空间中 自己空间中存储的是地址值,
- 除了上面的其他所有类型
this的内存原理
this的作用:区分局部变量和成员变量
this的本质:代表方法调用者的地址值
综合练习
文字版格斗游戏
// 需求:
// 格斗游戏,每个游戏角色的姓名,血量,都不相同,在选定人物的时候(new对象的时候),这些信息就应该被确定下来。// 源码 JavaBrean类// 源码 测试类API
- Scanner
- Randon
字符串
String
- string是Java定义好的一个类。定义在java.lang包中, 所以使用的时候不需要导包
- java程序中的所有字符串文字. 都被实为此类的对象。
- 符串不可变,它们的值在创建后不能被更改
创建String对象的两种方式
- 直接赋值 String str = "anc";
- 构造函数 String str = new String()
Java的内存模型
StringTable(串池)
Java的常用方法(比较内容)
- boolean equals方法(要比较的字符串) 完全一样结果才是true,否则为false
- boolean equalslgnoreCase(要比较的字符串) 忽略大小写的比较
练习一: 用户登录
// 需求: 已知正确的用户名和密码,请用程序实现模拟用户登录。
// 总共给三次机会,登录之后,给出相应的提示// 源码
package string;
import java.util.Scanner;
public class StringDemo {
public static void main(String[] args) {
// 需求: 已知正确的用户名和密码,请用程序实现模拟用户登录。
// 总共给三次机会,登录之后,给出相应的提示
// 步骤一: 定义已知用户名和密码
String name = "小冯";
String password = "123456";
// 步骤二: 使用键盘录入实现用户名和密码的的输入
// Scanner s = new Scanner(System.in);
// System.out.println("请输入您的用户名");
// String newName = s.next();
// System.out.println("请输入您的密码");
// String newPassword = s.next();
// 步骤三: 输入的次数 循环遍历步骤二
for (int i = 0; i < 3; i++) {
// 步骤二: 使用键盘录入实现用户名和密码的的输入
Scanner s = new Scanner(System.in);
System.out.println("请输入您的用户名");
String newName = s.next();
System.out.println("请输入您的密码");
String newPassword = s.next();
// 步骤四: 判断输入的数据是否正确
if (newName.equals(name) && newPassword.equals(password)) {
System.out.println("登录成功!!!");
break;
} else {
// 判断次数用完锁定账户
if(i == 2){
System.out.println("账户: "+newName+" 已经被锁定, 请联系管理人员");
}else{
System.out.println("您输入的用户名或密码错误, 您还有"+(2-i)+"次机会");
}
}
}
}
}练习二: 遍历字符串并统计个数
// 需求1.: 键盘录入一个字符串,使用程序实现在控制台遍历该字符串// 源码
package string;
import java.util.Scanner;
public class StringDemo {
public static void main(String[] args) {
// 需求: 键盘录入一个字符串,使用程序实现在控制台遍历该字符串
// 步骤一: 键盘录入
Scanner s = new Scanner(System.in);
System.out.println("请输入一个字符串: ");
String str = s.next();
// 步骤二: 循环遍历字符串
for (int i = 0; i < str.length(); i++) {
char result = str.charAt(i);
System.out.println(result);
}
}
}// 需求2: 键盘录入一个字符串,统计该字符串中大写字母字符,小写字母字符,数字字符出现的次数(不考虑其他字符)// 源码
package string;
import java.util.Scanner;
public class StringDemo {
public static void main(String[] args) {
// 需求: 键盘录入一个字符串,统计该字符串中大写字母字符,小写字母字符,数字字符出现的次数(不考虑其他字符)
// 步骤一: 键盘录入
Scanner s = new Scanner(System.in);
System.out.println("请输入一个字符串: ");
String str = s.next();
// 步骤二: 统计 ==> 即次数 定义默认为0
int bigCount = 0;
int smallCount = 0;
int numberCount = 0;
// 步骤三: 循环遍历出对应的字符
for (int i = 0; i < str.length(); i++) {
// 循环遍历 得到对应的字符
char c = str.charAt(i);
// 步骤四: 判断c
if (c >= 'A' && c <= 'Z') {
bigCount++;
} else if (c >= 'a' && c <= 'z') {
smallCount++;
} else if (c >= '0' && c <= '9') {
numberCount++;
}
}
System.out.println("大写字母有: " + bigCount + "个");
System.out.println("小字母有: " + smallCount + "个");
System.out.println("数字有: " + numberCount + "个");
}
}练习三: 字符串的拼接和反转
// 需求1: 定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果。
// eg: 数组为: int[] arr = {1,2,3}
// 执行方法后的输出结果为: [1,2,3]// 源码
package string;
public class StringDemo {
public static void main(String[] args) {
// 需求: 定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,
// 步骤二: 调用方法
int[] arr = {1,2,3,4,5,6};
String result = arrToString(arr);
System.out.println("最终的打印结果: "+result);
}
// 步骤一: 定义一个方法
// 定义方法的三部曲
// 1.我要干嘛 ========= 遍历数组并拼接成一个字符串
// 2.我干这件事情需要什么才能完成? ========= 需要数组
// 3.我干完了是否要把结果返回给调用处
// 如果调用处需要继续使用,那么必须返回 ====== 需要返回
// 如果调用处不需要继续使用,那么可以返回也可以不返回
public static String arrToString(int[] arr) {
if (arr == null) {
return "";
}
if (arr.length == 0) {
return "[]";
}
// 定义返回值
String result = "[";
for (int i = 0; i < arr.length; i++) {
if(i == (arr.length-1)){
result += (arr[i] + "]");
}else{
result += (arr[i] + ",");
}
}
return result;
}
}// 需求2:
// 定义一个方法,实现字符串反转.
// 键盘录入一个字符串,调用该方法后,在控制台输出结果
// 例如,键盘录入abc,输出结果cba// 源码
package string;
public class StringDemo {
public static void main(String[] args) {
// 需求: 定义一个方法,实现字符串反转.键盘录入一个字符串,调用该方法后,在控制台输出结果
String result = reverse("12345");
System.out.println(result);
}
// 步骤一: 定义一个方法
// 定义方法的三部曲:
// 1.我要干嘛? =====> 实现字符串的反转
// 2.我干这件事, 需要什么才能完成? ====> 需要字符串
// 3.是否需要打结果返回调用处? ====> 需要返回
public static String reverse(String arr) {
String result = "";
for (int i = arr.length() - 1; i >= 0; i--) {
char c = arr.charAt(i);
result += c;
}
return result;
}
}练习四: 金额转换
// 需求: 金额转化
// 思路: 1.查表法,将大写的数字定义在一个数组中练习五: 手机号屏蔽 / 身份证号码信息查询 / 游戏骂人敏感词替换
手机号屏蔽 substring( 开始索引 , 结束索引 )
// 需求: 13158583939 替换成131****3939 // 字符串的截取 substring(开始索引, 结束索引);身份证号码信息查询
// 需求: 身份证号码信息查询 // 在控制台打印出: 出生年月和性别 eg:2000年10月21日 女游戏骂人敏感词替换 replace(旧值 , 新值)
// 需求: 游戏骂人敏感词替换
StringBuilder
使用场景:
- 1.字符串的拼接
- 2.字符串的反转
StringBuilder可以看成是一个容器,创建之后里面的内容是可变的
- 作用:提高字符串的操作效率
创建
- StringBuilder sb = new StringBuilder(); 无参
- StringBuilder sb = new StringBuilder("abc"); 有参
常用方法
- 添加: public StringBuilder append(任意类型)
- 反转: public StringBuilder reverse()
- 获取长度: public int length()
- 变回字符串: public String toString()
package string;
public class StringDemo {
public static void main(String[] args) {
// StringBuilder
// 字符串的创建
StringBuilder sb = new StringBuilder();
// 添加
sb.append("123456789");
sb.append("abc");
// 链式编程
sb.append("123").append("abc").append("feng");
System.out.println(sb);
// 反转
sb.reverse();
System.out.println(sb);
System.out.println(sb.length());
// 变回字符串
String st = sb.toString();
System.out.println(st);
}
}练习 - 对称字符串
// 需求: 键盘接受一个字符串,程序判断出该字符串是否是对称字符串,并在控制台打印是或不是
// 对称字符串:123321、111
// 非对称字符串:123123// 需求: 定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果。
// eg: 数组为: int[] arr = {1,2,3}
// 执行方法后的输出结果为: [1,2,3]// 源码:
package string;
public class StringDemo {
public static void main(String[] args) {
// 需求: 定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果。
int[] arr = {1,2,3};
String result = arrToString(arr);
System.out.println(result);
}
// 步骤一: 定义一个方法 时刻想着定义方法的三部曲
public static String arrToString(int[] arr){
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if(i == arr.length -1){
sb.append(arr[i]);
}else{
sb.append(arr[i]).append(", ");
}
}
sb.append("]");
return sb.toString();
}
}StringJoiner
- StringJoiner跟StringBuilder一样,也可以看成是一个容器,创建之后里面的内容是可变的。
- 作用:提高字符串的操作效率,而且代码编写特别简洁,但是目前市场上很少有人用。
- JDK8出现的
创建
- public StringJoiner(间隔符号)
- public StringJoiner(间隔符号, 开始符号,结束符号)
常用方法
- 添加: public StringJoiner add(添加的内容)
- 获取长度: public int length()
- 转化为字符串: public String toString()
// 需求: 定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果。
// eg: 数组为: int[] arr = {1,2,3}
// 执行方法后的输出结果为: [1,2,3]// 源码
package string;
import java.util.StringJoiner;
public class StringDemo {
public static void main(String[] args) {
// 需求: 定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果。
String[] arr = {"aaa","bbb","ccc"};
String result = arrToString(arr);
System.out.println(result);
}
// 步骤一: 定义一个方法 时刻想着定义方法的三部曲
public static String arrToString(String[] arr){
StringJoiner sb = new StringJoiner(", ","[","]");
for (int i = 0; i < arr.length; i++) {
sb.add(arr[i]);
}
return sb.toString();
}
}总结( String StringBuilder StringJoiner)
String
- 表示字符串的类,定义了很多操作字符串的方法
StringBuilder
一个可变的操作字符串的容器。
可以高效的拼接字符串,还可以将容器里面的内容反转
StringJoiner
JDK8出现的一个可变的操作字符串的容器,可以高效,方便的拼接字符串。
在拼接的时候,可以指定间隔符号,开始符号,结束符号。
字符串原理
扩展底层原理1
字符串存储的内存原理
- 直接赋值会复用字符串常量池中的
- new出来不会复用,而是开辟一个新的空间
扩展底层原理2
== 号比较的到底是什么?
- 基本数据类型比较数据值
- 引用数据类型比较地址值
扩展底层原理3
字符串拼接的底层原理
- 如果没有变量参与,都是字符串直接相加,编译之后就是拼接之后的结果,会复用串池中的字符串。
- 如果有变量参与,会创建新的字符串,浪费内存。
扩展底层原理4
StringBuilder提高效率原理图
- 有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存
扩展底层原理5
StringBuilder源码分析
- 默认创建一个长度为16的字节数组
- 添加的内容长度小于16,直接存
- 添加的内容大于16会扩容(原来的容量*2+2)
- 如果扩容之后还不够,以实际长度为准
综合练习
罗马数字的两种写法
/* 需求:
键盘录入一个字符串,
要求1:长度为小于等于9
要求2:只能是数字
将内容变成罗马数字
下面是阿拉伯数字跟罗马数字的对比关系:
I一1、11-2、III-3、IV-4、V-5、VI-6、VIl-7、VIl-8、IX-9
注意点:
罗马数字里面是没有0的
如果键盘录入的数字包含0,可以变成"”(长度为e的字符串)
*/调整字符串的内容并比较
/*
调整字符串
给定两个字符串,A和B
A的旋转操作就是将A最左边的字符移动到最右边
例如,若A='abcde',在移动一次之后结果就是'bcdea'
如果在若干次调整操作之后,A能变成B,那么返回True。
如果不能匹配成功,则返回false
*/后续练习思路分析
// 验证码 打乱顺序
//集合
集合的基本使用
- 可以存储引用数据类型
- 不可以存储基本数据类型 ==> 包装类
创建集合
ArrayList<String> list = new ArrayList<>();ArrayList 成员方法
- boolean add(E e) 添加是否成功
- boolean remove(E e) 删除元素是否成功
- E remove(int index) 删除索引的元素是否成功
- E set(int index,E e) 修改元素
- E get(int index) 获取元素
- int sise() 集合的长度
package string;
import java.util.ArrayList;
public class StringDemo {
public static void main(String[] args) {
// 集合的创建
ArrayList<String> list = new ArrayList<>();
// 添加 add()
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add("eee");
// 删除 remove()
// boolean aaa = list.remove("aaa");
// String aaa1 = list.remove(2);
// 修改 set()
// String result = list.set(1, "小冯");
// 查询 get()
// String result = list.get(2);
//System.out.println(result + "=====" + list);
// 循环遍历打印出对应的数据
for (String s : list) {
System.out.println(s);
}
}
}基本数据类型对应的包装类
| 基本数据类型 | 对应的包装类 |
|---|---|
| byte | Byte |
| short | Short |
| char | Character |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| boolean | Boolean |
集合练习
添加字符串 遍历
// 需求: 定义一个集合,添加字符串,并进行遍历
// 遍历格式参照:[元素1,元素2,元素3]。// 源码:
package string;
import java.util.ArrayList;
public class StringDemo {
public static void main(String[] args) {
// 需求: 定义一个集合,添加字符串,并进行遍历
// 遍历的格式参照: [元素1, 元素2, 元素3]
// 步骤一: 创建集合
ArrayList<String> list = new ArrayList<>();
// 步骤二: 添加元素
list.add("aaa");
list.add("bbb");
list.add("ccc");
// 步骤三: 循环遍历
System.out.print("[");
for (int i = 0; i < list.size(); i++) {
if (i == list.size() - 1){
System.out.print(list.get(i));
}else{
System.out.print(list.get(i) + ", ");
}
}
System.out.println("]");
}
}添加数字 遍历
// 需求: 定义一个集合,添加数字,并进行遍历
// 遍历格式参照:[元素1,元素2,元素3]。
// 添加基本数据类型 需要包装类// 源码:
package string;
import java.util.ArrayList;
public class StringDemo {
public static void main(String[] args) {
// 需求: 定义一个集合,添加数字,并进行遍历
// 遍历的格式参照: [元素1, 元素2, 元素3]
// 步骤一: 创建集合
ArrayList<Integer> list = new ArrayList<>();
// 步骤二: 添加元素
list.add(123);
list.add(789);
list.add(456);
// 步骤三: 循环遍历
System.out.print("[");
for (int i = 0; i < list.size(); i++) {
if (i == list.size() - 1){
System.out.print(list.get(i));
}else{
System.out.print(list.get(i) + ", ");
}
}
System.out.println("]");
}
}添加学生对象 遍历
// 添加学生对象并遍历
// 需求: 定义一个集合,添加一些学生对象,并进行遍历
// 学生类的属性为:姓名,年龄。// 学生对象
package string;
import java.util.ArrayList;
public class StringDemo {
public static void main(String[] args) {
// 需求: 定义一个集合,添加一些学生对象,并进行遍历
// 学生类的属性为:姓名,年龄
// 步骤一: 创建集合
ArrayList<Student> list = new ArrayList<>();
// 步骤二: 创建学生对象
Student s1 = new Student("左林", 26);
Student s2 = new Student("小冯", 30);
Student s3 = new Student("小艾", 20);
// 步骤三: 学生对象添加到集合中
list.add(s1);
list.add(s2);
list.add(s3);
// 步骤三: 循环遍历
for (int i = 0; i < list.size(); i++) {
Student stu = list.get(i);
System.out.println(stu.getName() + " " + stu.getAge());
}
}
}// 添加学生对象并遍历
// 需求: 定义一个集合,添加一些学生对象,并进行遍历
// 学生类的属性为:姓名,年龄。
// 要求: 对象的数据来自键盘录入// 源码:
package string;
import java.util.ArrayList;
import java.util.Scanner;
public class StringDemo {
public static void main(String[] args) {
// 需求: 定义一个集合,添加一些学生对象,并进行遍历
// 学生类的属性为:姓名,年龄
// 步骤一: 创建集合
ArrayList<Student> list = new ArrayList<>();
// 步骤二: 键盘录入数据
Scanner sc =new Scanner(System.in);
// 循环遍历添加3个学生对象
for (int i = 0; i < 3; i++) {
// 创建学生对象
Student s = new Student();
// 键盘录入数据
System.out.println("请输入姓名: ");
String name = sc.next();
System.out.println("请输入年龄: ");
int age = sc.nextInt();
// 录入的数据添加到学生对象里面
s.setName(name);
s.setAge(age);
// 将对象里面的数据添加到集合里面去
list.add(s);
}
// 步骤三: 循环遍历
for (int i = 0; i < list.size(); i++) {
Student stu = list.get(i);
System.out.println(stu.getName() + " " + stu.getAge());
}
}
}查找用户是否存在
// 添加用户对象并判断是否存在
// 需求:
// 1.main方法中定义一个集合,存入三个用户对象,
// 用户属性为:id,username,password
// 2.要求:定义一个方法,根据id查找对应的用户信息
// 如果存在,返回true
// 如果不存在,返回false// 源码:
package string;
import java.util.ArrayList;
public class StringDemo {
public static void main(String[] args) {
// 需求1:main方法中定义一个集合,存入三个用户对象,
// 用户属性为:id,username,password
// 要求2:定义一个方法,根据id查找对应的用户信息
// 如果存在,返回true
// 如果不存在,返回false
// 步骤一: 创建一个集合
ArrayList<Student> list = new ArrayList<>();
// 步骤二: 创建用户对象
Student s1 = new Student("111a", "张三", "123456");
Student s2 = new Student("222a", "李四", "123456");
Student s3 = new Student("333a", "王五", "123456");
Student s4 = new Student("444a", "小冯", "123456");
Student s5 = new Student("555a", "小艾", "123456");
// 步骤三: 将创建的用户对象添加到集合里面
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
list.add(s5);
// 步骤五:调用方法
boolean result1 = getUserInfo("123a", list);
boolean result2 = getUserInfo("111a", list);
boolean result3 = getUserInfo("555a", list);
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
}
// 步骤四: 定义方法 三部曲
public static boolean getUserInfo(String id, ArrayList<Student> list) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getId().equals(id)) {
return true;
}
}
return false;
}
}// 需求:
// 1.main方法中定义一个集合,存入三个用户对象,
// 用户属性为:id,username,password
// 2.要求:定义一个方法,根据id查找对应的用户信息
// 如果存在,返回true 返回索引
// 如果不存在,返回false -1
package string;
import java.util.ArrayList;
public class StringDemo {
public static void main(String[] args) {
// 需求1:main方法中定义一个集合,存入三个用户对象,
// 用户属性为:id,username,password
// 要求2:定义一个方法,根据id查找对应的用户信息
// 如果存在,返回true 返回索引
// 如果不存在,返回false -1
// 步骤一: 创建一个集合
ArrayList<Student> list = new ArrayList<>();
// 步骤二: 创建用户对象
Student s1 = new Student("111a", "张三", "123456");
Student s2 = new Student("222a", "李四", "123456");
Student s3 = new Student("333a", "王五", "123456");
Student s4 = new Student("444a", "小冯", "123456");
Student s5 = new Student("555a", "小艾", "123456");
// 步骤三: 将创建的用户对象添加到集合里面
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
list.add(s5);
// 步骤五:调用方法
boolean result1 = getUserInfo("123a", list);
int result11 = getUserInfo1("123a", list);
boolean result2 = getUserInfo("111a", list);
int result22 = getUserInfo1("111a", list);
boolean result3 = getUserInfo("555a", list);
int result33 = getUserInfo1("555a", list);
System.out.println(result1 + "=====" + result11);
System.out.println(result2 + "=====" + result22);
System.out.println(result3 + "=====" + result33);
}
// 步骤四: 定义方法 三部曲
public static boolean getUserInfo(String id, ArrayList<Student> list) {
return getUserInfo1(id, list) >= 0;
}
public static int getUserInfo1(String id, ArrayList<Student> list) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getId().equals(id)) {
return i;
}
}
return -1;
}
}返回多个数据
// 添加手机对象并返回要求的数据
// 需求:
// 定义Javabean类:Phone
// Phone属性:品牌,价格。
// main方法中定义一个集合,存入三个手机对象
// 分别为:小米,1000。苹果,8000。锤子, 2999
// 定义一个方法,将价格低于3000的手机信息返回// 源码:
package string;
import java.util.ArrayList;
public class PhoneDemo {
public static void main(String[] args) {
// 需求:
// 定义Javabean类:Phone
// Phone属性:品牌,价格。
// main方法中定义一个集合,存入三个手机对象
// 分别为:小米,1000。苹果,8000。锤子, 2999
// 定义一个方法,将价格低于3000的手机信息返回
// 步骤一: 定义一个 Phone 类
// 步骤二: 定义集合
ArrayList<Phone> list = new ArrayList<>();
// 步骤三: 创建对象
Phone p1 = new Phone("小米", 1000);
Phone p2 = new Phone("华为", 8000);
Phone p3 = new Phone("魅族", 2999);
// 步骤四: 将对象存储在集合中
list.add(p1);
list.add(p2);
list.add(p3);
// 步骤六: 调用
ArrayList<Phone> result = getPhoneInfo(list);
// 步骤七: 循环遍历 验证数据是否存在
for (int i = 0; i < result.size(); i++) {
String brand = result.get(i).getBrand();
int price = result.get(i).getPrice();
System.out.println("品牌: " + brand + " 价格: " + price);
}
}
// 步骤五: 定义方法 三部曲
public static ArrayList<Phone> getPhoneInfo(ArrayList<Phone> list) {
// 需要返回多个数据 定义一个集合存储
ArrayList<Phone> result = new ArrayList<>();
// 循环遍历
for (int i = 0; i < list.size(); i++) {
// 获取价格信息
int price = list.get(i).getPrice();
if (price < 3000) {
result.add(list.get(i));
}
}
return result;
}
}学生管理系统
待学习
面向对象进阶
static
static表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量
被static修饰的成员变量,叫做静态变量
- 特点
- 被该类所有对象共享
- 不属于对象,属于类
- 随着类的加载而加载,优先于对象存在
- 调用方式
- 类名调用(推荐)
- 对象名调用
被static修饰的成员方法,叫做静态方法
- 特点
- 多用在测试类和工具类中
- Javabean类中很少会用
- 调用方式
- 类名调用(推荐)
- 对象名调用
static的注意事项
- 静态方法只能访问静态变量和静态方法
- 非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法
- 静态方法中是没有this关键字
总结
- 静态方法中,只能访问静态
- 非静态方法可以访问所有
- 静态方法中没有this关键字
目前学的三个类
- Javabean类: 用来描述一类事物的类。比如,Student,Teacher,Dog,Cat等
- 测试类: 用来检查其他类是否书写正确,带有main方法的类,是程序的入口
- 工具类: 不是用来描述一类事物的,而是帮我们做一些事情的类
// Javabean 基本格式
public class Student{
// 1.类名见名思意 大驼峰命名法
// 2.成员变量私有化 private
// 3.创建构造方法( 空参 带全部参)
// 4.每个成员变量对应的setXxx和getXxx方法
}
// 测试类 基本格式
public class Test{
public static void main(String[] args) {
// 代码块
// 调用Javabean类
// 1.创建对象
Student s = new Student();
// 2.添加数据
// ...
// 调用工具类
StudentUtil.getData();
}
// 定义方法的地方
public static void getData(){}
// 方法的重载: 在同一个类中 方法名相同 参数不同的方法; 与返回值无关
}
// 工具类 基本格式
public class StudentUtil{
// 构造方法私有化
// 目的: 为了不让外界创建对象
private StudentUtil(){}
// 创建静态方法 static
public static void getData(){}
}定义数组工具类
// 定义数组工具类
// 需求: 在实际开发中,经常会遇到一些数组使用的工具类。
// 请按照如下要求编写一个数组的工具类:ArrayUtil
// 1.提供一个工具类方法printArr,用于返回整数数组的内容。
// 返回的字符串格式如:[10,20,50,34,100](只考虑整数数组,且只考虑一维数组)
// 2.提供这样一个工具方法getAerage,用于返回平均分。(只考虑浮点型数组,且只考虑一维数组)
// 3.定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。// ArrayUtil.java 源码 工具类
package util;
public class ArrayUtil {
// 私有化构造方法
// 目的: 为了不让外界创建他的对象
private ArrayUtil(){}
// 需要定义静态的成员方法, 方便调用
public static String printArr(int[] arr){
// StringBuilder 实现字符串的拼接
StringBuilder str = new StringBuilder("[");
for (int i = 0; i < arr.length; i++) {
if(i == arr.length -1){
str.append(arr[i]).append("]");
}else{
str.append(arr[i]).append(", ");
}
}
return str.toString();
}
public static double getAverage(double[] arr){
// 定义一个变量 存储总分
double sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
// 平均分
double result = sum / arr.length;
return result;
}
}// TestDemo.java 源码
package util;
public class TestDemo {
public static void main(String[] args) {
// 测试工具类中的两个方法是否正确
// 定义一个数组
int[] arr = {12,78,99,55,66,33};
String result = ArrayUtil.printArr(arr);
System.out.println(result);
// 定义一个数组
double[] arr1 = {2.3,5.6,4.2,8.6,9.5};
double average = ArrayUtil.getAverage(arr1);
System.out.println(average);
}
}定义学生工具类
// 定义学生工具类
// 需求:定义一个集合,用于存储3个学生对象,
// 学生类的属性为:name、age、gender
// 定义一个工具类,用于获取集合中最大学生的年龄// Javabean类 Student.java
package util;
public class Student {
private String name;
private int age;
private String gender;
public Student() {
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
*
* @return gender
*/
public String getGender() {
return gender;
}
/**
* 设置
*
* @param gender
*/
public void setGender(String gender) {
this.gender = gender;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + ", gender = " + gender + "}";
}
}// 测试类 Test.java
package util;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
// 步骤一: 创建 Javabean 类
// 步骤二: 定义一个集合
ArrayList<Student> list = new ArrayList<>();
// 步骤三: 创建学生对象
Student s1 = new Student("张三", 30, "男");
Student s2 = new Student("李四", 26, "女");
Student s3 = new Student("王五", 56, "男");
// 步骤四: 创建的学生对象 存在集合中
list.add(s1);
list.add(s2);
list.add(s3);
// 步骤五: 调用工具类里面的方法
int maxAgeStudent = StudentUtil.getMaxAgeStudent(list);
System.out.println(maxAgeStudent);
}
}// 工具类 StudentUtil.java
package util;
import java.util.ArrayList;
public class StudentUtil {
// 私有化构造方法
// 目的: 为了不让外界创建他的对象
private StudentUtil() {
}
// 获取集合中最大学的年龄
public static int getMaxAgeStudent(ArrayList<Student> list) {
// 定义一个默认值
int max = list.get(0).getAge();
// 循环遍历集合
for (int i = 1; i < list.size(); i++) {
int temAge = list.get(i).getAge();
if (temAge > max) {
max = temAge;
}
}
return max;
}
}继承
Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起继承关系。
public class Student extends Person{}Student称为子类(派生类),Person称为父类(基类或超类)。
继承的好处
- 可以把多个子类中重复的代码抽取到父类中了,提高代码的复用性
- 子类可以在父类的基础上,增加其他的功能,使子类更强大
什么时候用继承
当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码
继承的特点
Java只支持单继承,
不支持多继承,
但支持多层继承,
Java中所有的类都直接或者间接继承于object类,
继承的练习
// 现在有四种动物:布偶猫、中国狸花猫、哈士奇、泰迪
// 暂时不考虑属性,只要考虑行为。
// 请按照继承的思想特点进行继承体系的设计
// 四种动物分别有以下的行为:
// 布偶猫:吃饭、喝水、抓老鼠
// 中国狸花猫:吃饭、喝水、抓老鼠
// 哈士奇:吃饭、喝水、看家、拆家
// 泰迪:吃饭、喝水、看家、蹭一蹭
// 思维: 使用画图法能继承父类那些方法
- 构造方法 非私有==>不能 private ==>不能
- 成员变量 非私有==>能 private ==>能 但不能使用
- 成员方法 虚方法表==>能 否则 ==>不能
继承成员变量, 成员方法
就近原则 逐级往上面找
- 成员变量, 成员方法
- this.成员变量, this.成员方法
- super.成员变量, super.成员方法
方法的重写
- @Override 重写注解
方法重写的注意事项
- 重写方法的名称、形参列表必须与父类中的一致
- 子类重写父类方法时,访问权限子类必须大于等于父类(暂时了解:空着不写<protected<public)
- 子类重写父类方法时,返回值类型子类必须小于等于父类
- 建议:重写的方法尽量和父类保持一致。
- 只有被添加到虚方法表中的方法才能被重写
//练习
// 利用方法的重写设计继承结构
// 现在有三种动物:哈士奇、沙皮狗、中华田园犬
// 暂时不考虑属性,只要考虑行为。
// 请按照继承的思想特点进行继承体系的设计
// 三种动物分别有以下的行为:
// 哈士奇:吃饭(吃狗粮)、喝水、看家、拆家
// 沙皮狗:吃饭(吃狗粮、吃骨头)、喝水、看家
// 中华田园犬:吃饭(吃剩饭)、喝水、看家
// 思路使用: 画图法继承中的构造方法的访问特点
- 子类不能继承父类的构造方法,但是可以通过super调用
- 子类构造方法的第一行,有一个默认的super();
- 默认先访问父类中无参的构造方法,再执行自己。
- 如果想要方法文父类有参构造,必须手动书写 super(形参1,形参2)
this super 使用总结
- this: 理解为一个变量,表示当前方法调用者的地址值;
- super:代表父类存储空间。
| 关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
|---|---|---|---|
| this | this'.成员变量 | this.成员方法(...) | this(...) 访问本类方法, 即默认值 |
| super | super.成员变量 | super.成员方法(...) | super(...) |
// this(...) 代码解释
public class Student{
String name;
int age;
String school;
public Student(){
// 给学校一个默认值
this(null, 0, "贵州大学");
}
public Student(String name,int age,String school){
this.name = name;
this.age = age;
this.school = school;
}
}// 带有继承结构的标准Javabean类
// 1.经理
// 成员变量:工号,姓名,工资,管理奖金
// 成员方法:工作(管理其他人),吃饭(吃米饭)
// 2.厨师
// 成员变量:工号,姓名,工资
// 成员方法:工作(炒菜),吃饭(吃米饭)
// 难点: 标准Javabean类
// 1.类名见名知意
// 2.所有的成员变量都需要私有
// 3.构造方法(空参带全部参数的构造)
// 4.get/setpackage jicheng;
public class Employee {
private String id;
private String name;
private double salary;
public Employee() {}
public Employee(String id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
/**
* 获取
* @return id
*/
public String getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(String id) {
this.id = id;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return salary
*/
public double getSalary() {
return salary;
}
/**
* 设置
* @param salary
*/
public void setSalary(double salary) {
this.salary = salary;
}
public String toString() {
return "Employee{id = " + id + ", name = " + name + ", salary = " + salary + "}";
}
// 成员方法 工作
public void work(){
System.out.println("员工在工作");
}
// 成员方法 吃饭
public void eat(){
System.out.println("吃米饭");
}
}package jicheng;
public class Manager extends Employee {
private double bonus;
public Manager() {
}
public Manager(String id, String name, double salary, double bonus) {
super(id, name, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
// 成员方法的重写
@Override
public void work(){
System.out.println("我在管理其他人");
}
}package jicheng;
public class Cook extends Employee {
public Cook() {}
public Cook(String id, String name, double salary) {
super(id, name, salary);
}
// 成员方法 重写
@Override
public void work(){
System.out.println("厨师在炒菜");
}
}package jicheng;
public class EmployeeTest {
public static void main(String[] args) {
// 创建经理对象
Manager m = new Manager("zkwy0001" , "小冯" , 15000 , 8000);
System.out.println(m.getId() + " , " + m.getName() + " , " + m.getSalary() + " , " + m.getBonus() );
m.work();
m.eat();
// 创建厨师的对象
Cook c = new Cook();
c.setId("yz001");
c.setName("小艾");
c.setSalary(12000);
System.out.println(c.getId() + " , " + c.getName() + " , " + c.getSalary());
c.work();
c.eat();
}
}包, final, 权限修饰符, 代码块
什么是包
包就是文件夹。用来管理各种不同功能的Java类,方便后期代码维护。
- 包名的规则:公司域名反写+包的作用,需要全部英文小写,见名知意。com.itheima.domain
// 导包的规则
// 1.使用同一个包中的类时,不需要导包
// 2.使用java.lang包中的类时,不需要导包。
// 3.其他情况都需要导包
// 4.如果同时使用两个包中的同名类,需要用全类名。
// eg: 第四点
Student s = new Student("小冯" , 26);
com.zkwy.demo03.Student s2 = new com.zkwy.demo03.Student("小艾" , 24);
// 总结:
// 1.包的作用?
包就是文件夹,用来管理各种不同功能的Java类
// 2.包名书写的规则?
公司域名反写+包的作用,需要全部英文小写,见名知意
// 3.什么是全类名
包名 + 类名
// 4.什么时候需要导包? 什么时候不需要导包?
1.使用同一个包中的类时,不需要导包
2.使用java.lang包中的类时,不需要导包。
3.其他情况都需要导包
4.如果同时使用两个包中的同名类,需要用全类名。final
// final可以修饰 方法 类 变量
// 方法: 表明该方法是最终方法,不能被重写
// 类: 表明该类是最终类,不能被继承
// 变量: 叫做常量,只能被赋值一次 final int a =99;// 1.常量
// 实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。
// 2.常量的命名规范:
// 单个单词:全部大写
// 多个单词:全部大写,单词之间用下划线隔开
// 3.细节:
// final修饰的变量是基本类型:那么变量存储的数据值不能发生改变。
// final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,对象内部的可以改变。权限修饰符
- 权限修饰符:是用来控制一个成员能够被访问的范围的
- 可以修饰成员变量,方法,构造方法,内部类。
修饰符的分类
| 修饰符 | 同一个类中 | 同一个包中的其他类 | 不同包下的子类 | 不同包下的无关类 |
|---|---|---|---|---|
| private | ✔ | |||
| 空着不写 | ✔ | ✔ | ||
| protected | ✔ | ✔ | ✔ | |
| public | ✔ | ✔ | ✔ | ✔ |
代码块
1.局部代码块
public class Test {
public static void main(String[] args) {
// {}里面的代码就是 局部代码块
{}
}
}2.构造代码块
public class Test {
public static void main(String[] args) {
// 成员变量
//...
// {}里面的代码就是 构造代码块
// 将无参 和 全参构造函数 里面的共同的代码
{}
// 无参 全参
}
}3.静态代码块 重点掌握
// 格式:static{}
// 特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
// 使用场景:在类加载的时候,做一些数据初始化的时候使用抽象类
抽象方法 抽象类
// 1.抽象类的作用是什么样的?
// 抽取共性时,无法确定方法体,就把方法定义为抽象的;
// 强制让子类按照某种格式重写;
// 抽象方法所在的类,必须是抽象类。
// 2.抽象类和抽象方法的格式?
// public abstract 返回值类型 方法名(参数列表);
// public abstract class 类名{}
// 3.继承抽象类有哪些要注意?
// 要么重写抽象类中的所有抽象方法(用的比较多)
// 要么是抽象类// 练习题:
// 编写带有抽象类的标准Javabean类
// 青蛙Frog 属性: 名字, 年龄 行为: 吃虫子, 喝水
// 狗Dog 属性: 名字, 年龄 行为: 吃骨头, 喝水
// 山羊Sheep 属性: 名字, 年龄 行为: 吃草, 喝水// Animal.java 源码
package chouxiang;
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void drink(){
System.out.println(this.name+"正在喝水");
}
// 定义一个抽象方法
public abstract void eat();
}// Sheep.java 源码
package chouxiang;
public class Sheep extends Animal{
public Sheep() {
}
public Sheep(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("山羊正在吃草");
}
}// Dog.java 源码
package chouxiang;
public class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("狗正在啃骨头");
}
}// Frog.java 源码
package chouxiang;
public class Frog extends Animal {
public Frog() {
}
public Frog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("青蛙正在吃虫子");
}
}// Test.java 测试类
package chouxiang;
public class Test {
public static void main(String[] args) {
// 需求如下:
// 编写带有抽象类的标准Javabean类
// 青蛙Frog 属性: 名字, 年龄 行为: 吃虫子, 喝水
// 狗Dog 属性: 名字, 年龄 行为: 吃骨头, 喝水
// 山羊Sheep 属性: 名字, 年龄 行为: 吃草, 喝水
// 创建青蛙对象
Frog frog = new Frog("山羊" , 5);
frog.drink();
frog.eat();
// 创建狗对象
Dog dog = new Dog("狗",10);
dog.drink();
dog.eat();
// 创建山羊对象
Sheep sheep = new Sheep("山羊" , 15);
sheep.drink();
sheep.eat();
}
}接口
接口 ---- 就是一种规则
接口的定义与使用
接口用关键字interface来定义
public interface 接口名 {}接口不能实例化
接口和类之间是实现关系,通过implements关键字表示
public class 类名 implements 接口名{}接口的子类(实现类)
- 要么重写接口中的所有抽象方法 (推荐)
- 要么是抽象类
// 注意1:接口和类的实现关系,可以单实现,也可以多实现。
public class 类名 implements 接口名1,接口名2{}
// 注意2:实现类还可以在继承一个类的同时实现多个接口。
public class 类名 extends 父类 implements 接口名1,接口名2{}// 需求如下:
// 编写带有接口和抽象类的标准Javabean类
// 青蛙Frog 属性: 名字, 年龄 行为: 吃虫子, 喝水, 游泳
// 狗Dog 属性: 名字, 年龄 行为: 吃骨头, 喝水, 游泳
// 山羊Sheep 属性: 名字, 年龄 行为: 吃草, 喝水// Animal.java 源码
package jiekou;
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 都需要喝水
public void drink(){
System.out.println(this.name + "正在喝水");
}
// 吃的东西并不一样 将方法抽象
public abstract void eat();
}// Swim.java
package jiekou;
public interface Swim {
// 游泳
public abstract void swim();
}// Dog.java 源码
package jiekou;
public class Dog extends Animal implements Swim{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("狗正在啃骨头");
}
@Override
public void swim() {
System.out.println("狗正在狗刨游泳");
}
}// Frog.java 源码
package jiekou;
public class Frog extends Animal implements Swim{
public Frog() {
}
public Frog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("青蛙正在吃虫子");
}
@Override
public void swim() {
System.out.println("青蛙正在蛙游");
}
}// Sheep.java 源码
package jiekou;
public class Sheep extends Animal{
public Sheep() {
}
public Sheep(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("山羊正在吃草");
}
}// Test.java 测试类 源码
package jiekou;
public class Test {
public static void main(String[] args) {
// 需求如下:
// 编写带有接口和抽象类的标准Javabean类
// 青蛙Frog 属性: 名字, 年龄 行为: 吃虫子, 喝水, 游泳
// 狗Dog 属性: 名字, 年龄 行为: 吃骨头, 喝水, 游泳
// 山羊Sheep 属性: 名字, 年龄 行为: 吃草, 喝水
// 创建青蛙的对象
Frog frog = new Frog("青蛙" , 5);
frog.drink();
frog.eat();
frog.swim();
// 创建狗的对象
Dog dog = new Dog("狗" , 10);
dog.drink();
dog.eat();
dog.swim();
// 创建山羊的对象
Sheep sheep = new Sheep("山羊" , 30);
sheep.drink();
sheep.eat();
}
}接口中成员的特点
- 成员变量
- 只能是常量
- 默认修饰符: public static final ===> eg: int a=10;
- 构造方法 没有
- 成员方法
- 只能是抽象方法
- 默认修饰符: public abstract ===> void swim();
- JDK7以前:接口中只能定义抽象方法
- JDK8的新特性:接口中可以定义有方法体的方法( 默认 静态 )
- JDK9的新特性:接口中可以定义私有方法
接口和类之间的关系
- 类和类的关系
- 继承关系,只能单继承,不能多继承,但是可以多层继承
- 类和接口的关系
- 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
- 接口和接口的关系
- 继承关系,可以单继承,也可以多继承
// 编写带有接口和抽象类的标准Javabean类
我们现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。
为了出国交流,跟乒乓球相关的人员都需要学习英语。
请用所有知识分析,在这个案例中,哪些是具体类,哪些是抽象类,哪些是接口?
// 乒乓球运动员:姓名,年龄,学打乒乓球,说英语
// 篮球运动员:姓名,年龄,学打篮球
// 乒乓球教练:姓名,年龄,教打乒乓球,说英语
// 篮球教练:姓名,年龄,教打篮球JDK8以后接口中的新增方法
默认方法
允许在接口中定义默认方法,需要使用关键字default修饰
作用: 解决接口升级问题
接口中 默认方法 的定义格式:
- 格式: public default 返回值类型 方法名(参数列表)
- eg: public default void show()
接口中默认方法的 **注意事项: **
- 默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字
- public可以省略,default不能省略
- 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
静态方法
- 允许在接口中定义定义静态方法,需要用static修饰
接口中 静态方法 的定义格式:
- 格式: public static回值类型 方法名(参数列表)
- eg: public static void show()
接口中默认方法的 **注意事项: **
- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用 eg: 接口名称.静态变量名称();
- public可以省略,static不能省略
接口的应用
- 接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了
- 一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态,
适配器设计模式
- 设计模式(Designpattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。简单理解: 设计模式就是各种套路
- 配器设计模式:解决接口与接口实现类之间的矛盾问题
// 总结:
// 1.当一个接口中抽象方法过多,但是我只要使用其中一部分的时候,就可以适配器设计模式
// 2.书写步骤:
// 编写中间类xxxAdapter,实现对应的接口
// 对接口中的抽象方法进行空实现
// 让真正的实现类继承中间类,并重写需要用的方法
// 为了避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰多态
没有继承, 就没有多态
// 最初的创建对象
Student s = new Student();
// 使用多态
Person s = new Student();
// 即多态的格式
父类类型 对象名称 = new 子类对象;1.什么是多态?
对象的多种形态
2.多态的前提?
- 有继承/实现关系
- 有父类引用指向子类对象
- 有方法的重写
3.多态的好处?
使用父类型作为参数,可以接收所有子类对象, 体现多态的扩展性与便利。
多态调用成员的特点
- 变量调用:编译看左边,运行也看左边
- 方法调用:编译看左边,运行看右边
多态的优势与弊端
1.多态的优势
- 方法中,使用父类型作为参数,可以接收所有子类对象
2.多态的弊端是什么?
不能使用子类的特有功能
Animal a = new Dog(); // 解决方法 不能乱转化 // 即 类型的转化 看3 4点 Dog a = (dog)d;
3.引用数据类型的类型转换,有几种方式?
- 自动类型转换、强制类型转换
4.强制类型转换能解决什么问题?
- 可以转换成真正的子类类型,从而调用子类独有功能。
- 转换类型与真实对象类型不一致会报错
- 转换的时候用 instanceof 关键字进行判断
// 多态的综合练习
/*
根据需求完成代码:
1.定义狗类
属性:
年龄,颜色
行为:
eat(String something)(something表示吃的东西)
看家lookHome方法(无参数)
2.定义猫类
属性:
年龄,颜色
行为:
eat(String something)方法(something表示吃的东西)
逮老鼠catchMouse方法(无参数)
3.定义Person类//饲养员
属性:
姓名,年龄
行为:
keepPet(Dog dog,String something)方法
功能:喂养宠物狗,something表示喂养的东西
行为:
keepPet(Cat cat,String something)方法
功能:喂养宠物猫,something表示喂养的东西
生成空参有参构造,set和get方法
4.定义测试类(完成以下打印效果):
keepPet(Dog dog,String something)方法打印内容如下:
年龄为30岁的老王养了一只黑颜色的2岁的狗
2岁的黑颜色的狗两只前腿死死的抱住骨头猛吃
keepPet(Cat cat,String something)方法打印内容如下:
年龄为25岁的老李养了一只灰颜色的3岁的猫
3岁的灰颜色的猫着眼睛侧着头吃鱼
5.思考:
1.Dog和Cat都是Animal的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?
2.Dog和Cat虽然都是Animal的子类,但是都有其特有方法,能否想办法在keepPet中调用特有方法?
*/// Animal.java 源码
package duotai;
public class Animal {
// 成员变量
private int age;
private String color;
public Animal() {
}
public Animal(int age, String color) {
this.age = age;
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
// 成员方法
public void eat(String something){
System.out.println("动物在吃 " + something );
}
}// Dog.java 源码
package duotai;
public class Dog extends Animal {
public Dog() {
}
public Dog(int age, String color) {
super(age, color);
}
@Override
public void eat(String something) {
System.out.println(getAge() + "岁的" + getColor() + "的狗两只前腿死死的抱住" + something + "猛吃");
}
// 子类特有的方法
public void lookHome() {
System.out.println("狗在看家");
}
}// Cat.java 源码
package duotai;
public class Cat extends Animal{
public Cat() {
}
public Cat(int age, String color) {
super(age, color);
}
@Override
public void eat(String something) {
System.out.println( getAge()+"岁的"+getColor()+"的猫着眼睛侧着头"+something);
}
// 子类特有的方法
public void catchMouse() {
System.out.println("猫在逮老鼠");
}
}// Person.java 源码
package duotai;
public class Person {
// 成员变量
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 成员方法
// 饲养一只狗
public void keepPet(Dog dog,String something){
System.out.println("年龄为"+this.age+"岁的"+this.name+"养了一只"+dog.getColor()+"的"+dog.getAge()+"岁的狗");
dog.eat(something);
}
// 饲养一只猫 方法的重载
public void keepPet(Cat cat,String something){
System.out.println("年龄为"+this.age+"岁的"+this.name+"养了一只"+cat.getColor()+"的"+cat.getAge()+"岁的猫");
cat.eat(something);
}
// 5.思考:
// 1.Dog和Cat都是Animal的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?
// 2.Dog和Cat虽然都是Animal的子类,但是都有其特有方法,能否想办法在keepPet中调用特有方法?
public void keepPet1(Animal a,String something){
System.out.println("年龄为"+this.age+"岁的"+this.name+"养了一只"+a.getColor()+"的"+a.getAge()+"岁的动物");
a.eat(something);
}
public void keepPet2(Animal a,String something){
if (a instanceof Cat){
Cat cat = (Cat) a;
System.out.println("年龄为"+this.age+"岁的"+this.name+"养了一只"+cat.getColor()+"的"+cat.getAge()+"岁的猫");
cat.eat(something);
} else if (a instanceof Dog) {
Dog dog = (Dog) a;
System.out.println("年龄为"+this.age+"岁的"+this.name+"养了一只"+dog.getColor()+"的"+dog.getAge()+"岁的动物");
dog.eat(something);
}else{
System.out.println("没有动物");
}
}
}// Test.java 源码 测试类
package duotai;
public class Test {
public static void main(String[] args) {
/*
根据需求完成代码:
1.定义狗类
属性:
年龄,颜色
行为:
eat(String something)(something表示吃的东西)
看家lookHome方法(无参数)
2.定义猫类
属性:
年龄,颜色
行为:
eat(String something)方法(something表示吃的东西)
逮老鼠catchMouse方法(无参数)
3.定义Person类//饲养员
属性:
姓名,年龄
行为:
keepPet(Dog dog,String something)方法
功能:喂养宠物狗,something表示喂养的东西
行为:
keepPet(Cat cat,String something)方法
功能:喂养宠物猫,something表示喂养的东西
生成空参有参构造,set和get方法
4.定义测试类(完成以下打印效果):
keepPet(Dog dog,String something)方法打印内容如下:
年龄为30岁的老王养了一只黑颜色的2岁的狗
2岁的黑颜色的狗两只前腿死死的抱住骨头猛吃
keepPet(Cat cat,String something)方法打印内容如下:
年龄为25岁的老李养了一只灰颜色的3岁的猫
3岁的灰颜色的猫着眼睛侧着头吃鱼
5.思考:
1.Dog和Cat都是Animal的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?
2.Dog和Cat虽然都是Animal的子类,但是都有其特有方法,能否想办法在keepPet中调用特有方法?
*/
// 创建Person的对象
Person p1 = new Person("小冯" , 26);
// 需要创建狗的对象
Dog dog = new Dog(3,"黑色");
p1.keepPet(dog , "啃骨头");
Person p2 = new Person("小艾" , 24);
// 需要创建猫的对象
Cat cat = new Cat(2 , "灰色");
p2.keepPet(cat ,"吃鱼");
// 和上面的的结果是一样的
System.out.println("=============");
Person p = new Person("小冯" , 26);
Dog d = new Dog(3 , "黑色");
p.keepPet(d , "啃骨头");
Cat c = new Cat(2,"灰色");
p.keepPet(c , "吃鱼");
System.out.println("=============");
}
}内部类
类的五大成员
- 属性
- 方法
- 构造方法
- 代码块
- 内部类
什么是内部类
在一个类的里面,再定义一个类,
eg: 在A类的内部定义B类,BB类就被称为内部类
public class A{ // ... class B{ // .... } } // 什么时候用到内部类? // B类表示的事物是A类的一部分,且B单独存在没直意义. // eg: 汽车的发动机 ArrayList的迭代器 人的心脏等等
成员内部类
1.什么是成员内部类?
写在成员位置的,属于外部类的成员
2.获取成员内部类对象的两种方式?
- 方式一: 当成员内部类被private修饰时。 在外部类编写方法,对外提供内部类对象
- 方式二: 当成员内部类被非私有修饰时,直接创建对象。 Outer.lnner oi = new Outer().new Inner();
3.外部类成员变量和内部类成员变量重名时,在内部类如何访问?
- System.out.println(outer.this.变量名)
public class Outer{
// 成员内部类
class Inner{}
// 当成员内部类被private修饰时
public Inner getInstance(){
return new Inner();
}
}静态内部类
静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象,
1.什么是静态内部类?
- 静态内部类是一种特殊的成员内部类
2.直接创建静态内部类对象的方式?
- Outer.Inner oi = new Outer.Inner();
3.如何调用静态内部类中的方法?
- 非静态方法: 先创建对象, 用对象调用
- 静态方法: 外部类名.内部类名.方法名();
public class Outer{
// 成员内部类
static class Inner{}
}
// 创建静态内部类对象的格式:
// 外部类名.内部类名 对象名 = new 外部类名.内部类名();
// 调用静态方法的格式:
// 外部类名.内部类名.方法名();局部内部类
- 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量
- 外界是无法直接使用,需要在方法内部创建对象并使用
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量
匿名内部类( 重点学习 )
匿名内部类本质上就是隐藏了名字的内部类。
1.什么 是匿名内部类
- 隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。
2.匿名内部类的格式
// 格式:
new 类名或者接口名(){
重写方法;
}3.格式的细节
- 包含了继承或实现,方法重写,创建对象。
- 整体就是一个类的子类对象或者接口的实现类对象
4.使用场景
- 当方法的参数是接口或者类时,
- 以接口为例,可以传递这个接口的实现类对象
- 如果实现类只要使用一次,就可以用匿名内部类简化代码
// Outer.java
package neibunei;
public abstract class Outer {
public abstract void eat();
}
// Test.java
package neibunei;
public class Test {
public static void main(String[] args) {
// 匿名内部类
// 格式: new 接口或者类名(){};
new Swim(){
@Override
public void swim() {
System.out.println("重写游泳的方法");
}
};
new Outer(){
@Override
public void eat() {
System.out.println("我正在吃饭");
}
};
// 调用Outer的eat的方法
method(
new Outer() {
@Override
public void eat() {
System.out.println("我正在吃饭");
}
}
);
}
public static void method(Outer o){
o.eat();
}
}拼图小游戏
待学习 学习教程
常用的API
Math
- 是一个帮助我们用于进行数学计算的工具类
- 私有化构造方法,所有的方法都是静态的
常见的方法如下:
// abs: 获取绝对值(有范围限制) absExact: 获取绝对值
// ceil: 向上取整 floor: 向下取整 round: 四舍五入
// max: 获取最大值 min: 获取最小值
// pow: 获取a的b次幂 sqrt: 开平方根 cbrt: 开立方根
// random: 获取[0.0 , 10)之间的随机数// 需求: 判断一个数是否为一个质数'
public static boolean isPrime(int number){
for (int i = 2; i <= Math.sqrt(number); i++) {
if(number % i == 0){
return false;
}
}
return true;
}System
- System.exit(); 停止虚拟机
- System.currentTimeMillis(); 获取当前时间的毫秒值
- System.arraycopy(); 拷贝数据
Runtime
Runtime表示当前虚拟机的运行环境
/*
public static Runtime getRuntime() 当前系统的运行环境对象
public void exit(int status) 停止虚拟机
public int availableProcessors() 获得CPU的线程数
public long maxMemory() JVM能从系统中获取总内存大小(单位byte)
public long totalMemory() JVM已经从系统中获取总内存大小(单位byte)
public long freeMemory() JVM剩余内存大小(单位byte)
public Process exec(String command) 运行cmd命令
*/Object和Objects
Object
- Object是Java中的顶级父类。所有的类都直接或间接的继承于Object类。
- Object类中的方法可以被所有子类访问,所以我们要学习Object类和其中的方法。
Object的构造方法
- public Object( ) 空参数
Object的成员方法( 共13个 )
- toString() 返回对象的字符串表达形式
- 如果我们打印一个对象,想要看到属性值的话,那么就重写toString方法就可以了。
- 在重写的方法中,把对象的属性值进行拼接。 插件创建Javabean类 最后一个已经重写了
- equals(Object obj) 比较两个对象是否相等
- 比较的地址 若想比较对象对象里面的属性属性值 需要重写 alt + insert 快速创建
- clone( int a) 对象的克隆 默认是浅克隆
- 如果需要深克隆需要重写方法或者使用第三工具类
Objects
- Objects是一个对象工具类,提供了一些操作对象的方法
- equals(对象1,对象2):先做非空判断,比较两个对象
- isNull(对象):判断对象是否为空
- nonNull(对象):判断对象是否不是空
BigInteger和BigDecimal
BigInteger
在Java中, 整数有四种类型: byte(1个字节), short(2个字节), int(4个字节), long(8个字节).
/*
public BigInteger(int num, Random rnd)获取随机大整数,范围:[e~2的num次方-1]
public BigInteger(String val)获取指定的大整数
public BigInteger(String val, int radix)获取指定进制的大整数
public static BigInteger valueOf(long val)静态方法获取BigInteger的对象,内部有优化
-16===16 的数字进行了优化
细节:
对象一旦创建里面的数据不能发生改变。
*/
- 如果BigInteger表示的数字没有超出long的范围,可以用静态方法获取。
- 如果BigInteger表示的超出long的范围,可以用构造方法获取。
- 对象一旦创建,BigInteger内部记录的值不能发生改变。
- 只要进行计算都会产生一个新的BigInteger对象- Bglnteger表示一个大整数。
- 如何获取BagInteger的对象?
- BigInteger b1 = BigInteger .valueOf(0.1);
- BigInteger b1 = new BigInteger("整数");
- 常见操作 如下所示
public BigInteger add(BigInteger val) 加法
public BigInteger subtract(BigInteger val) 减法
public BigInteger multiply(BigInteger val) 乘法
public BigInteger divide(BigInteger val) 除法,获取商
public BigInteger[] divideAndRemainder(BigInteger val) 除法,获取商和余数
public booleanequals(Object x) 比较是否相同
public BigInteger pwo(int exponent) 次幂
public BigInteger max/min(BigInteger val) 返回较大值/较小值
public int intValue(BigInteger val) 转为int类型整数,超出范围BigDecimal
- 用于小数的精确计算
- 用来表示很大的小数
// 构造方法
BigDecimal bd = new BigDecimal("小数
// 静态方法 [0,10]进行了优化
BigDecimal bd = BigDecimal.valueOf(4.1)// BigDecimal 构造方法创建
BigDecimal bd = new BigDecimal("99.5");
// 静态方法创建
BigDecimal bd1 = BigDecimal.valueOf(99.56);
// 加
BigDecimal bigDecimal = BigDecimal.valueOf(3);
BigDecimal bigDecimal1 = BigDecimal.valueOf(10);
BigDecimal add = bigDecimal.add(bigDecimal1);
System.out.println(add);
// 减
BigDecimal subtract = bigDecimal1.subtract(bigDecimal);
System.out.println(subtract);
// 乘
BigDecimal multiply = bigDecimal.multiply(bigDecimal1);
System.out.println(multiply);
// 除
BigDecimal divide = bigDecimal1.divide(bigDecimal , 2 , RoundingMode.HALF_UP);
System.out.println(divide);正则表达式
安装插件 any-rule
// 需求
// 1.请编写正则表达式验证用户输入的手机号码是否满足要求
// String regex = "1[3-9]\\d{9}" eg:13185859696
// 2.请编写正则表达式验证用户输入的的邮箱号是否满足要求。
// 3.请编写正则表达式验证用户输入的电话号码码是否满足要求。爬虫
本地爬虫
- Pattern:表示正则表达式
- Matcher:文本匹配器,作用按照正则表达式的规则去读取字符串,从头开始读取。在大串中去找符合匹配规则的子串。
// 有如下文本,请按照要求爬取数据。
// Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台
// 要求:找出里面所有的JavaXx// 源码:
package api;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
// 有如下文本,请按照要求爬取数据。
// Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台
// 要求:找出里面所有的JavaXx
// 需要知道的知识点:
// Pattern:表示正则表达式
// Matcher:文本匹配器,作用按照正则表达式的规则去读取字符串,从头开始读取。在大串中去找符合匹配规则的子串。
String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台";
// 1.获取正则表达式对象
Pattern p = Pattern.compile("Java\\d{0,2}");
// 2.获取文本匹配器的对象
// 即拿着m去读取str, 找到符合p规则的子串
Matcher m = p.matcher(str);
// 3.利用循环获取
while (m.find()){
String group = m.group();
System.out.println(group);
}
}
}网络爬虫
//分组
// 1.正则表达式中分组有两种:
// 捕获分组、非捕获分组
// 2.捕获分组(默认):
// 可以获取每组中的内容反复使用。
// 3.组号的特点:
// 从1开始,连续不间断
// 以左括号为基准,最左边的是第一组
// 4.非捕获分组:
// 分组之后不需要再用本组数据,仅仅把数据括起来,不占组号。
// (?:)(?=)(?!)都是非捕获分组JDK7以前时间相关的类
Date
Date类是一个JDk写好的Javabean类,用来描述时间,精确到毫秒。 利用空参构造创建的对象,默认表示系统当前时间。 利用有参构造创建的对象,表示指定的时间。
1.如何创建日期对象?
- Date d = new Date();
- Date d = new Date(指定毫秒值);
2.如何修改时间对象中的毫秒值?
- setTime(毫秒值);
3.如何获取时间对象中的毫秒值
- getTime();
SimpleDateFormat
两个作用:
- 格式化:把时间变成我们喜欢的格式
- 解析:把字符串表示的时间变成Date对象
创建对象
- SimpleDateFormat sdf = new SimpleDateFormat();
- SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
两个方法
- format 格式化
- parse 解析
package api;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDate {
public static void main(String[] args) throws ParseException {
// JDK7 以前的时间对象
// 1.创建一个时间对象
Date d = new Date();
System.out.println(d);
// 2.创建对象表示一个指定的时间
Date d1 = new Date(0L);
System.out.println(d1);
// 3.修改时间
d1.setTime(1000L);
System.out.println(d1);
// 获取当前时间的毫秒值
long time = d1.getTime();
System.out.println(time);
// SimpleDateFormat 默认格式
SimpleDateFormat sdf = new SimpleDateFormat();
String format = sdf.format(d1);
System.out.println(format);
// 带参格式
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String format1 = sdf1.format(d1);
System.out.println(format1);
// 解析: 把字符串表示的时间变成Date对象
String str = "2000-10-21 05:20:00";
// 创建时间对象
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parse = sdf2.parse(str);
System.out.println(parse);
System.out.println(parse.getTime());
Date d2 = new Date(972076800000L);
System.out.println(d2);
SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String format2 = sdf3.format(d2);
System.out.println(format2);
}
}Calendar
- Calendar代表了系统当前时间的日历对象,可以单独修改、获取时间中的年,月,日
- **细节: **Calendar是一个抽象类,不能直接创建对象。
获取Calendar日历类对象的方法
- getInstance() 获取当前时间的日历对象
/*
public static Calendar getInstance()获取当前时间的日历对象
public final Date getTime()获取日期对象
public final setTime(Date date)给日历设置日期对象
public long getTimeInMillis()拿到时间毫秒值
public void setTimeInMillis(long millis)给日历设置时间毫秒值
public int get(int field)取日期中的某个字段信息
public void set(int field,int value)修改日历的某个字段信息
public void add(int field,int amount)为某个字段增加/减少指定的值
*/1.Calendar表示什么?
表示一个时间的日历对象
2.如何获取对象?
通过getlnstance方法获取对象
3.常见方法:
**setXxx: ** 修改
**getXxx: ** 获取
**add: ** 在原有的基础上进行增加或者减少
4.细节点:
日历类中月份的范围:0~11 日历类中星期的特点:星期日是一周中的第一天
**可以通过 查表法 来获取对应的星期 **
JDK8新增时间相关的类
ZoneId
时区
// 1.ZoneId 获取时区
// 获取所有的时区
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
System.out.println(zoneIds);
System.out.println( "时区长度: " + zoneIds.size());
// 获取当前系统的默认时区
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId);
// 获取指定时区
ZoneId zoneId1 = ZoneId.of("Asia/Pontianak");
System.out.println(zoneId1);Instant
时间戳
/*
static Instant now()获取当前时间的Instant对象(标准时间)
static Instant ofXxx(long epochMilli)根据(秒/毫秒/纳秒)获取Instant对象
ZonedDateTime atZone(ZoneId zone)指定时区
boolean isXxx(Instant otherInstant)判断系列的方法
Instant minusXxx(long millisToSubtract)减少时间系列的方法
Instant plusXxx(long millisToSubtract)增加时间系列的方法
*/ZoneDateTime
带时区的时间
DateTimeFormatter
用于时间的格式化和解析
LocalDate
年、月、日
LocalTime
时、分、秒
LocalDateTime
年、月、日、时、分、秒
Duration
时间间隔(秒,纳秒)
Period
时间间隔(年,月,日)
ChronoUnit
时间间隔(所有单位)
包装类
用一个对象, 把基本数据类型包装起来
| 基本数据类型 | 对应的包装类 |
|---|---|
| byte | Byte |
| short | Short |
| char | Character |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| boolean | Boolean |
1.什么是包装类?
- 基本数据类型对应的对象
2.JDK5以后对包装类新增了什么特性?
- 自动装箱、自动拆箱
3.我们以后如何获取包装类对象?
- 不需要new,不需要调用方法,直接赋值即可
// integer成员方法
// 转化为二进制 八进制 十六进制
// 重点: 将字符串的整数转化为int类型的整数
// Integer.parseInt("122")
// 注意点: 8个包装类 都有 parXxxx 方法综合练习
键盘录入
// 需求: 键盘录入一些1~100之间的整数,并添加到集合中。
// 直到集合中所有数据和超过200为止// 源码:
package api;
import java.util.ArrayList;
import java.util.Scanner;
public class Test01 {
public static void main(String[] args) {
// 需求: 键盘录入一些1~100之间的整数,并添加到集合中。
// 直到集合中所有数据和超过200为止
// 步骤一: 创建集合 存储整数
ArrayList<Integer> list = new ArrayList<>();
// 步骤二: 键盘录入数据 并添加到集合中去
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入一个整数: ");
String s = sc.nextLine();
// 类型转换
int num = Integer.parseInt(s);
if (num < 1 || num > 100) {
System.out.println("请输入数据1~100之间的数据");
continue;
}
// 将数据添加到集合中去
list.add(num);
// 集合求和
int sum = getSum(list);
if (sum > 200) {
System.out.println("集合中的所有数据和已经超过200");
break;
}
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
// 创建一个求和方法
private static int getSum(ArrayList<Integer> list) {
int sum = 0;
for (int i = 0; i < list.size(); i++) {
sum += list.get(i);
}
return sum;
}
}算法水题1
// 自己实现parseInt方法的效果,将字符串形式的数据转成整数。
// 要求:
// 字符串中只能是数字不能有其他字符
// 最少一位,最多10位
// 0不能开头// 源码:
package api;
public class Test02 {
public static void main(String[] args) {
// 自己实现parseInt方法的效果,将字符串形式的数据转成整数。
// 要求:
// 字符串中只能是数字不能有其他字符
// 最少一位,最多10位
// 0不能开头
// 步骤一: 定义一个字符串
String str = "123456789";
// 步骤二: 字符串的校验
boolean matches = str.matches("[1-9]\\d{0,9}");
if (!matches) {
System.out.println("数据格式有误!!!");
} else {
// 步骤三: 定义一个变量存储最终的整数
int number = 0;
// 步骤四: 遍历字符串得到里面的每一个字符
for (int i = 0; i < str.length(); i++) {
int c = str.charAt(i) - '0';
number = number * 10 + c;
}
System.out.println(number);
}
}
}算法水题2
// 需求:
// 定义一个方法自己实现toBinaryString方法的效果,将一个十进制整数转成字符串表示的二进制package api;
public class Test03 {
public static void main(String[] args) {
// 定义一个方法自己实现toBinaryString方法的效果,将一个十进制整数转成字符串表示的二进制
String str = toBinaryString(6);
System.out.println(str);
// 使用Java去验证是否正确
System.out.println(Integer.toBinaryString(6));
}
// 步骤一: 定义一个方法 三部曲
public static String toBinaryString(int number) {
// 定义一个字符串 实现拼接
StringBuilder str = new StringBuilder();
// 除基取余 倒着拼接
while (true) {
//当 number 为0 跳出循环
if (number == 0) break;
// 现获取余数 % 2
int remainder = number % 2;
// 在0索引处添加数据
str.insert(0 , remainder);
// 在获取除数 / 2
number /= 2;
}
return str.toString();
}
}算法水题3
// 需求:
// 请使用代码实现计算你活了多少天,用JDK7和JDK8两种方式完成// 源码
package api;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Date;
public class Test04 {
public static void main(String[] args) throws ParseException {
// 需求
// 请使用代码实现计算你活了多少天,用JDK7和JDK8两种方式完成
// JDK7 需要将时间转化为毫秒值再进比较计算
// 步骤一: 获取出生年月的毫秒值
String birthday = "1998-06-02";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(birthday);
long birthdayTime = date.getTime();
System.out.println("出生日期毫秒值: " + birthdayTime);
// 步骤二: 获取当前时间的毫秒值
long nowTime = System.currentTimeMillis();
System.out.println("现在时间的毫秒值: " + nowTime);
// 步骤三: 计算时间间隔多少天
long time = (nowTime - birthdayTime) / 1000 / 60 / 60 / 24;
System.out.println(time);
System.out.println("==================");
// JDK8
// 步骤一: 获取出生年月日
LocalDate ld1 = LocalDate.of(1998, 6, 2);
System.out.println(ld1);
// 步骤二: 获取当前时间的年月日
LocalDate now = LocalDate.now();
System.out.println(now);
// 步骤三: 获取时间间隔
long time1 = ChronoUnit.DAYS.between(ld1, now);
System.out.println(time1);
}
}算法水题4
// 判断任意的一个年份是闰年还是平年
// 要求:用JDK7和JDK8两种方式判断
// 提示:
// 二月有29天是闰年
// 一年有366天是闰年常见算法
基本查找 / 顺序查找
// 基本查找
// 需求:定义一个方法利用基本查找,查询某个元素是否存在
// 数据如下:{131,127,147,81,103,27,7,79}package suanfa;
public class Test01 {
public static void main(String[] args) {
// 基本查找
// 需求:定义一个方法利用基本查找,查询某个元素是否存在
// 数据如下:{131,127,147,81,103,27,7,79}
// 步骤二: 定义一个数组 存储上面的数据
int[] arr = {131, 127, 147, 81, 103, 27, 7, 79};
// 步骤三: 定义一个数据
int number1 = 81;
int number2 = 99;
// 步骤四: 调用方法
boolean b1 = getBaseSearch(arr, number1);
boolean b2 = getBaseSearch(arr, number2);
System.out.println(b1 + " " +b2);
}
// 步骤一: 定义一个方法 三部曲
public static boolean getBaseSearch(int[] arr, int number) {
// 循环遍历数组
for (int i = 0; i < arr.length; i++) {
if (arr[i] == number) return true;
}
return false;
}
}二分查找 / 折半查找
优势: 提高查找效率
前提条件: 数组中的数据必须是有序的
核心逻辑: 每次排除一半的查找范围
max 最大索引 min 最小索引 mid中间索引
// 二分查找 / 折半查找
// 需求:定义一个方法利用二分查找/折半查找,查询某个元素在数组中的索引
// 数据如下:{7,23,56,81,99,122,135,155,180}// 源码:
package suanfa;
public class Test02 {
public static void main(String[] args) {
// 二分查找 / 折半查找
// 需求:定义一个方法利用二分查找/折半查找,查询某个元素在数组中的索引
// 数据如下:{7,23,56,81,99,122,135,155,180}
// 步骤二: 定义数组存储上面的数据
int[] arr = {7, 23, 56, 81, 99, 122, 135, 155, 180};
// 步骤三: 定义查询的数据
int number1 = 81;
int number2 = 155;
int number3 = 199;
int number4 = 5;
// 步骤四: 调用方法
int index1 = getIndex(arr, number1);
int index2 = getIndex(arr, number2);
int index3 = getIndex(arr, number3);
int index4 = getIndex(arr, number4);
System.out.println(index1 + " " + index2 + " " + index3 + " " + index4);
}
// 步骤一: 定义一个方法 三部曲
public static int getIndex(int[] arr, int number) {
// 定义三个索引
int max = arr.length - 1;
int min = 0;
while (true) {
if (min > max) return -1;
// 获取中间的索引值
int mid = (max + min) / 2;
// 判断中间索引对应的值有三种情况
if (arr[mid] > number) {
max = mid - 1;
} else if (arr[mid] < number) {
min = mid + 1;
} else if (arr[mid] == number) {
return mid;
}
}
}
}分块查找
分块的原则1:前一块中的最大数据,小于后一块中所有的数据(块内无序,块间有序)
分块的原则2:块数数量一般等于数字的个数开根号。比如:16个数字一般分为4块左右。
核心思路:先确定要查找的元素在哪一块,然后在块内挨个查找。
// 分块查找
// 核心思想:
// 块内无序,块间有序
// 实现步骤:
// 1.创建数组blockArr存放每一个块对象的信息
// 2.先查找blockArr确定要查找的数据属于哪一块
// 3.再单独遍历这一块数据即可// 源码:
package suanfa;
public class Test03 {
public static void main(String[] args) {
// 分块查找
// 核心思想:
// 块内无序,块间有序
// 实现步骤:
// 1.创建数组blockArr存放每一个块对象的信息
// 2.先查找blockArr确定要查找的数据属于哪一块
// 3.再单独遍历这一块数据即可
int[] arr = {16, 5, 9, 12, 21, 18,
32, 23, 37, 26, 45, 34,
50, 48, 61, 52, 73, 66};
// 步骤一: 对数据进行分类 如上所示
// 步骤三: 创建三个快的对象
Block b1 = new Block(21, 0, 5);
Block b2 = new Block(37, 6, 11);
Block b3 = new Block(73, 12, 17);
// 步骤四: 定义一个数组存储三个对象
Block[] blockArr = {b1, b2, b3};
// 步骤五: 定义一个变量 存储要查询的值
int number1 = 30;
int number2 = 100;
int number3 = 26;
int number4 = 66;
// 步骤七: 调用方法 获取索引值 传递索引表/原始的数组/要查询的值
int index1 = getIndex(blockArr, arr, number1);
int index2 = getIndex(blockArr, arr, number2);
int index3 = getIndex(blockArr, arr, number3);
int index4 = getIndex(blockArr, arr, number4);
System.out.println(index1 + " " + index2 + " " + index3 + " " + index4);
}
// 步骤六: 定义一个方法 利用分块原理 查询对应的index
private static int getIndex(Block[] blockArr, int[] arr, int number) {
// 查询在对象里面的索引值
int blockIndex = findBlockIndex(blockArr, number);
// 索引值进行判断 -1 直接返回 -1
if(blockIndex == -1) return -1;
// 索引值不等于-1 循环遍历数据
int startIndex = blockArr[blockIndex].getStartIndex();
int endIndex = blockArr[blockIndex].getEndIndex();
for (int i = startIndex ; i <= endIndex; i++) {
if(number == arr[i]) return i;
}
return -1;
}
// 再次定义一个方法 查询number在对象的那个索引上
public static int findBlockIndex(Block[] blockArr, int number) {
for (int i = 0; i < blockArr.length; i++) {
if(blockArr[i].getMax() >= number) return i;
}
return -1;
}
}
// 步骤二: 定义一个Javabean类
class Block {
// 成员变量
private int max;
private int startIndex;
private int endIndex;
public Block() {
}
public Block(int max, int startIndex, int endIndex) {
this.max = max;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
/**
* 获取
*
* @return max
*/
public int getMax() {
return max;
}
/**
* 设置
*
* @param max
*/
public void setMax(int max) {
this.max = max;
}
/**
* 获取
*
* @return startIndex
*/
public int getStartIndex() {
return startIndex;
}
/**
* 设置
*
* @param startIndex
*/
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
/**
* 获取
*
* @return endIndex
*/
public int getEndIndex() {
return endIndex;
}
/**
* 设置
*
* @param endIndex
*/
public void setEndIndex(int endIndex) {
this.endIndex = endIndex;
}
public String toString() {
return "Block{max = " + max + ", startIndex = " + startIndex + ", endIndex = " + endIndex + "}";
}
}插值查找
- 前提条件: 数组中的数据必须是有序的
优化二分查找
斐波那契查找
- 前提条件: 数组中的数据必须是有序的
优化二分查找
树表查找
哈希查找
排序算法
冒泡排序
- 冒泡排序 : 相邻的元素两两比较,大的放右边,小的放左边
// 代码实现
package suanfa;
public class Test04 {
public static void main(String[] args) {
// 冒泡排序
// 核心: 相邻的元素两两比较,大的放右边,小的放左边
// 定义一个数组
int[] arr = {4, 2, 3, 5, 1, 8, 9, 10, 50, 30, 20, 15, 99};
// 循环遍历
for (int i = 1; i < arr.length; i++) {
// 判断相邻两个数据
for (int j = 0; j < arr.length - i; j++) {
// 判断相邻两个数
if (arr[j] > arr[j + 1]) {
// 进行变换位置
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}选择排序
- 从0索引开始,拿着每一个索引上的元素跟后面的元素依次比较小的放前面,大的放后面,以此类推。
插入排序
插入排序:将0索引的元素到N索引的元素看做是有序的,把N+1索引的元素到最后一个当成是无序的。遍历无序的数据,将遍历到的元素插入有序序列中适当的位置,如遇到相同数据,插在后面。
N的范围:0~最大索引
递归算法
递归指的是方法中调用方法本身的现象
递归的注意点:递归一定要有出口,否则就会出现内存溢出
- 核心: 1.找出口 2.找规律
// 递归求 1~100 之间的和
// 源码:
package suanfa;
public class Test05 {
public static void main(String[] args) {
// 递归求 1~100 之间的和
// 步骤二: 调用函数
int sum = getSum(100);
System.out.println(sum);
}
// 步骤一: 定义一个方法 三部曲
public static int getSum(int number) {
if (number == 1) return 1;
return number + getSum(number - 1);
}
}// 需求: 利用递归求5的阶乘
// 5! = 5 * 4 * 3 * 2 * 1
package suanfa;
public class Test06 {
public static void main(String[] args) {
// 需求: 利用递归求5的阶乘
// 5! = 5 * 4 * 3 * 2 * 1
// 步骤二: 调用方法
int factorial = getFactorial(5);
System.out.println(factorial);
}
// 步骤一: 定义方法 三部曲
public static int getFactorial(int number){
// 递归的核心 找出口 找规律
if(number == 1) return 1;
return number * getFactorial(number -1);
}
}快速排序
第一轮:把0索引的数字作为基准数,确定基准数在数组中正确的位置。 比基准数小的全部在左边,比基准数大的全部在右边。
要先移动右边的 再移动左边的
将排序范围中的第一个数字作为基准数,再定义两个变量start,end
start从前往后找比基准数大的,end从后往前找比基准数小的。
找到之后交换start和end指向的元素,并循环这一过程,直到start和end处于同一个位置,该位置是基准数在数组中应存入的位置,再让基准数归位。
归位后的效果:基准数左边的,比基准数小,基准数右边的,比基准数大
执行的效率很快
http://maven.aliyun.com/nexus/content/groups/public
// 快速排序
// 快速排序的原理:
// 1. 将排序范围中的第一个数字作为基准数,再定义两个变量start,end
// 2. start从前往后找比基准数大的,end从后往前找比基准数小的.
// 3. 找到之后交换start和end指向的元素,并循环这一过程,直到start和end处于同一个位置,该位置是基准数在数组中应存入的位置,再让基准数归位。
// 4. 归位后的效果:基准数左边的,比基准数小,基准数右边的,比基准数大
// 注意点: 需要先执行右边的执行左边的// 源码:
package suanfa;
public class Test07 {
public static void main(String[] args) {
// 快速排序
// 快速排序的原理:
// 1. 将排序范围中的第一个数字作为基准数,再定义两个变量start,end
// 2. start从前往后找比基准数大的,end从后往前找比基准数小的.
// 3. 找到之后交换start和end指向的元素,并循环这一过程,直到start和end处于同一个位置,该位置是基准数在数组中应存入的位置,再让基准数归位。
// 4. 归位后的效果:基准数左边的,比基准数小,基准数右边的,比基准数大
// 注意点: 需要先执行右边的执行左边的
// 步骤一: 定义一个无序的数组
int[] arr = {6,9,4,5,3,1,2,7,8};
// 步骤三: 调用方法
getQuickSort(arr , 0 , arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
// 步骤二: 定义方法 三部曲
public static void getQuickSort(int[] arr ,int i ,int j){
int start = i;
int end = j;
// 递归的出口
if(start > end) return;
// 定义第一个数据基数
int baseNum = arr[i];
// 利用循环找到要交换的数据
while(start != end){
// 找出右边比基数小的
while(true){
if(end <= start || arr[end] < baseNum) break;
end--;
}
// 找出左边比基数大的
while(true){
if (end <= start || arr[start] > baseNum) break;
start++;
}
// 把start和end数据进行交换
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
// 循环完毕 基准数归位
int temp = arr[i];
arr[i] = arr[start]; // arr[end]
arr[start] = temp;
// 左右分别重复刚才的操作 即递归操作 两个核心(1.找出口 2.找规律)
getQuickSort(arr , i ,start-1);
getQuickSort(arr , start+1 , j);
}
}希尔排序
堆排序
桶排序
归并排序
计数排序
基数排序
Arrays
操作数组的工具类
// public static String toString(数组)把数组拼接成一个字符申
// public static int binarySearch(数组,查找的元素)二分查找法查找元素
// public static int[]copyOf(原数组,新数组长度)拷贝数组
// public static int[]copyOfRange(原数组,起始索引,结束索引)拷贝数组(指定范围)
// public static void fi1l(数组,元素)填充数组
// public static void sort(数细)按照默认方式进行数组排序
// public static void sort(数组,排序规则)按照指定的规则排序// sort
Arrays.sort(arr1, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
// o1 - o2 从小到大 排序
// o2 - o1 从大到小 排序
}
});Arrays.sort()
// 排序再次讲解
package suanfa;
import java.util.Arrays;
import java.util.Comparator;
public class Test09 {
public static void main(String[] args) {
// Arrays
// 定义一个数据
int[] arr = {10,2,3,4,5,6,7,8,9,1};
// 把数组拼接位一个字符串
System.out.println(Arrays.toString(arr));
// 数据的复制
int[] arrCopy = Arrays.copyOf(arr, arr.length);
System.out.println(Arrays.toString(arrCopy));
System.out.println("======================================");
// 数组的排序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.toString(arrCopy));
// 排序默认就是 基本数据类型不行 必须是引用的数据类型
Integer[] arr2 = {5,8,9,1,3,2,6,4,7,10};
// 匿名内部类
Arrays.sort(arr2, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
// o1 - o2 是升序
// o2 - 01 是降序
}
});
System.out.println(Arrays.toString(arr2));
}
}Lambda表达式
函数式编程
函数式编程(Functionalprogramming)是一种思想特点。
函数式编程思想,忽略面向对象的复杂语法,强调做什么,而不是谁去做。
而我们要学习的Lambda表达式就是函数式思想的体现。
标准格式
() -> {}
// () 形参
// -> 固定格式
// {} 方法体注意事项
Lambda表达式可以用来简化匿名内部类的书写
Lambda表达式只能简化函数式接口的匿名内部类的写法
函数式接口:
- 有且仅有一个抽象方法的接口叫做函数式接口,接口上方可以加@Functionallnterface注解
package suanfa;
import java.util.Arrays;
import java.util.Comparator;
public class Test10 {
public static void main(String[] args) {
// 定义数组并存储一些字符串,利用Arrays中的sort方法进行排序
// 要求:
// 按照字符串的长度进行排序,短的在前面,长的在后面。(暂时不比较字符串里面的内容)
// 定义一个数组 存储字符串
String[] arr = {"aa" , "a" , "aaaa" , "aaa"};
// 排序
Arrays.sort(arr, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
System.out.println(Arrays.toString(arr));
// Lambda 简化 匿名内部类 完整格式
Arrays.sort(arr, (String o1, String o2) -> {
return o2.length() - o1.length();
}
);
System.out.println(Arrays.toString(arr));
// Lambda 简化 匿名内部类 简化格式
Arrays.sort(arr, ( o1, o2) -> o1.length() - o2.length());
System.out.println(Arrays.toString(arr));
}
}综合练习
按照要求进行排序
定义数组并存储一些女朋友对象,利用Arrays中的sort方法进行排序
要求1:属性有姓名、年龄、身高。
要求2:按照年龄的大小进行排序,年龄一样,按照身高排序,身高一样按照姓名的字母进行排序。
(姓名中不要有中文或特殊字符,会涉及到后面的知识)集合进阶
Collection集合
- Collection是单列集合的顶层接口,所有方法被List和Set系列集合共享
- 常见成员方法: add clear remove contains isEmpty size
- 三种通用的遍历方式
// Collection 常见方法
package suanfa;
import java.util.ArrayList;
import java.util.Collection;
public class Test11 {
public static void main(String[] args) {
// 单利集合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()集合长度
Collection<String> coll = new ArrayList<>();
// 添加元素
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
System.out.println(coll);
// 清空数据
// coll.clear();
// System.out.println(coll);
// 删除
coll.remove("bbb");
System.out.println(coll);
// 判断是否包含
System.out.println(coll.contains("ccc"));
System.out.println(coll.contains("bbb"));
// 判断是否为空
System.out.println(coll.isEmpty());
// 获取集合的长度
System.out.println(coll.size());
}
}迭代器遍历
迭代器在Java中的类是lterator,迭代器是集合专用的遍历方式。
package suanfa;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test12 {
public static void main(String[] args) {
// collection系列集合三种通用的遍历方式:
// 1.选代器遍历
// 2.增强for遍历
// 3.Lambda表达式遍历
// 选代器追历相关的三个方法:
// Iterator<E>iterator():获取一个选代器对象
// boolean hasNext():判断当前指向的位置是否有元素
// E next():获取当前指向的元素并移动指针
// 创建集合
Collection<String> coll = new ArrayList<>();
// 向集合中添加元素
coll.add("a");
coll.add("b");
coll.add("c");
coll.add("d");
coll.add("e");
coll.add("f");
// 通过集合 获取迭代器对象
// 迭代器就好比是一个箭头 默认指向集合的0索引出
Iterator<String> it = coll.iterator();
// 循环遍历 获取集合中的每一个元素
while(it.hasNext()){
String str = it.next();
System.out.println(str);
}
}
}增强for遍历
// 基本格式
for(元素的数据类型 变量名 : 数组或者集合){ }package suanfa;
import java.util.ArrayList;
import java.util.Collection;
public class Test13 {
public static void main(String[] args) {
// collection系列集合三种通用的遍历方式:
// 1.选代器遍历
// 2.增强for遍历
// 3.Lambda表达式遍历
// 增强for遍历
// for(元素的数据类型 变量名 : 数组或者集合){ }
// 步骤一: 创建集合
Collection<String> coll = new ArrayList<>();
// 步骤三: 向集合中添加数据
coll.add("张三");
coll.add("李四");
coll.add("王五");
// 增强for遍历 快捷键 coll.for 回车
for(String str : coll){
System.out.println(str);
}
}
}Lambda表达式遍历
// lambda表达式遍历:
default void forEach(Consumer<? super T> action):package suanfa;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
public class Test14 {
public static void main(String[] args) {
// collection系列集合三种通用的遍历方式:
// 1.选代器遍历
// 2.增强for遍历
// 3.Lambda表达式遍历
// Lambda表达式遍历
// default void forEach(Consumer<? super T> action):
// 创建集合
Collection<String> coll = new ArrayList<>();
// 向集合中 添加数据
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
// 首先使用匿名内部类的形式
coll.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
System.out.println("========");
// 使用lambda表达式进行遍历
coll.forEach(s -> System.out.println(s));
}
}List集合
列表迭代器
普通for循环
package suanfa;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Test15 {
public static void main(String[] args) {
// List系列集合独有的方法:
// void add(int index,E element)在此集合中的指定位置插入指定的元素
// E remove(int index)删除指定索引处的元素,返回被删除的元素
// E set(int index,E element)修改指定索引处的元素,返回被修改的元素
// E get(int index)返回指定索引处的元素
// List系列集合的五种通历方式:
// 1.迭代器 在遍历的过程中需要删除元素,请使用迭代器。 Iterator 继承Collection
// 2.列表迭代器 在遍历的过程中需要添加元素,请使用列表迭代器。 ListIterator
// 3.增强for 仅仅想遍历,那么使用增强for或Lambda表达式。 继承Collection
// 4.Lambda表达式 仅仅想遍历,那么使用增强for或Lambda表达式。 继承Collection
// 5.普通for循环 如果遍历的时候想操作索引,可以用普通for
// 创建集合 多态的形式
List<String> list = new ArrayList<>();
// 向集合中添加元素
list.add("张三");
list.add("李四");
list.add(1 , "王五");
System.out.println(list);
// 删除元素
System.out.println(list.remove("李四"));
System.out.println(list);
// 修改元素
System.out.println(list.set(0 , "小冯"));
System.out.println(list);
// 获取元素
System.out.println(list.get(1));
System.out.println("===========");
// 继承Collection的方法 迭代器
Iterator<String> ite = list.iterator();
while(ite.hasNext()){
String str = ite.next();
System.out.println(str);
}
System.out.println("===========");
// 继承Collection的方法 增强for
for (String s : list) {
System.out.println(s);
}
System.out.println("===========");
// 继承Collection的方法 Lambda表达式
list.forEach(s -> System.out.println(s));
System.out.println("===========");
// 普通的for循环
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
System.out.println("===========");
// 列表迭代器
ListIterator<String> li = list.listIterator();
while(li.hasNext()){
String next = li.next();
System.out.println(next);
}
System.out.println("===========");
}
}常见的数据结构
需要掌握下面的三个核心
- 每种数据结构长什么样子?
- 如何添加数据?
- 如何删除数据?
栈
栈的特点: 先进后出, 后进先出
队列
队列的特点: 先进先出, 后进后出
数组
查询快 增删慢 (连续空间)
链表
查询慢 增删快 (元素是游离)
二叉树
数据没有规律
遍历方式
// 二叉树遍历方式
// 前序遍历: 当前节点,左子节点,右子结点
// 中序遍历: 左子节点,当前节点,右子结点
// 后序遍历: 左子节点,右子结点,当前节点
// 层序遍历: 一层一层的去遍历二叉查找树
规则: 小的放在左节点, 大的放在右节点. 相等不存
平衡二叉树
规则: 任意节点左右子树高度差不超过1
旋转机制
// 旋转机制
// 规则一: 左旋
// 规则二: 右旋
// 触发时机: 当添加一个节点之后, 该树不在是一颗平衡二叉树红黑树
// 1.每一个节点或是红色的,或者是黑色的
// 2.根节点必须是黑色
// 3.如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
// 4.如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
// 5.对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点;ArraysList集合
// ArrayList的底层原理
// 1.利用空参创建的集合,在底层创建一个默认长度为0的数组
// 2.添加第一个元素时,底层会创建一个新的长度为10的数组
// 3.存满时,会扩容1.5倍
// 4.如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准LinkedList集合
// LinkedList的底层原理泛型
Java中的泛型是伪泛型
- 泛型中不能写基本数据类型
- 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
- 如果不写泛型,类型默认是Object
泛型类
// 使用场景: 当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
// 格式:
修饰符 class 类名<E>{}
public class ArrayList<E>{}
// 此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成:T(方法)、E(类中)、K、V等// 带有泛型的类
package suanfa;
// 当我在编写一个类的时候,如果不确定类型,那么这个类就可以定义为泛型类。
import java.util.Arrays;
public class MyArrayList<E> {
Object[] obj = new Object[10];
int size;
// 自定义添加方法 add
public boolean add(E e){
obj[size] = e;
size++;
return true;
}
// 自定义获取方法 get
public E get(int index){
return (E)obj[index];
}
@Override
public String toString() {
return Arrays.toString(obj);
}
}// 测试类:
package suanfa;
public class Test16 {
public static void main(String[] args) {
MyArrayList<String> list = new MyArrayList<>();
// 添加元素
list.add("张三");
list.add("李四");
list.add("王五");
// 获取元素
System.out.println(list.get(0));
System.out.println(list.get(1));
System.out.println(list.get(2));
System.out.println("===============");
System.out.println(list);
}
}泛型方法
// 方法中形参类型不确定时
// 方案1:使用类名后面定义的泛型 所有方法都能用
// 方案2:在方法申明上定义自己的泛型 只有本方法能用
// 基本格式
修饰符<类型> 返回值类型 方法名(类型 变量名){}
public<T> void show(T t){}
//// 泛型方法的练习
// 定义一个工具类:ListUtil
// 类中定义一个静态方法addAll,用来添加多个集合的元素。package suanfa;
import java.util.ArrayList;
public class ListUtil {
// 私有化构造方法
// 目的: 不让外界创建对象
private ListUtil() {}
// 类中定义一个静态方法addAll,用来添加多个集合的元素.
public static<T> void addAll(ArrayList<T> list , T e1 ,T e2 ,T e3 ,T e4 ){
list.add(e1);
list.add(e2);
list.add(e3);
list.add(e4);
}
// 顶一个不确定的个数
public static<T> void addAlls(ArrayList<T> list , T ...e){
for (T t : e) {
list.add(t);
}
}
}package suanfa;
import java.util.ArrayList;
public class Test17 {
public static void main(String[] args) {
// 定义一个工具类:ListUtil
// 类中定义一个静态方法addAll,用来添加多个集合的元素.
ArrayList<String> list = new ArrayList<>();
ListUtil.addAll(list , "张三" , "李四" , "王五" ,"小冯");
System.out.println(list);
// 添加不确定的元素
ArrayList<Integer> list1 = new ArrayList<>();
ListUtil.addAlls(list1 , 1,2,3,4,5,6,7,8,9);
System.out.println(list1);
}
}泛型接口
// 基本格式:
修饰符 interface 接口名<类型>{}
public interface List<E>{}
// 重点: 如何使用一个带泛型的接口
// 方式一: 实现类给出具体的类型
public class Test implements List<String> {}
// 方式二: 实现类延续泛型, 创建对象时再确定
public class Test<E> implements List<E> {}泛型的继承和通配符
// 泛型不具备继承性,但是数据具备继承性
// ? extends E :表示可以传递E或者E所有的子类类型
// ? super E:表示可以传递E或者E所有的父类类型泛型总结
// 1.什么是泛型?
// JDK5引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
// 2.泛型的好处?
// 统一数据类型
// 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
// 3.泛型的细节?
// 泛型中不能写基本数据类型
// 指定泛型的具体类型后,传递数据时,可以传入该类型和他的子类类型
// 如果不写泛型,类型默认是Object
// 4.哪里定义泛型?
// 泛型类:在类名后面定义泛型,创建该类对象的时候,确定类型
// 泛型方法:在修饰符后面定义方法,调用该方法的时候,确定类型
// 泛型接口:在接口名后面定义泛型,实现类确定类型,实现类延续泛型
// 5.泛型的继承和通配符
// 泛型不具备继承性,但是数据具备继承性
// 泛型的通配符:?
// ?extend E
// ?super E
// 6.使用场景
// 定义类、方法、接口的时候,如果类型不确定,就可以定义泛型
// 如果类型不确定,但是能知道是哪个继承体系中的,可以使用泛型的通配符Set集合
1.Set系列集合的特点
- 无序、不重复、无索引
- Set集合的方法上基本上与Collection的APl一致
2.Set集合的实现类特点
- HashSet:无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:可排序、不重复、无索引
package suanfa;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test18 {
public static void main(String[] args) {
// 利用Set系列的集合,添加字符串,并使用多种方式遍历。
// 选代器
// 增强for
// Lambda表达式
// Set集合添加元素无序, 不重复, 没有索引
// Set集合继承collection
// 步骤一: 创建一个Set集合的对象
Set<String> s = new HashSet<>();
// 步骤二: 添加元素
s.add("张三");
s.add("李四");
s.add("王五");
System.out.println(s);
System.out.println("==================");
// 遍历集合 迭代器
Iterator<String> iterator = s.iterator();
while(iterator.hasNext()){
String r = iterator.next();
System.out.println(r);
}
System.out.println("==================");
// 遍历集合 增强for
for (String string : s) {
System.out.println(s);
}
System.out.println("==================");
// 遍历集合 Lambda表达式( 即匿名内部类变化而来 )
s.forEach(r -> System.out.println(r) );
}
}HashSet
特点: 无序、不重复、无索引
// Hashset底层原理
// - HashSet集合底层采取哈希表存储数据
// - 哈希表是一种对于增删改查数据性能都较好的结构
// 哈希表组成
// - JDK8之前:数组 + 链表
// - JDK8开始:数组 + 链表 + 红黑树哈希值
哈希值: 对象的整数表现形式
// 哈希值:
// 对象的整数表现形式
// 1.如果没有重写hashcode方法,计算出的哈希值是不同的
// 2.如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
// 3.但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)// 需求:创建一个存储学生对象的集合,存储多个学生对象。
// 使用程序实现在控制台遍历该集合
// 要求:学生对象的成员变量值相同,我们就认为是同一个对象
// 注意事项: 向集合集合中添加 String Integer 底层已经写了hashcode; 自己写Javabean类的时候需要自己添加hashcode方法package suanfa;
import java.util.HashSet;
public class Test19 {
public static void main(String[] args) {
// 需求:创建一个存储学生对象的集合,存储多个学生对象。
// 使用程序实现在控制台遍历该集合
// 要求:学生对象的成员变量值相同,我们就认为是同一个对象
// 创建集合
HashSet<Integer> list1 = new HashSet<>();
// 向集合中添加数据
System.out.println(list1.add(1));
System.out.println(list1.add(2));
System.out.println(list1.add(3));
System.out.println(list1.add(1));
System.out.println(list1);
System.out.println("==========================");
// 创建一个学生对象
Student s1 = new Student("张三" , 24);
Student s2 = new Student("李四" , 30);
Student s3 = new Student("王五" , 28);
Student s4 = new Student("张三" , 24);
// 创建集合
HashSet<Student> list2 = new HashSet<>();
// 向集合中添加元素
System.out.println(list2.add(s1));
System.out.println(list2.add(s2));
System.out.println(list2.add(s3));
System.out.println(list2.add(s4));
System.out.println(list2);
}
}LinkedHashSet
特点: 有序、不重复、无索引
// 1.LinkedHashSet集合的特点和原理是怎么样的?
// 有序、不重复、无索引
// 底层基于哈希表,使用双链表记录添加顺序
// 2.在以后如果要要数据去重我们使用哪个?
// 默认使用HashSet
// 如果要求去重且存取有序,才使用LinkedHashSetpackage suanfa;
import java.util.LinkedHashSet;
public class Test20 {
public static void main(String[] args) {
// 1.LinkedHashSet集合的特点和原理是怎么样的?
// 有序、不重复、无索引
// 底层基于哈希表,使用双链表记录添加顺序
// 2.在以后如果要要数据去重我们使用哪个?
// 默认使用HashSet
// 如果要求去重且存取有序,才使用LinkedHashSet
// 步骤一: 创建学生对象
Student s1 = new Student("张三" , 22);
Student s2 = new Student("李四" , 30);
Student s3 = new Student("王五" , 20);
Student s4 = new Student("张三" , 22);
// 创建集合
LinkedHashSet<Student> lhs = new LinkedHashSet<>();
// 向集合中添加数据
System.out.println(lhs.add(s1));
System.out.println(lhs.add(s2));
System.out.println(lhs.add(s3));
System.out.println(lhs.add(s4));
System.out.println(lhs);
}
}TreeSet
特点: 可排序、不重复、无索引
底层: 红黑树 数据结构
eg: Intege 进行排序
两种比较方式
**方式一: **
默认排序 / 自然排序 : Javabean类实现Comparable接口指定比较规则.
package suanfa; import java.util.TreeSet; public class Test21 { public static void main(String[] args) { // 需求:创建TreeSet集合,并添加3个学生对象 // 学生对象属性: // 姓名,年龄。 // 要求按照学生的年龄进行排厅 // 同年龄按照姓名字母排列(暂不考虑中文) // 同姓名,同年龄认为是同一个人 // 指定排序方式 // 方式一: // 默认排序/自然排序: Javabean类实现Comparable接口 // 方式二: // 比较器排序:创建TreeSet对象时候,传递比较器Comparator指定规则 // 创建学生对象 Test21Student s1 = new Test21Student("zhangsan" , 29); Test21Student s2 = new Test21Student("lisi" , 28); Test21Student s3 = new Test21Student("wangwu" , 30); Test21Student s4 = new Test21Student("wangermazi" , 20); // 创建集合 TreeSet<Test21Student> ts = new TreeSet<>(); // 先集合中添加学生对象 ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); System.out.println(ts); } }
**方式二: **
比较器排序:创建TreeSet对象时候,传递比较器Comparator指定规则
package suanfa; import java.util.Comparator; import java.util.TreeSet; public class Test21 { public static void main(String[] args) { // 需求:请自行选择比较器排序和自然排序两种方式; // 要求:存入四个字符串,“c",“ab”,“df",“qwer" // 按照长度排序,如果一样长则按照首字母排序 // 指定排序方式 // 方式一: // 默认排序/自然排序: Javabean类实现Comparable接口 // 方式二: // 比较器排序:创建TreeSet对象时候,传递比较器Comparator指定规则 // 自然排序 // 创建集合 TreeSet<String> ts1 = new TreeSet<>(); // 向集合中添加元素 ts1.add("c"); ts1.add("ab"); ts1.add("df"); ts1.add("qwer"); System.out.println(ts1); // 比较器排序 // 创建集合 // o1:表示当前要添加的元素 // o2:表示已经在红黑树存在的元肃 // Comparator 是函数式接口 即可以改为lambda表达式 TreeSet<String> ts2 = new TreeSet<>(new Comparator<String>() { @Override public int compare(String o1, String o2) { // 按照长度排序, int i = o1.length() - o2.length(); // 如果一样长则按照首字母排序 i = i == 0 ? o1.compareTo(o2) : i; return i; } }); // lambda 表达式 TreeSet<String> ts3 = new TreeSet<>((o1, o2) -> { // 按照长度排序, int i = o1.length() - o2.length(); // 如果一样长则按照首字母排序 i = i == 0 ? o1.compareTo(o2) : i; return i; } ); // 向集合中添加元素 ts2.add("c"); ts2.add("ab"); ts2.add("df"); ts2.add("qwer"); // 向集合中添加元素 ts3.add("c"); ts3.add("ab"); ts3.add("df"); ts3.add("qwer"); System.out.println(ts2); System.out.println(ts3); } }
使用场景
- 1.如果想要集合中的元素可重复
- 用ArrayList集合,基于数组的。(用的最多)
- 2.如果想要集合中的元素可重复,而且当前的增删操作明显多于查询
- 用LinkedList集合,基于链表的
- 3.如果想对集合中的元素去重
- 用HashSet集合,基于哈希表的。(用的最多)
- 4.如果想对集合中的元素去重,而且保证存取顺序
- 用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet。
- 5.如果想对集合中的元素进行排序
- 用TreeSet集合,基于红黑树。后续也可以用List集合实现排序。
Java的注解
在注解入门
注解的声明类似于接口的声明,但是前面多了一个@符号:
内置注解
@Override: 限定重写父类方法。@Deprecated: 表示某个程序元素(如方法)已经过时。@SuppressWarnings: 告诉编译器忽略指定的警告。
元注解
用于注解其他注解的注解称为元注解。Java提供了以下几种元注解:
@Target: 表明该注解可以被应用于什么地方(如方法、类、字段等)。@Retention: 表明该注解的生命周期(仅源代码、编译期、运行期)。@Documented: 表示使用该注解的元素应被Javadoc或其他工具文档化。@Inherited: 表示该注解可以被子类继承。
自定义注解
- 使用@interface自定义注解时
@interface MyAnnototion{
// 注解参数: 参数类型 参数名();
int age();
// defalut 即 默认值
String name() default "";
// 默认值为 -1 代表存在
int id(); defalut -1;
...
}反射机制
maven 工具
Java项目
数据可视化
数据中枢
ETL
- 数据格式化 (统一管理)
