【JavaSE】JavaSE_ALL
Java SE
gosling 1900 sun->甲骨文
一,概述
1.1 开发场景
-
SSM
Spring 轻量级容器框架
SpringMVC 分层 web 开发框架
MyBatis 持久化框架
-
Android
-
大数据-hadoop
1.2 应用领域
- JavaEE
- 大数据
- Android
1.3 技术体系
- Java SE (Java Standard Edition) 标准版
- Java EE (Java Enterprise Edition) 企业版
- Java ME (Java Micro Edition) 小型版
1.4 特点
- oop 面向对象
- 健壮 (强类型机制,异常处理,垃圾自动收集)
- 跨平台 (.class文件 JVM)
- 解释性 (c++ 是编译性语言,Java编译后的代码需要解释器执行后才可以机器执行)
1.5 开发工具
- notepad++
- Sublime Text (推荐)
- IDEA (推荐)
- eclipse
后两种是集成 IDE 很智能,建议先 Sublime 再 IDEA
1.6 运行机制&过程
-
Java 语言特性:跨平台
因为:JVM
-
JVM (Java Virtual Machine)
- JVM 是 Java 虚拟机,也就是一个虚拟的计算机,包含在 JDK 中
- 不同操作系统有不同 JVM
- JVM 实现了
一次编译,到处运行
有个.class 文件就中了
示意图:
1.7 JDK&JRE
1.7.1 JDK
JDK(Java Development Kit) 是 Java 开发工具包
组成:JRE + Java 开发工具 (java,Javac,javadoc,javap…)
1.7.2 JRE
JRE(Java Runtime Environment) 是 Java 运行环境
组成:JVM + Java SE核心类库
如果只是想运行一个开发好的 Java 程序(.class 文件),计算机只需要安装 JRE 就行
1.7.3 安装 JDK
-
作者的阿里云网盘有Windows的JDK8&JDK11 点这里
-
声明:
目前 JDK 有很多版本,但是用的多的还是 8,11 。这两个也是永久版,所以推荐这两个。
傻瓜式安装,下一步就行。
安装下载目录最好是非C盘,
路径不要有中文或特殊符号尤其是空格
1.7.4 配置环境变量 path
- 为什么要配这个?
这时候 JDK 只能在安装目录用,在非安装目录用不了。比如你在桌面打开 DOW 命令行输入
java
或者javac
会出现下图有这种情况就是需要配置环境变量 path
-
为什么会有这种情况?
因为在执行当前的程序在当前目录不存在时,Windows 就会在系统已有的一个
path
的环境变量的指定目录下查找。如果还找不到就会出现上图场景 -
配置步骤
1.8 开发注意
- Java 转义符
- 新手易犯错误
- 设置电脑中文状态也输入英文符号点这里
1.9注释&代码规范
自己看人代码的时候骂别人”TM怎么不写注释这孙子!“
自己写代码的时候,“我这水平还用注释?注释-狗都不写”
-
还是劝大家养成写注释的好习惯,增强自己代码的可读性。这是一种格局。
-
开始编程前先写注释理清思路,后面按着注释写代码会轻松很多。
-
注释类型
- 单行注释
// ~
- 多行注释
/* ~ */
- 文档注释
/** ~ */
- 单行注释
-
注意:
-
多行注释里面不允许俄罗斯套娃再整个多行注释
-
文档注释一般是写在类或者方法前面,它是用javadoc 所解析,生成一套网页文件形式的说明文档
-
文档注释语法:javadoc -d 文件夹名 -xx -yy 源文件.java
-
-
文档注释演示
-
-
代码规范
1.10 DOS命令(了解)
DOS(Disk Operating System) 磁盘操作系统。这个是 Windows的。在 Windows 上用的还真不多,一般都是图形页面直接点啊点。
有过 Linux 基础的朋友应该看着看轻松啦
-
路径
- 绝对路径:你滴全名。从顶级目录开始定位形成的路径
- 相对路径:你滴小名。从当前目录开始定位形成的路径
-
常用命令
1.11 IDE
IDE 叫集成开发环境,Java 中最著名的当属 IDEA ,Eclipse。
1.11.1 IDEA
1.11.1.1 工作界面
1.11.1.2 设置
- 字体和颜色主题
- 字符编码:
1.11.1.3 文件对应项目
1.11.1.4 快捷键
二,变量
2.1 简介
变量要素:(权限) 类型 名称 值
咋个理解:
变量
就是一个酒店房间,然后变量名
就是房间门牌号,变量值
就是住在这个房间中的人,然后通过变量名
去访问变量值
就是送外卖按门牌号送到那个人手上,因为住在这个房间中的人是可以变的所以它叫变量
,要是一个人一直住在一个房间,那他不就是定量
了,对吧。
2.2 使用入门
-
声明
int a;
-
赋值
a = 1;
-
同时
int a = 1;
-
注意
2.3 ‘+’ 使用
Java 中字符串的拼接用的是
+
,有些语言是用$
,比如 Linux 中的 Shell 和 Android 的 Kotlin。其实吧后者更好用的,一会这儿一个加号那里一个很麻烦的。
2.4 数据类型
前言:其实吧不同的数据类型就是对一个数据在内存中给它分配不同的内存大小(字节)
-
总览结构(很重要,必须记下来!)
-
整数类型
- 顾名思义,拿来放整数的
- 顾名思义,拿来放整数的
咱就是说
int
类型正那边最大能放1.5个中国人口(21.5亿)还有那个 byte 能容纳的最大整数怎么记?咱程序员大多是男生,所以~“拜托要爱妻”(byte 127)
负数部分比正数部分数值多一点撒~那就"富人正好比你多亿点"
整数的使用细节
补充字符编码
-
浮点类型
-
啥浮点不符点的,就是咱说的小数,以后看见浮点数就是小数。
-
-
浮点数就是小数点可以浮动,可以变来变去。代价是什么是你表示小数时后面要乘以10。小数点浮动10的幂就改变。(科学计数法)
-
注意:浮点数是不能直接比较大小的,他们都是近似值,有精度缺失。
-
-
-
字符类型
-
字符就是单个的字母,汉字啥的,比如‘a’,‘你’ 这种。你要是有一串就得用字符串或者字符数组。
-
记得用英文单引号引起来
-
如果是直接赋值数字,它以为是unicode 码 会去找这个数字在 unicode 码中对应哪一个字符
-
-
-
布尔类型
boolean 就是只有 true & false 两个值,表示判断的,逻辑运算
2.5 自动/强制 类型转换
Java 程序在进行赋值或者运算时,精度小的自动转换成精度大的数据类型
2.5.1 数据类型精度排序
(背下来!很重要!)
2.5.2 自动转换注意细节
2.5.3 强制类型转换
精度低到高的会自动类型转换,那反过来呢?非要水往高处流,加个水泵对吧。
注意:
2.6 基础数据类型和 String 类型转换
2.6.1 基础 -> String
- 基本类型值 + “”
- 基本数据类型.toString
2.6.2 String ->基础
用 ‘基础数据类型的包装类.parseXX
’ 方法
要确保 String 能装成有效的数据,别搁着 “hello” -> int
2.6.3 String -> char
char = String.charArt(x) 要字符串第 x 个字符
2.6.4 借图演示
三,运算符
一般有对数据的运算赋值和比较等等
3.1 包含
- 算术运算符
- 赋值运算符
- 关系(比较)运算符
- 逻辑运算符
- 位(二进制)运算符
- 三元运算符
3.2 算术运算符
- 演示图
- 细节补充
- 一道相关面试题
3.3 关系运算符(比较运算符)
关系运算符的结果(关系表达式)一般是 boolean 型,就是 true & false 任选其一
这个经常在 if 或者 循环结构中用
提一句:一个等号是赋值,两个才是比较鸭!
3.4 逻辑运算符
用来连接多个条件,多个关系表达式,最终结果也是一个 boolean 值
3.4.1 一览表
3.4.2 规则
3.4.3 补充
- 逻辑与和短路与的区别:比如第一个结果是 false ,短路与直接短路,说不可能了这局,然后退出;但是逻辑与不管怎么样还会去看后面的那哥们。全部一一核实后才会结束。
- 正因如此,我们很少用单个的那个逻辑与或都是用短路的,为啥?效率高。
3.4.4 题目
- 韩老师这题目出的挺好
- 还有这道题,不愧是韩老师,我就全贴过来了
3.5 赋值运算符
将某个运算后的值赋给指定的变量
3.5.1 一览表![image-20220522162920352](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
3.5.2 特点
细节补充:
3.6 三元运算符
3.6.1 语法
条件表达式?表达式1:表达式2;
3.6.2 运算规则
3.6.3 细节
表达式1和表达式2要是可以赋给接受变量的类型,可以自动类型转换也是行的。
3.7 运算符优先级
- 只有赋值和单目运算符是从右向左来的,
- 一览表,上 > 下
3.8 标识符
标识符就是你给类,方法,变量起的名字
-
规则
规则是必须遵守的哈
-
规范
不是必要,但是能显得更加专业
-
什么是关键字?
就是被 Java 语言赋予了特殊含义,有专门用途的英文单词
关键词中所有字母小写撒
看图(不用背,多用):
-
保留字
日后可能会晋升关键字的一群大哥
3.9 键盘输入
是什么个逻辑呢?
就是 Java 有个包里面有个 Scanner 类是专门负责这个键盘读取的。所以咱的思路就是把资源引进来,然后实例化,用实例化的对象的对应方法来读。
-
导入包中的类
import java.util.Scanner;
-
实例化这个类的一个对象
Scanner myScanner = new Scanner(System.in);
-
用这个对象的对应方法来读
int num = myscanner.nextInt();
闲谈:
为什么 new 的时候传给 Scanner 的构造器的参数是 System.in ?
System 是系统类,然后 in 是静态的,所以可以不 new 直接通过类名调用。然后 System.in 是 inputStream 中的标准输入流,用的方法是 read() ,默认是把键盘当作输入的对象。把这个作为参数传给 Scanner 就是构造出来的那个 Scanner 是从键盘读取信息的。此外的话还有System.out 是标准输出到控制台,System.erro 是错误输出
3.10 进制
这章我是菜鸡,不做过多评讲
3.10.1 介绍
- 二进制:以 0B 结尾
- 八进制:以 0 开头
- 十六进制 以 0X 开头
不区分大小写,那个以什么结尾
3.10.2 十进制转 X 进制
规制:将它不停的除以 X 直到商为 0 ,然后把余数到过来就是对应二进制了。
其他转换补充:
3.10.3 源码,反码,补码
3.10.4 位运算符
四,控制结构
4.1 有哪几种?
- 顺序控制
- 分支控制
- 循环控制
4.2 顺序控制
如同水履平地,注意变量的前向引用。也就是只能用前面有的东西。
4.3 分支控制
4.3.1 if-esle
- 单分支 if
- 双分支 if-else
- 多分支 if-else if -… -else
4.3.1.1 单分支
4.3.1.2 双分支
4.3.1.4 多分支
4.3.2 嵌套分支
就是很多 if-else 混在一起,建议别超过3层,分内外层。不然跟个俄罗斯套娃一样谁看得懂鸭对吧
4.3.3 switch
4.3.3.1 语法
4.3.3.2 流程图
4.3.3.3 细节
说一下,上图中的 2 为什么表达式不能放浮点型这种小数呢?这个其实我前面有说到的。如果 uu 你细心记得的话。是 Java 中浮点数是不等直接判断相等的。
不记得的同学转到 2.4.3 复习一下
4.3.4 if&switch 怎么选
要是区间判断或者结果是 boolean 就用 if
要是具体判断的值不多,还是 byte ,short ,int,char ,String ,enum 就用 switch
4.4 循环控制
4.4.1 for
4.4.1.1 语法
4.4.1.2 说明
4.4.1.3 流程图
4.4.1.4 注意
4.4.2 while
4.4.2.1 语法
4.4.2.2 流程图
4.4.2.3 细节
- 该说不说那个循环体中的
循环变量迭代
是我常丢的
4.4.3 do…while
4.4.3.1 语法
4.4.3.2 流程图
4.4.3.3 说明
- 根据俺的经验这个大家主动用的不多,都记得 while 去了。其实在实际开发中,这个还是挺有用的,不然它怎么还存活至今,肯定是有他的独特作用滴。用多了,你就知道它的妙处了。
4.4.4 多重循环控制
其实跟上面那个嵌套 if 分支是一个道理,只不过判断换成了循环
- 要说起来,典型的用法有九九乘法表,金字塔,冒泡排序…
4.5 跳转控制
4.5.1 break
-
适用对象:switch for while do…while
-
作用:用来结束某个语句块的执行
-
演示图
-
4.5.2 continue
-
用途:结束本次循环,继续下一次循环
-
事宜演示图
-
也可以配合标签使用
4.5.3 return
用处:跳出所在方法
五,数组
5.1 介绍
一种引用数据类型,里面存放同一类型的数据
数组?一组数据
5.2
5.2.1 动态初始化
- 其实吧,咱还是中括号跟在数据类型后面的比较多,也就是 int[ ] a;
5.2.2 静态初始化
5.2.3 细节
- 既然数组中可以放同一数据类型的引用类型,那是不是可以直接把类放到数组中呢?哎对了,一定程度上这是可以的。但是类是是抽象的没有实体,根据 同一个类实例化的对象就可以放在数组中。
- 数组它本身不也是引用类型嘛?所以数组元素也可以放数组,是不是打开了新世界的大门了?对这个叫高维数组。见得最多的就是二维数组。哈哈哈。其实数组数据就是对象(Object)
5.2.4 怎么理解 “数组就是对象” 这句话?
-
在 Java 数组就是对象
证据:
Object obj = new int[10];
这是个很特殊的现象。你看数组是怎么产生的
new 数据类型[]
而对象呢?new 类名()
。是不是有着异曲同工的蛛丝马迹。 -
数组的父类就是
Object
,数组不是由某个类实例化过来的,而是直接由 JVM 指令创建的,这个直接创建对象的父类就是Object
,所以数组可以调用Object
中的所有方法,这也是论证依据。 -
数组不仅自己是对象,也是对象集合。它里面的元素不是可以是任何数据类型嘛?那引用数据类型也是数据类型,类就是一种引用类型,故数组中可以放类。但类是抽象的,所以只能放类的实例化的东西,什么?由类构成的对象!
-
其实数组刚诞生的时候就是 Object 的对象,他里面元素就是一个个的 Object ,是
null
。然后在指定了数据类型后,每个元素的初始值才变成了对应数据类型的初始值。比如制定了new int[]
,开始元素都是null
后来全是0
,再然后才是你给初始化的那些数字。而且数组名里面的值还只是那些数字的地址,它从始至终都只是在引用罢了,这是不是和对象是很像的? -
还有就是
=
。这个在基础数据类型是将值赋值给变量,但是到了引用类型是什么?是将一个对象给变量名参考引用,也就是说数组中=
是引用是地址!比如你想完整拷贝一个数组,你直接数组1 = 数组2
行吗?是行不通的。要怎么办?要一个个拷,哪怕是System.arraycopy 原理还是一个个拷。所以如果你直接把一个数组同时=
给A,B。如果 A 自己改了数组元素,他不仅会直接影响原数组,还会让 B 也跟着改变。 -
还有就是数组能直接知道里面有效元素的个数嘛?比如我这个数组容量是 100 ,其实里面只放了 10 个。除了在一个个统计一次是没办法直接得出的。
.length
获得的是数组的容量,不是元素个数。那.sizeof
呢?这个对集合可以,但是数组没有。这是不是很奇怪。 -
还有数组最多只能是 255 维,是不是又看到了 C 的影子。
5.3 数组赋值机制图
5.4 数组拷贝,反转,扩容
如果上文你看懂了,你就知道这些只不过都是开了一个新的数组,然后把旧的数组数据经过处理移植到新数组来然后 Java 的垃圾自动回收装置自动回收了旧的数组罢了。
5.5 数组排序
5.5.1 分类
- 内部排序:将需要处理的数据全加载到内部存储器中进行排序。(交换,选择,插入)
- 外部排序:数据量过大,就借助外部存储库来进行排序(合并,直接合并)
5.5.2 冒泡排序
- 解释:
- 思路:
5.6二维数组
咋个理解法?
我们以二维数组为例。不是说数组元素可以是任何数据类型吗?包括引用类型对吧,然后数组也是引用类型,那数组可以放在数组元素的位置上。
但是你用一维数组实现这个想法的时候,你会发现没法确定数据类型是什么?是
[]
嘛?[][] arr = new [][3]
这样可以吗?它报错了。那可以是 Object 嘛?因为数组的父类就是 Object 对吧。你看下图证实了这是可以的。
1
2
3
4
5
6
7
8
9
10
11 Object[] test03 = new Object[2];
test03[0] = new int[]{1, 2, 3, 5, 6};
test03[1] = new int[]{4, 5, 6};
for (int i = 0; i < test03.length; i++) {
printArray((int[]) test03[i]);
}
public static void printArray(int[] arr) {
System.out.println(Arrays.toString(arr));
}
}那还有别的办法嘛?有高维数组也可以。比如二维数组
二维数组就是存储一维数组的一维数组,啥意思就是它就是也是由一维数组组成的。就是你有没有这种疑惑,既然刚才我们用一维数组就一定程度上实现了数组元素放数组。那为啥还要整个二维数组,高维数组呢?
那我直接一个 Object 数组然后因为所有数据类型都是 Object 的子类,那我是不是可以随便放东西进去?你说这个有没有集合的影子?
那我们又回来,这个 Java 中的高维数组,二维数组存在意义是什么呢?他可不可以被替代?
我个人浅薄之见:高维数组/二维数组有自己存在的含义。发现没有,用 Object[] 这种办法实现的,每个元素是独立的,是封闭的,访问拿取难度是复杂的,需要强转。
然而二维数组虽然咱把它看成一维数组的合体容易理解,但是!它是不是像一个矩阵,它其中的元素独立程度是大于 Object[] 的。Object[] 是一行为一个封闭单位,而二维数组是一行中的一个小元素。
换言之,二维数组的数据粒度更小了,数据耦合性更低了,独立性更强了。
所以呢,这可以干些什么?我们可以利用他的每行每列中的每个元素都易于访问,去做单个数据规律性强的事情。而且它更加直观,访问更加方便。
所以说,存在还是有存在的意义的。
5.6.1 语法
-
动态初始化
-
-
这个是个很妙的做法,很高级下面的 2 就是实现这个的。
-
动态初始化之变阶不确定列数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//演示二维数组动态初始化列数不确定
//这个主要利用的就是
int[][] test04 = new int[3][];//
for (int i = 0; i < test04.length; i++) {
test04[i] = new int[i+1];
for (int j = 0; j < test04[i].length; j++) {
test04[i][j] = j+1;
}
}
for (int[] ints : test04) {
printArray(ints);
}
public static void printArray(int[] arr){
System.out.println(Arrays.toString(arr));
}
-
-
静态初始化
5.6.2 内存图
5.6.3 细节
有个好玩的我也贴过来
1 | //5.如何花样一行代码同时创建一维数组和二维数组 |
六,面向对象编程
6.0 三大特征
6.0.1 介绍
- 封装
- 继承
- 多态
6.0.2 封装
6.0.2.1 介绍
6.0.2.2 好处
6.0.2.3 步骤
注:其实也可以把带有业务逻辑的 set 放到 构造器中,这样构造器也会有验证过程,更加安全。
6.0.3 继承
6.0.3.1 需求描绘
- 当两个类有很多属性和方法是相同的,我们就可以把他们相同的提取出类做成一个父类表示他们的共性,然后让他们自己写自己的特性不需要再重新定义这些属性和方法,只需要声明继承这个父类即可。
- 好处:提高了代码复用性,扩展性,维护性,让你写的代码更接近人类思维。
6.0.3.2 示意图
6.0.3.3 语法
6.0.3.4 细节
6.0.3.5 本质
- 贴个题目:
6.0.4 多态
6.0.4.1 是什么?
-
就是说方法或者对象具有多种形态,这个是建立在封装和继承上的
-
具体的体现形式:
方法重载 - 传入不同的参数就会执行不同的方法
寓意的是状态的多样性有着一对多的意味
6.0.4.2 对象多态
-
-
前提:两个对象存在继承关系
-
向上转型:
-
向下转型:
-
注意:属性没有重写之说,属性的值看编译类型
-
instanOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或其子类型。
6.0.4.3 Java 的动态绑定机制
-
介绍:
-
代码举例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47package day02;
/**
* @author 李敏灿
* @version 1.0
*/
public class demo01{
public static void main(String[] args) {
//a 的编译类型 A, 运行类型 B
A a = new B();//向上转型
System.out.println(a.sum());//?40 -> 30
System.out.println(a.sum1());//?30-> 20
}
}
class A {//父类
public int i = 10;
//动态绑定机制:
public int sum() {//父类 sum()
return getI() + 10;//20 + 10
}
public int sum1() {//父类 sum1()
return i + 10;//10 + 10
}
public int getI() {//父类 getI
return i;
}
}
class B extends A {//子类
public int i = 20;
// public int sum() {
// return i + 20;
// }
public int getI() {//子类 getI()
return i;
}
// public int sum1() {
// return i + 10;
// }
}
6.0.4.4 应用
- 多态数组:数组定义为父类类型,里面实际保存子类类型
- 多态参数:方法定义的形参为父类类型,实参允许为子类类型
6.1 类与对象
6.1.1 类与对象的关系
-
-
-
怎么通俗的理解类和对象呢?举个例子。
高富帅
就是一个类,因为你又高又富又帅所以你
就是这个类的一个对象。
6.1.2 对象在内存中的存在形式
-
-
如何创建对象
6.1.3 类和对象的内存分配机制
6.1.3.1 Java 内存的结构分析
6.1.3.2 Java 创建对象的流程分析
- 在方法区中加载类的相关信息,属性和方法。这个阶段只会有一次
- 在堆中分配空间,进行初始化,分为默认初始化,显式初始化,构造器初始化。
- 将堆的地址赋给栈中的对象名,就指向对象
- 示意图:
6.2 类组成
6.2.1 属性
6.2.1.1 叫什么
从概念上它叫 属性,成员变量,field(字段)
咱统一叫属性
6.2.1.2 由什么组成
数据类型:包括基础数据类型,引用数据类型(数组,对象)
例如:
6.2.1.3 注意
6.2.1.4 怎么访问属性
6.2.2 方法
6.2.2.1 调用原理
6.2.2.2 好处
6.2.2.3 定义
解释:
- 形参列表:表示成员方法输入
6.2.2.4 注意
-
调用带参数的方法,对应着参数列表传入相同类型或兼容类型的参数
-
实参和形参的类型要一致或兼容,个数,顺序必须一致
-
方法不能嵌套定义
-
一个方法最多有一个返回值。想多个用数组类引用的。
-
返回类型可以是任意类型,包括基本类型和引用类型
-
有返回值必有 return
-
命名最好见名知意
-
public,protected,默认,private
-
返回数据类型
-
形参:
6.2.2.5 调用说明
其实吧,也不一定非要
对象名.方法名
来调用。静态(static)方法就可以直接类名.方法名
来用。🐶同类中直接调用还要注意一个问题就是
static
问题。如果你在 public 类中的 main 方法中调用同样写在 public 类下面的方法。不是 static 方法调不来的。因为 main 是 static 的。
6.2.2.6 传参机制
6.2.2.6.1 基本数据类型
基础数据类型,传递的是值,是值得拷贝,形参得任何改变不影响实参
6.2.2.6.2 引用数据类型
引用数据类型传递的本质是地址,可以通过形参影响实参。
其实传的也是值,不过这次的值他是个地址。所以说本质上传的是地址。
6.2.2.7 递归
递归就是方法自己调用自己,这里是比较难的,不是有句话嘛:😵
人理解迭代,神理解递归。
-
贴个老师的示意图
-
递归重要规则
-
贴个题目吧
还有个小老鼠找迷宫,汉诺塔,八皇后也都很难,都是用递归。
这章的难度不小,作者修行未果,水平不够,贴几张我老师的图,有兴趣的大佬感兴趣自行百度探索。
6.2.2.8重载
6.2.2.8.1 基本介绍
Java 中允许一个类中有多个同名方法的存在,只是要求形参列表不同。这就是重载!
6.2.2.8.2 好处
-
减轻起名烦恼
-
减轻记名烦恼
6.2.2.8.3 举例
6.2.2.8.4 注意细节
说到底只用在乎两件事:
- 函数名一样
- 形参有区别
其他的什么,返回类型,修饰符都随意
“名相等,参不同,其他不影响” 清楚不
形参有区别又指:参数类型或者个数至少有一个不一样。
你说参数名?不影响
6.2.2.9 重写
6.2.2.9.1 介绍
就是子类中有和父类一摸一样的方法(细节下面说),只有方法体不一样。我们就说子类这个方法覆盖了父类的方法,造成了方法重写。
6.2.2.9.2 细节
6.2.2.10重写&重载辨析
6.2.3 构造器
6.2.3.1 需求
就是咱想直接在创建对象的时候就直接指定这个对象的属性就发明了这个构造器
6.2.3.2语法
-
-
-
那我提个问:构造器可以被 static final abstract 修饰嘛?为什么?
-
static:JAVA中静态的东西都是属于类的,为类服务,构造函数是为了初始化对象,为对象服务。构造函数是用来生成实例,既然是实例就不是static的。这两者是相互矛盾的
-
final:构造器是不允许被继承,不允许被重写的。而 final 的作用就是防止函数被重写,所以构造器自己就有这功能,就不必画蛇添足了。
-
abstract:abstract 修饰的方法没有函数体,还要在子类中重写。然而在 new 对象的时候就会自动调用构造器,因此必须要有一个函数体(矛盾一)。此外构造器不能被重写。
-
6.2.3.3 基本介绍
6.2.3.4 注意细节
6.2.4 代码块
6.2.4.1 介绍
6.2.4.2 语法
6.2.4.3 好处/用法
6.2.4.4 细节
- static 代码什么时候用:如果有些代码必须在项目启动的时候就执行,那么我们就可以使用静态代码块来实现,这种代码是主动执行的。
6.2.5 内部类
6.2.5.1 分类
- 局部位置:局部内部类(有类名),匿名内部类(没有类名)
- 成员位置:成员内部类(没有 static),静态内部类(有 static)
6.2.5.2 介绍
6.2.5.3 语法
6.2.5.4 局部内部类
-
-
上图第二点说明:
==局部内部类不能用 public,protected,private,static修饰可以用 final 修饰==
为什么?
因为局部内部类就是一个局部变量,而局部变量本身就是一个访问权限 的设定。 只能在局部调用,也就是说局部变量的生命周期在{}之中除了这个方法外界是没办法访问你这个变量,所以不需要用任何修饰符修饰,比如private ,public protected,等但是能加final,也不能加static,静态的关键词
因为static只能修饰成员变量和成员方法,在局部变量中用static修饰,又不能直接被类调用,而static关键字就是不直接过对象而用类就可以直接调用的,所以局部变量前不能加static关键字
6.2.5.5 匿名内部类
6.2.5.6 介绍
注意啊,这也是一个对象。
6.2.5.7 插眼
具体?lambda?
6.2.5.6 成员内部类
6.2.5.7 介绍
这里要特殊补一句的就是:这个成员内部类怎么得到它实例化的对象呢?需要自己在外部类中写一个公开的方法,来返回。
6.2.5.7 静态内部类
-
-
外部其他类怎么访问静态内部类
6.3可变参数
6.3.1 概念
就是 Java 中多个方法,名字相同,功能相同只是参数个数不同,就可以用封装成一个方法。用可变参数。
6.3.2 基础语法
6.3.3 注意细节
举例:
1 | int[] test05 = {1,2,3}; |
6.4 作用域
6.4.1 基本使用
思考:为什么 Java 中全局变量有默认直接用,局部变量没有默认值必须赋值后才能用?
我个人觉得哈可能会有一下几点:
首先科普一下有哪几种变量,
类变量:在类内方法外,带有 static 修饰。是一个类共用的。存在于内存中的方法区,类一加载就会对它初始化。有默认值,可以不赋值。
属性(成员变量): 在类内方法外,没有 static 修饰。每个类实例化的对象各不相干,各不相同。存在于堆中,一实例化对象就会初始化它。有默认值,可以不赋值。
局部变量:在方法中,用方法才会加载,存在于栈中,没有默认值,局部变量可能是任意值,而不会自动初始化为某个值。(from 《Java 编程思想》)不可以不赋值就用,编译过不去。
-
存储位置。Java 中栈适合用于存储数据量少,但他查询存储速度比堆快,而堆可用于存储数据量大的,增删改查结点就比较麻烦,所以从数据量大小和访问频率来看这可能有点关系,毕竟局部变量是在用的时候直接进栈的,如果没有赋值,这个变量就没有初始值,也就没有办法操作,故局部变量要初始化。
-
赋值和取值的顺序差异。对于类变量和属性这种由类管辖的变量来说,他的赋值和取用顺序是不确定的。比如下面的代码:
1
2
3
4
5
6public class Test {
public String name;
public void AAA() {
System.out.println("AAA name=" + name);
}
}这里
name
的赋值可以发生在 AAA 之前也可以发生在 AAA 之后,这是运行时决定的,是 JVM 来管的。javac编译的管不着的,也拿捏不住根本。就像你用这个
Test
类实例化了一个对象,你就只是想调用 AAA 方法你直接new Test().AAA()
,这个顺序是不是就不是常规的顺序结构了。但是局部变量不一样,你看下面这个,编译器直接说必然是顺序结构,必须先定义赋值后访问。
1
2
3
4public void AAA() {
String myname = "张三";
System.out.println("AAA name=" + myname);
}-
目的和安全考虑。局部变量是拿来做运算的的,做运算如果不人为给定,逻辑不同。因此,为局部变量设置默认值不是一个好主意。否则,检查意外答案的原因非常困难且耗时。“我无法提出一个有效的理由使编译器将所有未初始化的变量初始化为0” gosling 如是说。
-
防止编程人员出错。在《Java 编程思想》中有提到这个,
语言设计者觉得人是不可靠的,这样做是为了大家不容易出现错误,他觉得这是对程序员的一种约束限制。C++ 就没有这个问题。
-
其实还有…额,作者能力有限,就说到这。希望更有能力的看官朋友们在评论区补充。
-
6.4.2 注意事项
6.5 关键字
6.5.1 this
6.5.1.1解释
JVM 给每个对象分配 this ,代表当前对象。
简单来说,那个来调用,this 就代表哪一个对象
6.5.1.2 注意
-
-
-
其实吧,这个是用来处理函数中,形参和类中的全局变量一样的情况。你要是代码块中没有和类中的全局变量没有同名的,你用这个的次数很少的。但是有些函数和特殊地方还是有用。
6.5.2 super
6.5.2.1 介绍
super 代表父类的引用,用于访问父类的属性,方法,构造器。
6.5.2.2 语法
6.5.2.3 注意细节
- 访问属性/方法的规则:
6.5.3 两者比较
6.5.4 final
6.5.5 介绍
6.5.6 细节
-
-
-
问:final 和 static 搭配不会使类加载的原理是什么?怎么理解?
严格来说应该是当他们两个同时修饰基础数据类型或者 String 时可以这样。
final 是在 运行时候加载的;static 是在 类信息加载时候初始化的。然而当 final 和 static 一起的时候,类加载的准备阶段就初始化了。
具体过程:Java 中有个属性叫 ConstantValue,他是通知 JVM 自动给 static 变量赋值的。只有同时被 static 和 final 修饰才会挂上这个属性。Java 是解释性语言,在运行的时候有这个几个阶段:首先是写好的源码
.java
文件然后javac
编译成.class
字节码文件,然后再java
运行在 JVM 上跑起来。跑的第一步就是 类加载的准备,然后再是类加载,再初始化,再进main
方法。而当你是 static final 双 buff 变量,在
javac
编译的时候就会给你生成 ConstantValue 属性,然后在类加载的准备时机便会根据这个 ConstantValue 属性给变量设置相应的值。所以在 类加载前这些事就整完了,所以它两搭配的变量访问不会引起类加载。
“老师我还有一个问题?为什么ConstantValue的属性值只限于基本类型和string?”
因为从常量池中只能引用到基本类型和String类型的字面量
其实还有原因……额我的能力有限就讲到这,欢迎各位更有实力的朋友在评论区补充。
-
6.6 包
6.6.1 作用
- 区分同名类
- 当类很多时方便管理类
- 控制访问范围
6.6.2 基本语法
6.6.3 本质
本质就是个文件夹来存放类
6.6.4 命名
- 规则:只能包含字母,数字,下划线,小圆点。但是不可以数字开头,不可以是保留字或者关键字。
- 规范:一般是小写字母加小圆点。例如:com.公司名.项目名.业务模块名
6.6.5 常用包
6.6.6 怎么引入包
其实吧,推荐那种用什么类就专门引用这个包下面的一个类。
6.6.7 注意细节
6.7 访问修饰符
主要加方法或属性前面,表示访问权限(范围)
6.7.1 基本介绍
6.7.2 一览图 (很重要)
-
-
这里面难就难在中间两个(protected,默认)不同包的子类的处理上。
比如
protected
,我问你是不是不同包就不能访问?不是的。比如有个不同包的子类,它是能访问的。又比如
默认
,那我再问你:是不是所有子类都不能访问? 不是的,同包子类就是可以访问的。所以说我们怎么理解?总结一下
- 使用protected修饰后方法、变量在同一包中都为可见的(main函数中需先实例化);而在不同包中只有在子类中可见
- 默认修饰后,只要在本包内任何的都可见
6.7.3 注意细节
6.8 Object 类详解
6.8.1 equals
-
-
注意:第五条的意思是,一般 equals 对于引用类型默认还是判断地址是否相等,但是 Integer String 给你重写好了,它两是判断内容是否相等的。
-
怎么重写:用方法重写,然后把每个内容比较一遍就可以知道等不等了。(一般来说在 IDEA 下直接打个 equals 回两下车就行,当然能自己理清逻辑写下也是极好的。)
6.8.2 hashCode
-
是什么
《对象地址替代品》
-
小结
6.8.3 toString
- 介绍
- 注:
- 重写 toString 方法,打印对象或拼接对象时都会自动调用该对象的 toString 方法
- 当直接输出一个对象时,toString 会被默认的调用
- 当然了,一般我们都喜欢重写这个方法来打印对象属性,IDEA 中快捷键,或者你输入 toString 他就会给你补全了。
6.8.4 finalize
这个在实际开发中很少用的哈。更多是为了应付面试。
6.9 类变量/类方法
6.9.1 类变量
6.9.1 介绍
6.9.2 语法
6.9.3 访问
6.9.4 细节
6.9.2 类方法
6.9.2.1 介绍
6.9.2.2 调用
6.9.2.3 适用场景
所以说是把一些常用的工具类做成静态的,然后就可以不实例化对象直接用,就很方便,比如 Math 这些。
6.9.2.4 细节
6.9.3 单例设计模式
6.9.3.1 设计模式是什么
6.9.3.2 单例设计模式又是什么
6.9.3.3 实现方式
-
-
饿汉式就是直接在开头那个 static 就直接给你 new 了对象
懒汉式是在开头给你 static 时 只是声明对象名,在公开的返回对象的方法中判断要是没有 new 就给你 new。new 了就不给 new 了。
6.9.3.4 代码演示
1 | package day03; |
6.9.3.5 比较
6.10 main 方法详解
6.10.1 说明![image-20220524192714496](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
6.10.2 细节![image-20220524192740454](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
6.10.3 IDEA 中怎么给 main 传参
6.11 抽象类
6.11.1 介绍
6.11.2 细节
6.11.3 模板设计模式
6.11.3.1 介绍
6.11.3.2适用
6.12 接口
6.12.1 介绍
6.12.2 场景
6.12.3 注意
-
-
-
证明:
1 | package day03; |
-
为什么 Java 中接口中的属性默认是 static 加 final?
接口的地位相当于一个合同,一个模板,一种规范。
static:是 static 是考虑未来子类中也会有 static 方法,要是不是 static 属性,那些子代被 static 修饰的就不能访问这个了。这样设计能最大限度发挥接口的属性的功能?
final:如果这里的变量不是 final 的,并且接口中的方法都是 abstract 的, 那我想修改类就得实现类,这违背了接口的设计初衷。而且接口就是一种规范,后面子类都得按这个做事,怎么呢想改就改了。
6.12.4 怎么理解接口和抽象类
6.12.5 接口多态的体现
也就是编译类型为接口的变量可以被赋予实现了这个接口的其他类的实现对象。
七,枚举&注解
7.1 枚举
7.1.1 介绍
7.1.2 实现方式
7.1.3 自定义枚举
-
原理
-
实操演示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43package day03;
/**
* @author 李敏灿
* @version 1.0
* 演示枚举
*/
public class CustomEnumeration {
public static void main(String[] args) {
Season season1 =Season.FALL;
System.out.println(season1);
}
}
class Season{
private String season;
private String des;
public static final Season SPRING = new Season("春天","万物复苏");
public static final Season SUMMER = new Season("夏天","热烈火热");
public static final Season FALL = new Season("秋天","天高气爽");
public static final Season WINTER = new Season("冬天","白雪皑皑");
private Season(String season, String des) {
this.season = season;
this.des = des;
}
public String getSeason() {
return season;
}
public String getDes() {
return des;
}
public String toString() {
return "Season{" +
"season='" + season + '\'' +
", des='" + des + '\'' +
'}';
}
} -
关键
7.1.4 enum 关键字枚举
7.1.4.1 介绍
7.1.4.2 代码演示
1 | package day03; |
7.1.4.3 Enum方法
7.1.4.4 enum 实现接口
7.5 注解
7.5.1 理解
7.5.2 常用注解
7.5.3 Override
7.5.4 Deprecated
7.5.5 SuppressWarnings
7.5.6 元注解
7.5.6.1 介绍
解释修饰其他注解的注解
7.5.6.2 种类
7.5.6.3 @Retention
7.5.6.4 @Target
7.5.6.5 @Documented
7.5.6.6 @Inherited
八,异常
8.1 概念
在 Java 语言中,程序执行中发生的不正常情况称之为“异常”。(开发过程中的语法错误和逻辑错误不是异常)
8.2 异常体系图
8.2.1 图
8.2.1 小结
8.3 运行时异常
空指针:要用的对象是空的
数学运算:比如除以 0 这种
数组下标越界:数组下标小于 0 或者大于数组容量
类型转换:本来人家是 String 你非要转 double
数字格式错误:当应用程序试图将字符串转换成一种数值类型, 但该字符串不能转换为适当格式时, 抛出该异常 => 使用异常我们
可以确保输入是满足条件数字. (Integer.parseInt)
8.4 编译异常
8.4.1 介绍
8.4.2 常见罗列
8.5 异常处理
8.5.1 介绍
8.5.2 方法
8.5.3 示意图
- try-catch
- throws
8.6 try-catch
8.6.1 说明
8.6.2 注意
8.7 throws
8.7.1 介绍
8.7.2 细节
8.8 自定义异常
8.8.1 概念
8.8.2 步骤
8.8.3 演示
-
结果图:
-
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package day03;
/**
* @author 李敏灿
* @version 1.0
*/
public class ExceptionDemo {
public static void main(String[] args) {
if (!(1 < 0)) {
throw new IntTest("这是不对的");
}
}
}
class IntTest extends RuntimeException {
public IntTest(String message) {
super(message);
System.out.println(message);
}
}
8.9 throw&throws
九,常用类
这章有很多设计底层的东西,比较难
9.1 包装类
9.1.1 分类
包装类就是针对八种数据类型的引用类型——包装类
如图:
9.1.2 包装类和基本数据类型的转换
-
-
-
Integer 和 Character 常用方法
9.1.3 一个面试题
就是自动装包的原理是什么?
-
自动装包底层用的还是那个
Integer.valueOf()
.我们来看看他的源码是什么1
2
3
4
5
6
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}从上面
Integer valueOf()
源码可以知道:当传入数字再一个范围内的话就是直接返回IntegerCache.cache
这个数组中的元素,要是不在这个范围就是直接 new 了。那这个IntegerCache.cache
又是个怎么样的数组呢?再追一次源码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}大家看出来了吗?这个
IntegerCache.cache
其实就是一个依次从 -128~127 的一个 Integer 数组。所以我们能得出什么结论:==当自动装包的数字在 -128~127 中的时候其实返回来是从一个固定的数组中返回的,如果数字是同一个返回的就是同一个对象。如果出了这个范围他就会自己直接 new 一个。== -
代码验证一下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30package day04;
/**
* @author 李敏灿
* @version 1.0
*/
public class PackagingClass01 {
public static void main(String[] args) {
//1.直接 new 的坑定不同
Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
System.out.println(i1 == i2);//false
//2,自动装箱用的是 valueOf 方法。分情况
//-128~127 是相等的,出了这个范围就不是
Integer i3 = 1;
Integer i4 = 1;
System.out.println(i3 == i4);//true
System.out.println(i1 == i3);//false
Integer i5 = 127;
Integer i6 = 127;
System.out.println(i5 == i6);//true
Integer i7 = -128;
Integer i8 = -128;
System.out.println(i7 == i8);//true
Integer i9 = 128;
Integer i10 = 128;
System.out.println(i9 == i10);//false
}
} -
还有一个细节就是
==
两边有一个基本数据类型比较的就是值是否相等。==
比较的是什么前面的笔记说的很清楚了哈,不记得要回顾。演示代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package day04;
/**
* @author 李敏灿
* @version 1.0
*/
public class PackagingClass02 {
public static void main(String[] args) {
Integer i = 128;
Integer i2 = new Integer(128);
int i1 = 128;
System.out.println(i == i1);//true
System.out.println(i2 == i1);//true
}
}
9.2 字符串
9.2.1 String
9.2.1.1 介绍
这张图为 char[]
怎么转String
提供了一套有效的思路。
9.2.1.2 创建方式
-
直接赋值
String s = "你好啊朋友";
-
调用构造器
String s = new String("你好啊朋友");
9.2.1.3 两种创建区别
-
-
出道小题目:
-
9.2.1.4 特性
-
String 是一个 final 类,代表不可变的字符序列
-
字符串是不可变的。一个字符串对象一旦被分配,他的==内容==是不可变的。(==字符串指向可以变==)
-
补充:这个在其他语言有自己的表现形式,比如同样是做 Android 开发的另一门语言 Kotlin 中就是用
val
不可变变量来做这个。具体什么意思呢?就是我这个String s = "hello";
一旦字符串赋给了字符串变量。字符串的==内容==就不可以变辣。不能说hello
自己变成了Hello
。但是s
变量指向可以变,比如又指向了HaHaHa
.这个过程创建了两个字符串对象,然后这个变量指向从第一个换成了第二个。字符串对象自己是没有变的。所以他这里的不可变是指==字符串对象的内容不可变,但是字符串变量的指向可变==。 -
出个题目:
9.2.1.5 常用方法
-
-
concat 是拼接字符串
这些要用的时候直接查就可以了
9.2.2 StringBuffer
9.2.2.1 介绍
就是内容可以变的 String
9.2.2.2 VS String
-
区别
-
怎么转换
-
String -> StringBuffer
-
StringBuffer->String
-
9.2.2.3 常见方法
- 增:append(加的东西)
- 删:delete(x,y) [x,y)的字符
- 改:replace(x,y,”AAA”) 用 AAA 替换 [x,y) 处的字符
- 查找第一出现索引 indexOf()
- 插入 insert(x,”AAA”) 把 AAA 插入在索引 x 处,原本的后移
- length 长度
问个小问题:String s = null;请问append 这个输出什么?
答案:“null”理由在源码。
9.2.3 StringBuilder
9.2.3.1 介绍
9.2.4 三者
- 比较
- 选择
9.3 Math
9.3.1 介绍
这里面都是执行基本数学运算的方法,均为静态方法。需要就查下 API
9.3.2 方法图
- abs 绝对值
- pow 求幂
- ceil 向上取整
- floor 向下取整
- round 四舍五入
- sqrt 求开方
- random 求随机数 [0,1)
- max/min 最值
9.4 Arrays
9.4.1 介绍
这里也是一些静态方法,用于管理或操作数组
9.4.2 具体
9.5 System
9.5.1 罗列
9.6 大数
9.6.1 介绍
9.6.2 常用方法
9.7 日期
9.7.1 第一代日期 Date
-
一览图
-
代码演示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31package day04;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author 李敏灿
* @version 1.0
* 演示第一代日期
*/
public class DateTimeDemo1 {
public static void main(String[] args) throws ParseException {
//1.Date
//直接这样 new 是返回当前时间,外国格式
Date date = new Date();
System.out.println(date);
//这样是用秒数去换算是什么时候
Date date1 = new Date(989989);
System.out.println(date1);
//2.SimpleDateFormat
//设置格式,注意字母是有规定的
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy 年 MM 月 dd 日 hh:mm:ss E");
String s = simpleDateFormat.format(date);
System.out.println("进行了格式化的时间\n"+s);//将原来的 Date 转了格式输出
String s1 = "2018 年 09 月 23 日 09:23:09 周一";
System.out.println(simpleDateFormat.parse(s1));//也可以把符合规范的 String 转为 Date
}
}
9.7.2 第二代日期 Calendar
9.7.2.1 介绍
9.7.2.2 代码演示
1 | package day04; |
9.7.3 第三代日期
9.7.3.1 出生背景
9.7.3.2 介绍
9.7.3.3 代码详讲
1 | package day04; |
9.7.3.3 格式日期类
9.7.4 时间戳
-
-
package day04; import java.time.Instant; import java.util.Date; /** * @author 李敏灿 * @version 1.0 * 演示时间戳 */ public class DateTimeDemo4 { public static void main(String[] args) { //1.时间戳 Instant now = Instant.now(); System.out.println(now); //2.时间戳转 Date Date from = Date.from(now); //3.Date 转 Instant Instant instant = from.toInstant(); } }
为什么会有这种情况?难道是烂哥又说错了?不是啊 这个 Map 中真的只能放引用类型哈,这里之所以能过还能打出来。是因为他给你自动包装了:`int -> Integer,double -> Double`。这样就是引用类型了。你以为你用的是基础类型其实人家给你包成了引用类型哈。不信你看下图,我加上泛型指定后问题就暴露出来了。 ![image-20220527120217257](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527120217257.png) 用基础类型的直接给你报错,换成包装类就好了。故得证 ==Map 中两个都得用引用类型==。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
## 十,集合
### 10.1 引入
![image-20220526170846404](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526170846404.png)
### 10.2 介绍
![image-20220526171005081](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526171005081.png)
### 10.3 框架
1. ![image-20220526171041219](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526171041219.png)
2. ![image-20220526171125147](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526171125147.png)
### 10.4 Collection
#### 10.4.1 特点
![image-20220526171751067](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526171751067.png)
#### 10.4.2 接口方法
1. add 添加单个元素
2. remove 删除指定元素
3. contains 查找元素是否存在
4. size 获取元素个数
5. isEmpty 判断是否为空
6. clear 清空
7. addAll 添加多个元素
8. containsAll 查找多个元素是否存在
9. removeAll 删除多个元素
#### 10.4.3 遍历
##### 10.4.3.1 迭代器 Iterator
1. 基本介绍
![image-20220526172253496](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526172253496.png)
2. 执行原理
![image-20220526172402666](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526172402666.png)
3. 快捷键 `itit`。(显示所有快捷键:Ctrl + j)
##### 10.4.3.2 增强 for 循环
![image-20220526173546544](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526173546544.png)
### 10.5 List
#### 10.5.1 基本介绍
![image-20220526174505304](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526174505304.png)
#### 10.5.2 方法
1. add 添加
2. get 获取
3. remove 移除
4. indexOf 返回查找元素的位置
5. lastIndexOf 上面一样不过是最后一个
6. set 替换
7. subList 返回某段位置的子集合
### 10.6 ArrayList
1. 注意![image-20220526181246356](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526181246356.png)
2. 底层源码
- ![image-20220526181417539](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526181417539.png)
- 示意图:![image-20220526192804650](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526192804650.png)
![image-20220526192824518](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526192824518.png)
### 10.7 Vector
#### 10.7.1 介绍
![image-20220526192930493](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220526192930493.png)
#### 10.7.2 源码
这里的源码解析过于复杂,略过,后面有时间了再补起来。
#### 10.7.3 比较
ArrayList 和 Vector 比较
![image-20220527105631312](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527105631312.png)
### 10.8 LinkedList
#### 10.8.1 说明
![image-20220527105739738](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527105739738.png)
#### 10.8.2 底层操作
![image-20220527110003876](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527110003876.png)
#### 10.8.3 源码解析和演示
难度有点深后面再加
#### 10.8.4 比较
![image-20220527111346938](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527111346938.png)
### 10.9 Set
#### 10.9.1 介绍
![image-20220527111908678](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527111908678.png)
没有索引就不能使用索引来获取
### 10.10 HashSet
#### 10.10.1 介绍
![image-20220527112250780](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527112250780.png)
#### 10.10.2 底层机制
1. ![image-20220527113140512](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527113140512.png)
2. ![image-20220527113231272](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527113231272.png)
3. 以上的源码具体分析有点深,后面再研究吧。这里略过了。
4. HashSet 扩容机制和转成红黑树机制
![image-20220527113729287](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527113729287.png)
### 10.11 LinkedHashSet
#### 10.11.1 介绍
![image-20220527113917333](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527113917333.png)
#### 10.11.2 底层机制
![image-20220527114009094](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527114009094.png)
### 10.12 Map
#### 10.12.1 特点
1. ![image-20220527115218079](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220527115218079.png)
2. 细节讨论:这里说一下,就是第二点。他说全得是引用类型。但是你会发现俺就用基础数据类型好像也没事也能用哈。如下图:
```java
package CollectionsDemo1;
import java.util.HashMap;
/**
* @author 李敏灿
* @version 1.0
* 验证 Map 中能不能放基础数据类型
*/
public class demo01 {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put(1.1,1);
System.out.println(map.get(1.1));//1
}
} -
10.12.2 常用方法
- put 添加
- containKey 查看键是否存在
- 其他的重合了,不必多说,这个用的时候直接查就行。
10.12.3 遍历方法
这个有点特殊
一般来说咱都喜欢 2 和 4 .
- 代码演示:
1 | package CollectionsDemo1; |
- 运行截图:
10.13 HashMap
10.13.1 介绍
10.13.2 底层
-
-
-
源码剖析
这里暂时省略他的底层源码分析和扩容机制
10.14 Hashtable
- 介绍
- 对比
10.15 Properties
- 介绍
10.16 Collections 工具类
10.16.1 介绍
10.16.2 方法
- 对于 List
10.17 开发中怎么选
10.18 TreeMap&TreeSet
- TreeSet 好像可以自己传比较器进去让元素有顺序,默认无序
- 其他的后面补充
十一,泛型
11.1 背景
比如我们想给 ArrayList 中加一些 dog 对象,并遍历出来。我们会面临两个问题:1. 可能会误加其他类型的对象进去集合;2. 遍历的时候必须进行向下类型,影响效率。泛型就可以解决这个问题。
11.2 好处
11.3 介绍
就是让泛型成为一种数据类型,然后在此类中可以使用。和普通的类型地位相同,至于之歌泛型 E 到底是什么。由实例化时候直接指定。
11.4 语法
- 声明
- 实例化
11.5 注意
实际开发中建议前面有后面没有,这是一种简写。
11.6 自定义泛型
-
解释一下数组和静态那两条:
数组初始化需要 new 但是还不确定具体类型是什么,所以只能声明不初始化
静态这些东西都是类初始化的时候做的,然而泛型的具体确定要等到你实例化那个类,时间逻辑相悖。
-
11.7 继承和通配符
第一个是不行的哈,泛型没有继承性
十二,多线程
12.1 相关概念
- 程序
- 进程
- 线程
- 单线程/多线程
- 并发/并行
12.2 线程
理解:
12.2.1 创建
12.2.2 Thread
12.2.2.1 代码演示
1 | package day05; |
12.2.2.2 分析详解:
-
sleep:这个在非主线程直接写
sleep(毫秒数)
是可以的,但是 main 中必须Thread.sleep(毫秒数)
-
run&start :这个直接 run() 还是在 main 线程中,只是单纯的调用了那个类中的那个方法。会堵塞在那个 run 方法中,执行完才会继续执行 main 中后面的东西;但是 start 是重新给 那个 Cat 类开了它自己的线程,然后 main 线程照样执行。所以控制台的效果就是他两轮流执行。
用 run():
用 start() :
-
start() 原理是什么?
start() -> start0() -> run()
所以它实际最后还是调用了 run() 这个办法,区别就是前面调用了 start0() 这个方法,这个方法是本地方法,是 JVM 调用的,底层用 C/C++ 实现,是它给你开新线程的,开了新线程并不是立马运行的,开了只是给你生成了,准备了将新线程变成了可运行状态,具体什么时候跑起来,取决于 CPU,由这个老哥统一调度。
12.2.3 Runnable
12.2.3.1 说明
也没啥子不同的就是要把那个继承了 Runnable 接口的类的对象用个 Thread 包起来然后再 start
代码:
1 | package day06; |
12.2.4 两者区别
12.2.5 线程终止
演示:
1 | package day06; |
12.2.6 常用方法
-
-
-
演示一下怎么线程插队:
上代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36package day06;
/**
* @author 李敏灿
* @version 1.0
* 演示线程插队
*/
public class demo3 {
public static void main(String[] args) throws InterruptedException {
Bird bird = new Bird();
Thread thread1 = new Thread(bird);
thread1.start();
for (int i = 0; i < 20; i++) {
System.out.println("我是 main 不许你嘻嘻哈哈");
Thread.sleep(1000);
if (i == 4) {
thread1.join();
}
}
}
}
class Bird implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("叽叽喳喳哈哈哈哈");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} -
守护线程
12.3 生命周期
12.3.1 线程状态
12.3.2 状态转换图
12.4 线程同步
12.4.1 介绍
12.4.2 具体方法
12.4.3 原理
12.4.4 代码演示
1 | package day06; |
12.5 锁
12.5.1 互斥锁
12.5.1.1 介绍
12.5.2 死锁
12.5.3 释放锁
- 释放锁操作:
- 不会释放锁的操作:
十三,IO流
13.1 文件流
13.2 文件操作
13.2.1 创建文件
-
概述
-
代码演示:
-
package day06; import java.io.File; import java.io.IOException; /** * @author 李敏灿 * @version 1.0 * 文件创建 */ public class demo5 { public static void main(String[] args) throws IOException { //1. 直接全路径创建路径 String filepath = "C:\\Users\\Micenlee李敏灿\\Desktop\\hello.txt"; File file = new File(filepath); file.createNewFile(); //2.父文件+子名字 File file1 = new File("C:\\Users\\Micenlee李敏灿\\Desktop\\"); String sonfilepath = "hello1.txt"; File file2 = new File(file1, sonfilepath); file2.createNewFile(); //3.父目录 + 子目录 String fatherfilepath = "C:\\Users\\Micenlee李敏灿\\Desktop\\"; String sonfilepath1 = "hello2.txt"; File file3 = new File(fatherfilepath, sonfilepath1); file3.createNewFile(); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
成功截图:![image-20220528201900237](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220528201900237.png)
#### 13.2.2 获取文件信息
1. 介绍![image-20220528202017865](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220528202017865.png)
2. 代码演示:
3. ```java
package day06;
import java.io.File;
import java.io.IOException;
/**
* @author 李敏灿
* @version 1.0
* 演示 文件信息查询
*/
public class demo6 {
public static void main(String[] args) throws IOException {
//先创建文件对象
File file = new File("C:\\Users\\Micenlee李敏灿\\Desktop\\news1.txt");
//调用相应的方法, 得到对应信息
file.createNewFile();
System.out.println("文件名字=" + file.getName());//文件名字=news1.txt
System.out.println("文件绝对路径=" + file.getAbsolutePath());//文件绝对路径=C:\Users\Micenlee李敏灿\Desktop\news1.txt
System.out.println("文件父级目录=" + file.getParent());//文件父级目录=C:\Users\Micenlee李敏灿\Desktop
System.out.println("文件大小(字节)=" + file.length());//文件大小(字节)=0
System.out.println("文件是否存在=" + file.exists());//T
System.out.println("是不是一个文件=" + file.isFile());//T
System.out.println("是不是一个目录=" + file.isDirectory());//F
}
}
13.2.3 目录操作
13.3 IO 流原理及流的分类
13.3.1 Java IO 流原理
13.3.2 流的分类
13.4 IO 流体系图
13.4.1 IO 流体系图
13.4.2 文件 VS 流
13.5 FileInputStream
字节输入流 文件 -> 程序
演示:
1 | package day06; |
13.6 FileOutputStream
13.6.1 介绍
13.6.2 代码演示
1 | package day06; |
13.7 FileReader&FileWriter
13.7.1 介绍
13.7.2 相关方法
-
FileReader
-
FileWriter
-
注意:这个 FileWriter 写完之后记得刷新
13.7.3 代码演示
这里演示的是利用 FileReader 从一个文件中读取出来然后用 FileWriter 追加带另外一个文件中去
1 | package day06; |
13.8 节点流和处理流
13.8.1 介绍
13.8.2 一览表
13.8.3 区别与联系
13.8.4 处理流功能
13.8.5 处理流
13.8.5.1 BufferedReader&BufferedWriter
代码实现:
1 | package day06; |
13.8.5.2 BufferInputStream&BufferOutputStream
-
介绍:
可以拿这两个便捷的拷贝音视频文件
-
代码演示利用这两个处理流来拷贝音视频:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51package day07;
import java.io.*;
/**
* @author 李敏灿
* @version 1.0
* 演示用处理流拷贝音视频文件
*/
public class demo1 {
public static void main(String[] args) {
//1. 把路径,流准备好
String fromPath = "C:\\Users\\Micenlee李敏灿\\Desktop\\AAA.mp4";
String toPath = "C:\\Users\\Micenlee李敏灿\\Desktop\\BBB.mp4";
//2. 提前声明流,方便 finally 中关闭
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
byte[] readDate = new byte[1024];
int readLen = 0;
try {
//3. 流的初始化
bis = new BufferedInputStream(new FileInputStream(fromPath));
bos = new BufferedOutputStream(new FileOutputStream(toPath));
while ((readLen = bis.read(readDate))!= -1){
bos.write(readDate,0,readLen);
bos.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis!=null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
13.8.6 对象流
13.8.6.1 序列化和反序列化
13.8.6.2 对象流
13.8.6.3 注意
13.8.6.4 代码演示
1 | package day07; |
23行为什么要加一个 flush 的解释:
如果不加他就会报 EOFException
这个的原因还是上一篇说的 flush 原理,因为 Object 对象流还是处理流,有哪个缓存区机制,如果 23 行没有那个 flush 。你是 write 了然后就 read ,可能有东西还在缓存区没写进去,你就去读。不就是读到异常结尾了,就给你蹦出来一个 EOFException。如果你 write 完了,及时的 flush 了,或者把那个 close 提到你 read 之前他就解决了。
13.8.7 标准输入输出流
13.8.7.1 介绍
13.8.8 转换流
13.8.8.1 背景
一般来说 Java 中默认读取文件字符是按 UTF8 来读的,当文件是这种类型的一点问题没有。但是如果读取的文件是 gbk 或者其他格式,再按默认的去读就会出乱码。如下图:
解决办法,用字节流读取可以指定读取的格式,然后用字符包装类可以高效读取。那用转换类中间弄一下就可以又解决中文乱码问题又可以高效读取了。这就是转换流存在的意义。
13.8.8.2 介绍
13.8.8.3 代码演示
1 | package day07; |
结果图:
13.8.9 打印流
-
介绍
打印只有输出流,没有输入流。就 PrintStream 字节打印流和 PrintWriter 字符打印流。
-
代码演示:
两个差不多,唯一的区别就是字节和字符。这里我们用字节打印流演示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package day07;
import java.io.FileNotFoundException;
import java.io.PrintStream;
/**
* @author 李敏灿
* @version 1.0
* 字节打印流
* PrintStream
*/
public class demo6 {
public static void main(String[] args) throws FileNotFoundException {
String path = "C:\\Users\\Micenlee李敏灿\\Desktop\\hello.txt";
PrintStream printStream = new PrintStream(path);
printStream.print("你还好吗朋友");//这里是向桌面的 hello.txt 输入
printStream = System.out;//这个改变了字节打印流,成了向控制台输出
System.out.println("我很好,谢谢你");
printStream.close();//记得关闭刷新,不然写不进去哦
}
}结果图:
13.9 Propoties
13.9.1 引入
13.9.2 介绍
13.9.3 代码演示
-
写:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package day07;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
/**
* @author 李敏灿
* @version 1.0
* 写 Properties 配置文件
*/
public class demo7 {
public static void main(String[] args) throws IOException {
String path = "C:\\Users\\Micenlee李敏灿\\Desktop\\hello.properties";
Properties properties = new Properties();
properties.setProperty("age","19");
properties.setProperty("name","李敏烂");
properties.setProperty("height","187");
properties.store(new FileWriter(path),"我演示给大家看的一个实验");
}
}结果图:
-
读:
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package day07;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;
/**
* @author 李敏灿
* @version 1.0
* 读 properties
*/
public class demo8 {
public static void main(String[] args) throws IOException {
String path = "C:\\Users\\Micenlee李敏灿\\Desktop\\hello.properties";
Properties properties = new Properties();
properties.load(new FileReader(path));
properties.list(System.out);
System.out.println(properties.getProperty("age"));
System.out.println(properties.getProperty("name"));
System.out.println(properties.getProperty("height"));
}
}结果图:
13.10 flush 详解
13.10.1 背景
我有个问题:
就是 Java 中 IO 流中的那个 flush 是干嘛的?原理是什么?什么时候用?什么时候可以不用?
13.10.2 原理
-
流的 writer 原理:Java 中 文件直接通过流 (Stream) 的方式传递,但是不同的流传递的方式还是有点不同的。比如现在通过 Java 程序去给桌面一个文件写东西进去:如果是节点流,他们 write 是直接淦目标中了;但是包装流 (Buffer 流) 他们就有个缓冲区,设计的初衷是提高读写效率,他们 write 先是写在缓冲区,满了才给写目标文件中去。
-
flush 原理:这个 flush 是干啥的呢?就是如果我们直接调用它,他就会不管缓存区有没有满,都给他淦出缓存区,强行冲一遍。注意啊,这个赶出缓存不是直接写到物理地址硬盘上,而是赶出去让操作系统来写到文件上去。这个 flush 还是个空方法。
下面是 flush 的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/**
* Flushes this output stream and forces any buffered output bytes
* to be written out. The general contract of <code>flush</code> is
* that calling it is an indication that, if any bytes previously
* written have been buffered by the implementation of the output
* stream, such bytes should immediately be written to their
* intended destination.
* <p>
* If the intended destination of this stream is an abstraction provided by
* the underlying operating system, for example a file, then flushing the
* stream guarantees only that bytes previously written to the stream are
* passed to the operating system for writing; it does not guarantee that
* they are actually written to a physical device such as a disk drive.
* <p>
* The <code>flush</code> method of <code>OutputStream</code> does nothing.
* 中文翻译:
刷新此输出流并强制写出任何缓冲的输出字节。 <code>flush<code> 的一般约定是调用它表示,如果先前写入的任何字节已被输出 流的实现缓冲,则应立即将这些字节写入其预期目的地。 <p> 如果此流的预期目的地是底层操作系统提供的抽象,例如文件,则刷新 流仅保证先前写入流的字节被传递给操作系统进行写入;它不能保证它们实际上被写入了物理设备,例如磁盘驱动器。 <p> <code>OutputStream<code> 的 <code>flush<code> 方法什么也不做。
* @exception IOException if an I/O error occurs.
*/
public void flush() throws IOException {
} -
缓冲流的 close 原理:它会先用一下 flush 然后再关流。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55/**
* Closes this output stream and releases any system resources
* associated with the stream.
* <p>
* When not already closed, the {@code close} method of {@code
* FilterOutputStream} calls its {@code flush} method, and then
* calls the {@code close} method of its underlying output stream.
*
*中文翻译:
关闭此输出流并释放与该流关联的所有系统资源。 <p> 当尚未关闭时,{@code FilterOutputStream} 的 {@code close} 方 法调用其 {@code flush} 方法,然后调用其底层输出流的 {@code close} 方法
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#flush()
* @see java.io.FilterOutputStream#out
*/
public void close() throws IOException {
if (closed) {
return;
}
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
Throwable flushException = null;
try {
flush();
} catch (Throwable e) {
flushException = e;
throw e;
} finally {
if (flushException == null) {
out.close();
} else {
try {
out.close();
} catch (Throwable closeException) {
// evaluate possible precedence of flushException over closeException
if ((flushException instanceof ThreadDeath) &&
!(closeException instanceof ThreadDeath)) {
flushException.addSuppressed(closeException);
throw (ThreadDeath) flushException;
}
if (flushException != closeException) {
closeException.addSuppressed(flushException);
}
throw closeException;
}
}
}
}
13.10.3 使用场景
Java 中有缓冲区的是 BufferedOutput 流的那些,所以在这些流每次 write 后如果想立马把缓存区的东西写到文件,以防丢失就可以用一下这个
- 其实现实开发中,如果暂时不能 close ,那就每 write 一下就 flush 一下
- 如果一定会 close 流(比如写在 finally 中),就可以不写 flush。因为它 close 前给你 flush 了。
13.10.4 错误使用演示
你要是不肯定会 close 也不 write 后就是 flush ,你写的数据就会丢失一小部分。
演示:
- 不 close 也不及时 flush -> 数据丢失
1 | package day07; |
结果图:
拷是拷成功了
但是你打开:
-
只及时 flush 不 close -> 可以
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51package day07;
import java.io.*;
/**
* @author 李敏灿
* @version 1.0
* 演示用处理流拷贝音视频文件
*/
public class demo1 {
public static void main(String[] args) {
//1. 把路径,流准备好
String fromPath = "C:\\Users\\Micenlee李敏灿\\Desktop\\AAA.mp4";
String toPath = "C:\\Users\\Micenlee李敏灿\\Desktop\\BBB.mp4";
//2. 提前声明流,方便 finally 中关闭
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
byte[] readDate = new byte[1024];
int readLen = 0;
try {
//3. 流的初始化
bis = new BufferedInputStream(new FileInputStream(fromPath));
bos = new BufferedOutputStream(new FileOutputStream(toPath));
while ((readLen = bis.read(readDate))!= -1){
bos.write(readDate,0,readLen);
bos.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// if (bos != null){
// try {
// bos.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
if (bis!=null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}结果图:
拷贝成功
打开拷贝视频可以播放,没有损坏
-
不及时 flush 但最后一定 close 了 -> 可以的
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51package day07;
import java.io.*;
/**
* @author 李敏灿
* @version 1.0
* 演示用处理流拷贝音视频文件
*/
public class demo1 {
public static void main(String[] args) {
//1. 把路径,流准备好
String fromPath = "C:\\Users\\Micenlee李敏灿\\Desktop\\AAA.mp4";
String toPath = "C:\\Users\\Micenlee李敏灿\\Desktop\\BBB.mp4";
//2. 提前声明流,方便 finally 中关闭
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
byte[] readDate = new byte[1024];
int readLen = 0;
try {
//3. 流的初始化
bis = new BufferedInputStream(new FileInputStream(fromPath));
bos = new BufferedOutputStream(new FileOutputStream(toPath));
while ((readLen = bis.read(readDate))!= -1){
bos.write(readDate,0,readLen);
//bos.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis!=null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}拷贝成功图:
打开能播放图:
13.10.5 总结
所以大家在用 处理流写东西时,如果一定能 close 流,那没啥事。但是如果不能关,记得 write 一下 flush 一下,不然数据会丢失。
13.10.6 非要做
比如现在我们非要既不及时 flush 也不 close 还想写到文件怎么办?
-
把缓存区大小改为数据大小
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package day07;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
public class demo2 {
public static void main(String[] args) throws Exception {
File file = new File("C:\\Users\\Micenlee李敏灿\\Desktop\\hello.txt");
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos,1000);//这里我把缓存区大小设置为 1 kb
byte[] b = new byte[1024];
bos.write(b);//这里我们写入 1 kb 的数据
//bos.flush();
}
}结果图:是成功的,大小为我们刚写的 1 KB
这里为啥大小和占用空间不一样鸭?为什么占用空间是 4 KB。因为硬盘最小是以 4 K 为分配单位的。大小和占用空间不一样是很正常的,硬盘分区的最小是以4k为计算单位的。 就是说好像一个一个格子一样,这些格子比较大。 即使是一个文件写了一个字,它的大小不足1k,但是显示占用空间为4k。 所以特别是一些小文件很多的东西。
-
写入文件大于缓存区默认大小(8 KB)
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package day07;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
public class demo2 {
public static void main(String[] args) throws Exception {
File file = new File("C:\\Users\\Micenlee李敏灿\\Desktop\\hello.txt");
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] b = new byte[1024*8];
bos.write(b);//这里我们写入 1 kb 的数据
//bos.flush();
}
}结果图:大小为 8 KB
-
大家思考:那在音视频我们能不能这样呢?为什么能或者不能?
答案:不能,会有丢失。原因俺也不知道,希望大家在评论区教我。
13.11 怎么关这种匿名流
题目描述:
-
在方法内部关闭。这样可以在调用这个办法结束就关闭这个匿名流,匿名流只能用一次。
-
依靠 full-gc 给你关。就是 Java 的垃圾自动装置,会在 gc 的时候给你关闭那些没有用过的流。一定程度上如果胆子大,可以就不关然后等着 JVM 给你调 full-gc 给你关。
-
用新版的 try-with-resouce 别老整这些匿名流。这个是最新的也是最优雅的关流的办法。
演示代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package day07;
import Utils.StreamUtils;
import java.io.*;
/**
* @author 李敏灿
* @version 1.0
*/
public class demo14 {
public static void main(String[] args) {
String fromPath = "C:\\Users\\Micenlee李敏灿\\Desktop\\AAA.mp4";
try (
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(fromPath))
//这里写流
) {
//操作代码块
} catch (IOException e) {
}
}
}IDEA中在 new 资源流的时候后面加个
.twr
就可以出来了凡是在 try 后面小括号中的流,只要实现了 Closeable 接口的,都可以这样关,省心又方便。
-
《Effective Java》在第三版中也推荐使用try-with-resources语句替代try-finally语句。
所以在处理必须关闭的资源时,使用try-with-resources语句替代try-finally语句。生成的代码更简洁,更清晰,并且生成的异常更有用。 try-with-resources语句在编写必须关闭资源的代码时会更容易,也不会出错,而使用try-finally语句实际上是不可能的。
如此,推荐大家使用try-with-resources优雅地关闭资源!
十四,网络编程
14.1 网络
14.1.1 网络通信
14.1.2 网络
14.1.3 ip 地址
14.1.4 域名
14.1.5 网络通信协议
- 借用下我老师的图:
14.1.6 TCP 和 UDP
14.2 InetAddress 类
14.2.1 方法
代码演示:
1 | package day07; |
14.3 Socket
14.3.1 介绍
14.3.2 示意图
14.4 TCP 网络通信编程
14.4.1 介绍
14.4.2 代码演示
-
利用字节流来发条消息
服务端:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42package day07;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 李敏灿
* @version 1.0
* 演示 TCP 网络通信
* 服务端
*/
/*
介绍:
用字节流编写一个服务端,一个客户端。服务端在 9999 端口监听
客户端连接到服务器端,发送消息,然后退出。服务器接收到打印在控制台然后退出。
*/
public class demo10 {
public static void main(String[] args) throws IOException {
//1.开服务端,开接口监听,形成一条数据通道
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("我是服务端,在 9999 端口监听,等待连接。。。");
//2.接受客户端
Socket socket = serverSocket.accept();
System.out.println("服务端 socket ="+ socket.getClass());
//3.读取客户端写入到数据通道的数据
InputStream inputStream = socket.getInputStream();
//4.IO 读取
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf))!= -1){
System.out.println(new String(buf,0,readLen));
}
//5.关闭所有流
inputStream.close();
socket.close();
serverSocket.close();
}
}客户端:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* @author 李敏灿
* @version 1.0
* 客户端
*/
public class demo11 {
public static void main(String[] args) throws IOException {
//1. 连接服务端 (IP,端口)
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端 socket 返回"+socket.getClass());
//2.连接上,得到对应的输出写入流
OutputStream outputStream = socket.getOutputStream();
//3.通过输出流,写数据到 数据通道
outputStream.write("hello,server".getBytes());
//4.关闭流
socket.shutdownOutput();
outputStream.close();
socket.close();
System.out.println("客户端退出");
}
}结果图:
-
传照片并对话:
工具类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39package Utils;
import java.io.*;
/**
* @author 李敏灿
* @version 1.0
* IO 流的工具类
*/
public class StreamUtils {
/**
* 将输入流转换成 byte[]
*/
public static byte[] streamToByteArray(InputStream is) throws IOException {
//1.创建输出流对象
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = is.read(buf))!=-1){
bos.write(buf,0,readLen);
}
byte[] array = bos.toByteArray();
bos.close();
return array;
}
/**
* 将 InputStream 转换为 String
*/
public static String streamToString(InputStream is) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine())!=null){
stringBuilder.append(line+"\r\n");
}
return stringBuilder.toString();
}
}服务端:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43package day07;
import Utils.StreamUtils;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 李敏灿
* @version 1.0
* 传图片对话网络编程
* 服务端
*/
public class demo12 {
public static void main(String[] args) throws IOException {
//1. 服务端在本机监听 8888 端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务端在 8888 端口监听。。。");
//2.等待连接
Socket socket = serverSocket.accept();
//3.读取用户发送的数据
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
//4.将得到的 byte 数组,写到指定路径
String destPath = "C:\\Users\\Micenlee李敏灿\\Desktop\\ccc.mp4";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destPath));
bos.write(bytes);
bos.flush();
//==========向客户端回复收到消息
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("收到视频,谢谢你");
bw.flush();
socket.shutdownOutput();//这个是设置写入结束标记.网络编程必加
//关闭其他资源
bw.close();
bos.close();
bis.close();
socket.close();
serverSocket.close();
}
}客户端:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42package day07;
import Utils.StreamUtils;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* @author 李敏灿
* @version 1.0
* 传图片对话网络编程
* 客户端
*/
public class demo13 {
public static void main(String[] args) throws IOException {
//1. 连接服务端
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
//2.将文件读到 Java 程序
String fromPath = "C:\\Users\\Micenlee李敏灿\\Desktop\\AAA.mp4";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fromPath));
byte[] bytes = StreamUtils.streamToByteArray(bis);
//3.将数据打到通道中
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
bos.flush();
socket.shutdownOutput();
//====接受服务端的消息
InputStream is = socket.getInputStream();
String string = StreamUtils.streamToString(is);
System.out.println(string);
//关闭所有流
is.close();
bos.close();
bis.close();
socket.close();
}
}结果图:
14.4.3 总结
14.4.3.1 服务端写法
-
服务器开端口:
ServerSocket serverSocket = new ServerSocket(端口);
-
等待连接:
Socket socket = serverSocket.accept();
-
获取对应的输出/输入流:
socket.getInputStream()
socket.getOutputStream()
-
具体的 IO 流操作:
记得如果是输出记得加上
socket.shutdownOutput()
-
最后记得关闭所有流
14.4.3.2 客户端写法
-
连接服务端:
Socket socket = new Socket(InetAddress.getLocalHost(), 8888)
-
还是获取对应的流
-
具体操作,还是如果是 write 记得
socket.shutdownOutput()
-
关闭流
14.5 netstat 指令
14.6 UDP 网络通信编程
14.6.1 介绍
14.6.2 流程
14.6.3 代码
问题:
代码:
接收端:
1 | package day08; |
发送端:
1 | package day08; |
结果图:
十五,反射
15.1 介绍
15.2 机制原理图
15.3 反射用途
15.4 主要相关类
15.5 代码入门
1 | package day08; |
15.6 优缺点
15.7 反射性能优化
代码演示:
1 | Method method1 = aClass.getMethod(method); |
15.8 Class 类
15.8.1 介绍
15.8.2 常用方法
15.8.3 获取 Class 对象
15.8.4 那些类型有 Class 对象
15.9 类加载
15.9.1 说明
15.9.2 类加载时机
15.9.3 类加载过程图
15.9.4 类加载各个阶段完成任务
15.9.5 加载阶段
15.9.6 连接阶段-验证
15.9.7 连接阶段-准备
解释:
15.9.8 连接阶段-解析
15.9.10 初始化
15.10 通过反射获取类的结构信息
15.10.1 Java.lang.Class
getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。
getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
15.10.2 Java.lang.reflect.Field
15.10.3 Java.lang.reflect.Method
15.10.4 Java.lang.reflect.Constructor
15.11 通过反射创建对象
-
-
代码:
-
package day08; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * @author 李敏灿 * @version 1.0 * 通过反射构建实例 */ public class Reflection02 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //1. 获取到 User 类的 Class 对象 Class<?> aClass = Class.forName("day08.User"); //2.用 public 无参构造器 Object o = aClass.newInstance(); System.out.println(o); //3.用 public 有参构造器 Constructor<?> constructor = aClass.getConstructor(String.class); Object o1 = constructor.newInstance("李敏烂"); System.out.println(o1); //4.通过 private 构造器 Constructor<?> constructor1 = aClass.getDeclaredConstructor(int.class, String.class); constructor1.setAccessible(true);//爆破,将私有的限制突破。没有这个会报 IllegalAccessException Object o2 = constructor1.newInstance(19, "烂烂"); System.out.println(o2); } } class User{ private int age = 10; private String name = "Mecenlee"; public User() { } public User(String name) { this.name = name; } private User(int age, String name) { this.age = age; this.name = name; } @Override public String toString() { return "User{" + "age=" + age + ", name='" + name + '\'' + '}'; } }
结果图:![image-20220530154241721](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220530154241721.png)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
结果图:![image-20220530152047467](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220530152047467.png)
### 15.12 通过反射访问类中的成员
#### 15.12.1 访问属性
1. 介绍![image-20220530152146899](https://article-picture-resource.oss-cn-chengdu.aliyuncs.com/imags/image-20220530152146899.png)
2. 代码演示:
3. ```java
package day08;
import java.lang.reflect.Field;
/**
* @author 李敏灿
* @version 1.0
* 演示反射怎么操作属性
*/
public class Reflection03 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
//1. 得到 Student 对应的 Class 对象
Class<?> aClass = Class.forName("day08.Student");
//2. 得到实例对象
Object o = aClass.newInstance();
System.out.println(o.getClass());
//3.使用反射得到 age 属性
Field age = aClass.getField("age");
age.set(o,99);
System.out.println(age.get(o));
//4.使用反射操作 name 属性
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
name.set(null,"Jack");
//System.out.println(name.get(o));
System.out.println(name.get(null));
}
}
class Student{
public int age;
private static String name;
public Student() {
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
}
15.12.2 访问方法
-
介绍
-
代码演示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60package day08;
import com.sun.tools.javac.Main;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author 李敏灿
* @version 1.0
* 演示反射怎么访问方法
*/
public class Reflection04 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//1.获取 类对象
Class<?> aClass = Class.forName("day08.Boss");
//2.创建一个对象
Object o = aClass.newInstance();
//3.调用 public 的 hi 方法
Method hi = aClass.getMethod("hi", String.class);
hi.invoke(o, "HL");
//4.调用 private 的 say 方法
Method say = aClass.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);//直接上爆破
System.out.println(say.invoke(null, 0, "lmc", '男'));//0lmc男
//5.在反射中如果方法有返回值,统一返回 Object 。但是他的运行类型和方法定义的返回类型一致
Method m1 = aClass.getMethod("m1");
Object invoke = m1.invoke(o);
System.out.println("invoke 的运行类型=" + invoke.getClass());//invoke 的运行类型=class day08.Monster
}
}
class Monster {
}
class Boss {
public int age;
private static String name;
public Boss() {
}
public Monster m1() {
return new Monster();
}
//静态方法
private static String say(int n, String s, char c) {
return n + "" + s + "" + c;
}
//普通方法
public void hi(String c) {
System.out.println("hi~" + c);
}
}
十六,正则表达式
16.1 介绍
- 正则表达式是处理文本的利器
- 说直白一点就是,正则表达式就是对字符串值执行模式匹配的技术
16.2 底层
主要就是一个 find 和 group 源码的分析问题
代码:
1 | package day10; |
结果图:
16.3 语法
16.3.1 介绍
16.3.2 元字符
16.3.2.1 转义号 \\
16.3.2.2 字符匹配符
16.3.2.3 选择匹配符
16.3.2.4 限定符
16.3.2.4 定位符
16.3.2.5 分组
16.3.2.5.1 一览表
16.3.2.5.2 代码演示
- 命名捕获(第二个):
代码:
1 | package day10; |
结果图:
-
非命名捕获(第三个):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package day10;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author 李敏灿
* @version 1.0
*/
public class demo1 {
public static void main(String[] args) {
String content = "李敏猫1290李敏烂5545李敏狗2342";
//演示(?::pattern)的改良版
String regStr1 = "李敏(猫|烂|狗)";//李敏猫李敏烂李敏狗
//2.实例化一个正则表达式对象
Pattern pattern = Pattern.compile(regStr1);
//3.依次做个匹配器
Matcher matcher = pattern.matcher(content);
//4.开始工作
while (matcher.find()) {
System.out.println("找到什么:" + matcher.group(0));
//下面的这些不能用,因为是非捕获分组
// System.out.println("第一个()中是什么:" + matcher.group("g1"));
// System.out.println("第二个()中是什么:" + matcher.group("g2"));
}
}
}结果图:
-
正向非命名捕获(第四个)
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29package day10;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author 李敏灿
* @version 1.0
* 捕获分名字
*/
public class demo1 {
public static void main(String[] args) {
String content = "李敏猫1290李敏烂5545李敏狗2342";
//演示(?<name>pattern)
String regStr2 = "李敏(?=猫|狗)";//两个
//2.实例化一个正则表达式对象
Pattern pattern = Pattern.compile(regStr2);
//3.依次做个匹配器
Matcher matcher = pattern.matcher(content);
//4.开始工作
while (matcher.find()) {
System.out.println("找到什么:" + matcher.group(0));
//System.out.println("第一个()中是什么:" + matcher.group("g1"));
//System.out.println("第二个()中是什么:" + matcher.group("g2"));
}
System.out.println("over");
}
}结果图:
-
反向非命名捕获(第五个)
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29package day10;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author 李敏灿
* @version 1.0
* 捕获分名字
*/
public class demo1 {
public static void main(String[] args) {
String content = "李敏猫1290李敏烂5545李敏狗2342";
//演示(?<name>pattern)
String regStr2 = "李敏(?!猫|狗)";//一个
//2.实例化一个正则表达式对象
Pattern pattern = Pattern.compile(regStr2);
//3.依次做个匹配器
Matcher matcher = pattern.matcher(content);
//4.开始工作
while (matcher.find()) {
System.out.println("找到什么:" + matcher.group(0));
//System.out.println("第一个()中是什么:" + matcher.group("g1"));
//System.out.println("第二个()中是什么:" + matcher.group("g2"));
}
System.out.println("over");
}
}效果图:
16.4 应用
16.5 常用类
16.5.1 一览表
16.5.2 Pattern 类的方法
matches:整个匹配
1 | package day10; |
16.5.3 Matcher 类的方法
16.6 分组,捕获,反向引用
反向引用举例:
1 | package day10; |
16.7 正则 in String
-
-
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33package day10;
/**
* @author 李敏灿
* @version 1.0
* 演示正则表达式在 String 中的用途
*/
public class StringReg {
public static void main(String[] args) {
String content = "2000 年 5 月, JDK1.3、 JDK1.4 和 J2SE1.3 相继发布, 几周后其\" +\n" +
"\"获得了 Apple 公司 Mac OS X 的工业标准的支持。 2001 年 9 月 24 日, J2EE1.3 发\" +\n" +
"\"布。 \" +\n" +
"\"2002 年 2 月 26 日, J2SE1.4 发布。 自此 Java 的计算能力有了大幅提升";
//1. 替换
String s = content.replaceAll("JDK1\\.3|JDK1\\.4", "JDK");
System.out.println(s);
//2.验证
content = "13809098987";
if (content.matches("13(8|9)\\d{8}")){
System.out.println("验证成功");
}else{
System.out.println("验证失败");
}
// 3.分割
content = "hello#abc-jack12smith~北京";
String[] split = content.split("#|-|~|\\d+");
for (String s1 : split) {
System.out.println(s1);
}
}
} -
结果图:
十七,JDBC
17.1 介绍
17.2 获取连接
-
直接 new 的静态加载
-
用反射来动态加载
-
用DriverManager
-
Class.forName 自动完成注册
-
这个才是用的最多的
17.3 结果集
17.3.1 介绍
17.3.2 底层![image-20220601232406547](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
17.3.3 代码演示:
1 | package day11; |
17.4 Statement
演示 SQL 注入:
-
表的准备:
-
账号或者密码不对尝试-> 登不进去
-
账号密码都对就能登录那个账号:
-
SQL 注入:
账号:1’ or
密码:or ‘1’='1
就靠 SQL 注入,不知道账号密码也进去了,还是全部都暴露。
17.5 PreparedStatement
17.5.1 介绍
17.5.2 好处
17.5.3 代码演示:
1 | package day11; |
验证图:
成功:
失败:
防住了基本 SQL 注入:
17.6 API
17.7 封装JDBCUtils
代码展示:
1 | package day11; |
截图:
17.8 事务
17.8.1 总结![image-20220602092820257](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
17.8.2 说明
其实这个就是一种对语句的捆绑,要么都执行成功要么都失败。就像图中举的转账的例子,如果不用事务,假如 A 转了 100 出去,然后系统出问题了,B 没收到。那这 100 就凭空消失了。但是用了事务就不会,他会捆绑转出和接受只有两个都成功才行。
17.8.3 代码
17.8.3.1 数据库准备:
1 | 转账业务的演示 |
17.8.3.2 JDBC
不用事务结果图:
用事务结果图:
这次没有问题
代码:
1 | package day12; |
17.9 批处理
17.9.1 总结
17.9.2 实操
17.9.2.1 数据库准备
1 | CREATE TABLE admin2( |
17.9.2.2 Java 端
代码:
1 | package day12; |
不用批处理:1969 ms
用了批处理:68ms
17.10 数据库连接池
17.10.1 传统问题
17.10.2 数据库连接池种类
17.10.3 代码实操
- C3P0 两种方法
代码:
1 | package day12; |
xml 文件
1 | <c3p0-config> |
-
Druid
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39package day12;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.junit.jupiter.api.Test;
import javax.sql.DataSource;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.util.Properties;
/**
* @author 李敏灿
* @version 1.0
* Druid 数据库连接池的使用
*
*/
public class demo4 {
public void testDruid() throws Exception {
//1. 加入 Druid 包
//2.加入配置文件 druid.proper 拷贝进项目的 src 目录
//3.创建 properties 对象,读取配置文件
Properties properties = new Properties();
properties.load(new FileReader("src\\druid.properties"));
//4. 创建指定参数的 Druid 连接池
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
long start = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
Connection connection = dataSource.getConnection();
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("Druid 连接池耗时"+(end - start));//403
}
}
17.11 Apache-DBUtils
17.11.1 问题描述
17.11.2 介绍
17.11.3 代码演示
演示用 DBUtils + Druid 完成对表的 crud
1 | package day12; |
1 | //queryRunner.query 源码解析 |
17.12 DAO和常用方法
17.12.1 问题
17.12.2 说明
17.12.3 实操
成功图:
代码模板:在这个 Gitee 地址
十八,个人补充
18.1 常识
- 什么是 BAT,TMD?
BAT 指 百度,阿里,腾讯
TMD 指 头条,美团,滴滴
18.2 知新
-
每一个类编译后都有一个 .class 文件
-
可以把 main 写在非 public 类中,然后编译后(javac)指定运行(java)这个类就可以让程序入口切换到非 public 类中的 main 方法
-
-
.java
是源文件,由一个个类构成;而每个类都会在javac
后变成一个.class
文件。 -
Java 中 char 本质还是数字 ,对应的是 unicode (ASCII(只有英文) -> unicode(全了但是浪费空间) ->utf8
-
Java中取余的本质是利用了除法的只能保留整数 10%3=10-10/3*3
-
a = a++ 见 3.2.3
-
System.in & System.out 见3.9.3
-
前一段时间一直纠结 Java 怎么没有 goto 。它用的是标签啊!看4.5.1.4
-
String 不属于基础数据类型而是数据类型
-
类就是数据类型
-
打印数组的话,直接写数组名是不行滴。要么遍历嘛,要么就
Arrays.toString(数组名)
-
局部变量是不能使用访问修饰符的
-
异常处理的时候 catch 多个,是子在前父在后
-
JUnit 是 Java 语言的单元测试框架(Jshell 也挺好玩) 用的挺多的,就直接
@Test
然后把第二个引进来就中。import org.junit.jupiter.api.Test;
-
建议大家无论干嘛最好类中留一个无参构造器,因为反射会用到这个,不然会报出来奇奇怪怪的错误,比如创建不了等啊。