NEWS LETTER

Java笔记

Scroll down

一、思想:

Snipaste_2025-01-11_20-38-55

二、Win系统快捷键

ctrl+win+d:创建新桌面

ctrl+win+方向键:切换虚拟桌面

ctrl+win+f4:关闭桌面

win+Tab:桌面总览

Alt+Tab:选择窗口

win+Tab:窗口总览

ctrl+Tab:切换窗口

win+d:显示桌面

win+方向键:控制窗口

Alt+f4:关闭当前应用

win+q:全局搜索

win+数字键:快速启动任务栏应用

win+L:锁屏

win+E:打开我的电脑

三、CMD

1、CMD常见代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#进入多级目录
cd 目录1\目录2\...

#回退到盘符目录
cd \

#清屏
cls

#退出命令提示符窗口。
exit

#盘符切换
盘符名称+冒号

#查看当前路径下的内容
dir

#进入单级目录
cd 目录

#回退到上一级目录
cd ..

2、CMD注意事项

(1)在CMD中直接输入程序名(包括后缀名)可以启动程序;

(2)在CMD中使用方向键↑↓可以切换之前输入的语句;

(3)在计算机高级系统设置里设置某个程序的环境变量后,可以在C:\Users\moon>里启动程 序;

四、Java学习的前项准备

1、JDK相关链接

(1)JDK的下载链接:https://www.oracle.com/cn/java/technologies/downloads/

(2)Java文档概述:https://docs.oracle.com/en/java/javase/23/docs/api/index.html

2、JDK的内容

image-20250111222238978

3、手动配置环境变量(在电脑的高级系统设置里)

3.1 操作界面

image-20250112112436645

3.2 变量设置

image-20250112112706244

3.3 部分问题

额外小扩展

部分win10的电脑有一个小bug。
当你重启之后,配置的环境变量会失效。

解决方案:

1,JAVA_HOME还是照样配置
2,在path当中,就不要引l用JAVA_HOME了。
直接写完整路径
比如:E:\develop\jdk\bin

4、Hello World程序(在非集成环境下)

4.1 代码:

1
2
3
4
5
public  class  HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld");
}
}

4.2 编译(要在文件所在的盘符下启动命令行):

1
javac 程序名(有后缀名)

4.3 运行(要在文件所在的盘符下启动命令行):

1
java 程序名(无后缀名)

5、高级记事本的使用(以Notepad++为例)

(1)Notepad++下载链接:https://notepad-plus.en.softonic.com/download

(2)常见高级记事本:Notepad++、Editplus、Sublime

(3)Notepad++的设置:

image-20250112121043408

image-20250112115627489

(4)使用Notepad++的原因:Notepad++有行数和关键字高亮

五、Java的开发方向

1、Java的三大平台

  • Java SE
  • Java ME
  • Java EE

2、Java SE

image-20250112122424278

image-20250112122837774

3、Java ME(已经没落了)

image-20250112123300918

4、Java EE

image-20250112123652161

5、Java的运用

image-20250112124810395

六、Java的优点与特点

1、优点

(1)用户量大 (2)适用面广 (3)与时俱进(一直在更新) (4)自身优越性

2、自身优越性

(1)面向对象(2)安全性 (3) 多线程(执行多任务)(4) 开源(5)跨平台

七、Java可以跨平台的原因

1、高级语言的编译运行方式

(1)过程:编程、编译、运行

(2)编译的类型:编译型、解释型、混合型,半编译,半解释

(3)平台:Arm平台(手机运行)、X86平台(电脑运行)

2、编译型(不能跨平台)

image-20250112174241020

(1)过程:.c->.obj->.exe

(2)但由于电脑(或手机)有不同的硬件,所以同个程序即使在同个平台编译过了,还要 对拥有不同的硬件的电脑(或手机)重新编译一次。

3、解释型

image-20250112175123252过程:没过程,因为是直接拿着原文件按行翻译的

4、混合型

image-20250112175725753

(1)Java不是直接运行在电脑上的,而是运行在虚拟机上的

(2)跨平台原理:

image-20250112180248985

九、JRE和JDK

1、JDK(Java开发工具包)

(1)JVM:Java虚拟机,真正运行Java程序的地方

(2)核心类库:调用的包

(3)开发工具:多个工具

2、JRE(Java运行环境)(不需要修改,只需要运行)

单独抽离出需要的工具

3、包含关系

JDK包含JRE,JRE包含JVM

十、基础语法

1、class

用于创建/定义类,后面跟类名

2、字面量

就是(数据类型:整数、小数、字符串(””)、字符(’’)、布尔、空类型(null))的值

3、输出和输入

1
2
3
4
5
6
7
8
9
//输入
//导包
import java.util.Scanner;
//创建对象
Scanner sc=new Scanner(System.in);
//接收数据
int i=sc.nextInt();
//输出
System.out.println(i);

java里常用的控制台输出语句有System.out.println和System.out.print

两者之间的区别如下:

(1)参数有区别:System.out.println() 可以不写参数

​ System.out.print(参数) 参数不能为空.必须有

(2)效果有区别println :会在输出完信息后进行换行,产生一个新行print: 不会产生新行

(3)println更简洁, print更灵活

print可以后面跟”\n”来达到和println一样的效果也可以跟”\t” 制表符, 等.

4、转义字符

(1)\b(008):退格(BS),将当前位置移到前一列

(2)\f(012):换页(FF),将当前位置一道下页开头

(3)\n(010):换行(LF),将当前位置移到下一行开头

(4)\r(013):回车(CR),将当前位置移到本行开头

(5)\t (009)制表符:在打印的时候,把前面字符串的长度补齐到8,或者8的整数倍。最少补1个空格,最多补8个空格。

用法:

1
System.out.println("abc"+'\t');

(6)\\(092):代表一个反斜字符\

(7)\'(039):代表一个单引号字符(撤号字符)

(8)\“(034):代表一个双引号字符

(9)?(063):代表一个问号

(10)\0(000):空字符(NULL)

(11)\ddd(三位八进制):1到3位八进制数所代表的任意字符

(12)\xhh(十六进制):十六进制所代表的任意字符

5、变量

Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。

byte:

  • byte 数据类型是8位、有符号的,以二进制补码表示的整数;
  • 最小值是 -128(-2^7)
  • 最大值是 127(2^7-1)
  • 默认值是 0
  • byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
  • 例子:byte a = 100,byte b = -50。

short:

  • short 数据类型是 16 位、有符号的以二进制补码表示的整数
  • 最小值是 -32768(-2^15)
  • 最大值是 32767(2^15 - 1)
  • Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
  • 默认值是 0
  • 例子:short s = 1000,short r = -20000。

int:

  • int 数据类型是32位、有符号的以二进制补码表示的整数;
  • 最小值是 -2,147,483,648(-2^31)
  • 最大值是 2,147,483,647(2^31 - 1)
  • 一般地整型变量默认为 int 类型;
  • 默认值是 0
  • 例子:int a = 100000, int b = -200000。

long:

  • long 数据类型是 64 位、有符号的以二进制补码表示的整数;
  • 最小值是 -9,223,372,036,854,775,808(-2^63)
  • 最大值是 9,223,372,036,854,775,807(2^63 -1)
  • 这种类型主要使用在需要比较大整数的系统上;
  • 默认值是 0L
  • 例子: long a = 100000Llong b = -200000L
    “L”理论上不分大小写,但是若写成”l”容易与数字”1”混淆,不容易分辩。所以最好大写。

float:

  • float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
  • float 在储存大型浮点数组的时候可节省内存空间;
  • 默认值是 0.0f
  • 浮点数不能用来表示精确的值,如货币;
  • 例子:float f1 = 234.5f。

double:

  • double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数;

  • 浮点数的默认类型为 double 类型;

  • double类型同样不能表示精确的值,如货币;

  • 默认值是 0.0d

  • 例子:

    1
    2
    3
    4
    5
    double   d1  = 7D ;
    double d2 = 7.;
    double d3 = 8.0;
    double d4 = 8.D;
    double d5 = 12.9867;

    7 是一个 int 字面量,而 7D,7. 和 8.0 是 double 字面量。

boolean:

  • boolean数据类型表示一位的信息;
  • 只有两个取值:true 和 false;
  • 这种类型只作为一种标志来记录 true/false 情况;
  • 默认值是 false
  • 例子:boolean one = true。

char:

  • char 类型是一个单一的 16 位 Unicode 字符;
  • 最小值是 \u0000(十进制等效值为 0);
  • 最大值是 \uffff(即为 65535);
  • char 数据类型可以储存任何字符;
  • 例子:char letter = ‘A’;。

各数据类型的最小值和最大值以下表示

1
2
数据类型.MIN_VALUE
数据类型.MAX_VALUE

6、计算机的存储规则

任意数据都是以二进制存储的。

6.1 任意进制转十进制

公式:系数*基数的权次幂 相加

系数:就是每一位上的数
基数:当前进制数
权又:从右往左,依次为0 1 2 3 4 5 …

image-20250114170253935

6.2 十进制转其他进制

image-20250114165041914

十转二除二;十转八除八

6.3 ASCII码表

img

6.4 图片

通过每个像素点中的RGB三原色来存储

6.5 声音

对声音的波形图进行采样在存储

7、标识名

给变量,函数,类起的名字(要记命名规则)

十一、IDEA

1、IDEA工程组成

项目、模块、包、类

2、IDEA简化语句

2.1 创建main函数

1
2
3
//输入以下简化语句
psvm
//IDEA会补全出现 public static void main(String[] args){}

2.2 创建带布尔的if语句

1
2
3
4
5
6
7
8
boolean flag = true;
//输入以下简化语句
flag.if
//IDEA会补全出现 if(flag){}

//输入以下简化语句
flag.else
//IDEA会补全出现 if(!flag){}

2.3 创建完整的for语句/带布尔的while语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
boolean flag = true;
//输入以下简化语句
fori
//IDEA会补全出现 for(int i=0;i<;i++){}

int a=10;
//输入以下简化语句
a.for
//IDEA会补全出现for (int i = 0; i < a; i++)

//输入以下简化语句
a.forr
//IDEA会补全出现 for(int a=a;i>0;a--){}




//输入以下简化语句
flag.while
//IDEA会补全出现 while(flag){}

2.4 创建对象的语句

1
2
3
//输入以下简化语句
new 类名().var
//IDEA会补全出现 类名 对象名(一般IDEA会取类名的首字母) = new 类名();

2.5 创建输出的语句

1
2
3
//输入以下简化语句
"Hello World".sout
//IDEA会补全出现 System.out.println("Hello World");

2.6 创建异常的语句

1
2
3
//输入以下简化语句
int num = 10/0;.try
//IDEA会补全出现 ...;

2.7 List各种操作的语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
List<Integer> List = Arrays.asList(1,2,3,4,5,6);
//输入以下简化语句
List.for
Integer.sout
List.fori
List.forr //这个为反向
List.get(i).sout

Iterator<Integer> iterator = List.iterator();
//输入以下简化语句
iterator.hasNext().while
iterator.next.sout

//IDEA会补全出现 ...;

3、IDEA快捷键

(1)推荐操作

运行:Alt+4

调试:Alt+5

批量修改:Shift+F6

显示上下文操作:Alt+回车

特殊框选:长按鼠标中键

缩进:Tab

取消缩进:Shift+Tab

注释:Ctrl+/

取消注释:Ctrl+Shift+/

删除一整行:Ctrl+Y

复制一整行:Ctrl+D

对代码切换大小写:Ctrl+Shift+U

剪切板:Ctrl+Shift+V

开始新行:Shift+回车

把一整行向上移:Alt+Shift+向上箭头

格式化代码:Alt+Ctrl+L

提取方法:Alt+Ctrl+M

重构:Alt+Ctrl+Shift+T

最近的更改:Alt+Shift+C

导航到最后编辑的位置:Ctrl+Shift+Backspace

添加多个光标:Alt+Shift+点击

快速生成标准JavaBean类:Alt+insert

(2)代码阅读

查找:Ctrl+F

在文件中查找:Ctrl+Shift+F

替换:Ctrl+R

全局替换:Ctrl+Shift+R

搜索一切:Shift*2

运行所有:Ctrl*2

上下标签页:Alt+左右箭头

切换器:Ctrl+Tab

最近文件:Ctrl+E

折叠和展开:Ctrl+(数字键上的)-/(数字键上的)+

查看形参:Ctrl+P

查看文档:Ctrl+Q

前往声明:Ctrl+B

前往实现:Ctrl+Alt+B

切换方法:Alt+上下箭头

跳转行列:Ctrl+G

(3)对文件操作

文件重构:Shift+F6

复制路径:Ctrl+Shift+C

新建文件:Ctrl+Alt+Insert

临时文件:Ctrl+Alt+Shift+Insert

使用 Ctrl 键进行精确多选

(4)Debug

下一行:F8

下一个断点:F9

进入方法:F7

跳过方法:Shift+F8

运行到光标:Alt+F9

编辑断点:Ctrl+Shift+F8

跳到错误:F2

十二、补充

1、数据类型转换

数字在进行运算时,数据类型不一样不能运算,需要转成一样的,才能运算

1.1 隐式转换(自动类型提升)

取值范围小转为取值范围大;

byte、short、char三种数据类型在运算的时候,不管跟谁运算,都会直接先提升为int,然后再进行运算(char按ASCII码表来变)

1.2 强制转换(手动)

取值范围大转为取值范围小;

格式:目标数据类型 变量名=(目标数据类型)被强转的数据;

1
2
double a=12.3;
int b=(int)a;

1.3 字符串“+”操作

当“+”操作中出现字符串时,这个“+”十字符串连接符,而不是算术运算符。(但是变量还是会保持原来的值)

例:”123”+123=”123123”

2、逻辑运算符

符号 作用 说明
& 逻辑与(且) 并且,两边都为真,结果才是真
| 逻辑或 或者,两边都为假,结果才是假
^ 逻辑异或 相同为 false,不同为 true
! 逻辑非 取反

^的用法:

1
System.out.println(1 ^ 1);//相同是false,不同是true

3、短路逻辑运算符

符号 作用 说明
&& 短路与 结果和&相同,但是有短路效果
|| 短路或 结果和|相同,但是有短路效果

4、三元运算符

关系表达式 ? 表达式 : 表达式;

5、运算符优先级

优先级 运算符
1 . () {}
2 !、~、++、–
3 *、/、%
4 +、-
5 <<、>>、>>>
6 <、<=、>、>=、instanceof
7 ==、!=
8 &
9 ^
10 |
11 &&
12 ||
13 ?:
14 =、+=、-=、*=、/=、%=、&=、^=、|=

6、原码、反码、补码

符号位是最前面的一位,一个1或0称之为一个bit;

一个字节最大为01111111(最大为八位),转为十进制为+127;

最小为11111111,转为十进制为-127;

image-20250115171935487

反码是为了解决原码不能计算负数的问题而出现的;

补码是为解决0的两种形式而出现的;

负数计算就是在负数的反码+1后进行计算。

7、分支语句

7.1 switch的相关知识点

default:位置是任意的,同时是可以省略,但是不建议省略。

case穿透(没写break):在switch中,会按顺序匹配case的值,如果匹配上了,就会执行对应的语句体,如果此时发现了break,那么结束整个switch语句。如果没有发现break,那么程序会继续执行下一个擦色的语句体,一直遇到break或者右大括号(就是在最后一行的意思)为止。有穿透的原因:如果case的语句体有重复,可以用case穿透来简化代码。

switch在JDK12(及以上)中的新特性(自带break,不用自己写):

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
int i =1,j=2;
//多行语句
switch(i){
case 1->{
j=i;
System.out.println(i);
}
case 2->{
j=i;
System.out.println(i);
}
case 3->{
j=i;
System.out.println(i);
}
default ->{
j=i;
System.out.println(i);
}
}
//单行语句
switch(j){
case 1->System.out.println(1);
case 2->System.out.println(2);
case 3->System.out.println(3);
default ->System.out.println("no");
}

7.2 if和switch的使用区别

if用于对范围的判断,switch用于有限个数据。

7.3 while的补充

while的特殊写法

1
2
while(cin>>){
}

for和while区别在变量作用域;

在使用无限循环或在不知道循环次数的时候用while;

无限循环下面不要写其他代码,因为无限循环出不来。

7.4 数组的补充

int型的数组可以装byte、short、int;

double型的可以装除了boolean的其他数据类型。

(1)静态初始化

长度在初始化时就已经固定了;

1
2
3
4
5
//完整格式
int[] arr =new int[]{1,2,3};
//简化格式
int[] arr = {1,2,3};
//数据类型[] 数组名={元素1,元素2,元素3};

(2)动态初始化

初始化时只给定数组长度,由系统为数组分配初始值;

整数类型:默认初始值0

小数类型:默认初始值0.0

字符类型:默认初始值’/u0000’ 空格

布尔类型:默认初始值 false

引用数据类型:默认初始值null

1
2
3
//格式
int[] arr=new int[3];
//数据类型[] 数组名=new 数据类型[数组长度];

7.5 数组的内存图

(1)Java内存分配

  • 栈 方法运行时使用的内存,比如main方法运行,进入方法栈中执行
  • 堆 存储对象或者数组,new来创建的,都存储在堆内存
  • 方法区 存储可以运行的class文件
  • 本地方法栈 JVM在使用操作系统功能的时候使用,和我们开发无关
  • 寄存器 给CPU使用,和我们开发无关

注意:

从JDK8开始,取消方法区,新增元空间。
把原来方法区的多种功能进行拆分,
有的功能放到了堆中,有的功能放到了元
空间中。

image-20250117171014250

(2)内存图

两个数组不同空间:

image-20250117174027828

两个数组指向同空间:

当两个数组指向同个空间时,其中一个数组对小空间中的值发生了改变,那么其他数组再次访问的时候都是修改之后的结果了。

image-20250119152658253

8、方法(函数)

8.1 完整格式:

1
2
3
4
5
6
public static 返回值类型 方法名(参数){
方法体;
return 返回值;
}
//参数格式:(int num1,int num2)
//

方法和方法之间是平级关系(一般main在最上面),不能互相嵌套定义

8.2 函数重载

在同一个类中,方法名相同,参数不同的方法。与返回值无关。

参数不同:个数不同,类型不同,顺序不同。

重载的判断:会判断方法之间是否构成重载关系

​ 会定义重载的方法

​ 顺序不同可以,但是不建议

符合重载的例子:

1
2
3
4
5
6
7
8
public class MethodDemo {
public static int sum(int a,int b){
return a + b;
}
public static int sum(int a,int b,int c){
return a + b + c;
}
}

Java虚拟机会通过参数的不同(重载适用于所有数据类型)来区分同名的方法

image-20250120220007790

image-20250120221039363

8.3 方法的内存原理

8.3.1 调用的基本内存原理

方法被调用后就会进栈执行,执行完就离开栈

8.3.2 基本数据类型与引用数据类型

基本数据类型:(1)整数、浮点数、布尔、字符类型(2)变量中存储的是真实的数据(3)在栈中存储

引用数据类型:(1)new出来的其他所有类型都是(如类、接口、数组、String)(2)变量中存储的是地址值(3)在栈中存储地址值,在堆内存中存储数据

8.4 方法的值传递

基本数据类型不会被方法的形参改变;

而引用数据类型被方法的形参改变。

十三、Java的对象

1、设计对象

  • 类(设计图):是对象共同特征的描述;
  • 对象:是真实存在的具体东西。
  • Javabean类:用来描述一类事物的类。比如,Student,Teacher,Dog,Cat等
  • 测试类:用来检查其他类是否书写正确,带有main方法的类,是程序的入口
  • 工具类:不是用来描述一类事物的,而是帮我们做一些事情的类。
  • 在Java中,必须先设计类,才能获得对象。
1
2
3
4
5
public class Phone{

}
//在定义完Phone这个类之后可以的通过new来获取对象
Phone p = new Phone();

1.1 定义类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class 类名{
//1、成员变量(代表属性,一般是名词)
//2、成员方法(代表行为,一般是动词)
//3、构造器
//4、代码块
//5、内部类
}

//例子
public class Phone{
//属性(成员变量)
String brand;
double price;
//行为(方法)
public void call(){

}
public void playGame(){

}
//构造器
//代码块
//内部类
}

1.2 得到类的对象

1
2
3
4
5
6
//获取对象
//类名 对象名 = new 类名();
Phone p = new Phone();
//使用对象
//访问属性:对象名.成员变量
//访问行为:对象名.方法名(...)

1.2.1 类的区分

(1)用于描述一类事物的类,专业叫做:Javabean类。在Javabean类中,是不写main方法的。

(2)在以前,编写main方法的类,叫做测试类。

我们可以在测试类中创建JavaBean类的对象并进行赋值调用。

1.2.2 定义类的注意事项

(1)一个Java文件中可以定义多个class类,且只能一个类是public修饰,而且public修饰的类名必须成为代码文件名

(2)在实际开发中,还是一个文件一个class类。

(3)成员变量的完整格式:修饰符 数据类型 变量名称

(4)成员变量一般是只定义不初始化值的,除非需要自定义默认值。成员变量一般有自己的默认值。

数据类型 明细 默认值
基本类型 byte、short、int、long 0
float、double 0.0
boolean false
引用类型 类、接口、数组、String null

1.3 对象的三大特征

封装、继承、多态

1.3.1 封装

对象代表什么,就得封装对应的数据,并提供数据对应的行为

例子:人画圆;画是人的动作,但是画出的圆需要有半径,而且半径是圆的属性。所以画圆是圆这个对象的行为。

只要影响了对象的状态,就是该对象的行为。

Java已经封装了很多的对象

image-20250131222125934

1.3.2 与类相关的关键字

(1)private

  • 是一个权限修饰符
  • 可以修饰成员(成员变量和成员方法)
  • 被private修饰的成员只能在本类中访问

(2)public

  • 是一个权限修饰符
  • 可以修饰成员(成员变量和成员方法)
  • 被private修饰的成员可以被任何其他类访问,这意味着它没有访问限制。

(3)this

  • 是一个权限修饰符
  • 可以指向这个类内的成员(成员变量和成员方法)

1.4 创建类的注意事项

(1) 赋值过滤

为了保证类的成员属性出现不合法的情况,

可以设置private并创建set和get的public方法

1
2
3
4
5
6
7
8
9
10
11
public void setage(int a) {
if (a<=10) {
age=a;
Yes();
}else{
No();
}
}
public int getage() {
return age;
}

(2) 就近原则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Girlfriend{
private int age;
public void method(){
int age = 10;
System.out.println(age);
}
}
//println会用最近的age

//使用this
public class Girlfriend{
private int age;
public void method(){
int age = 10;
System.out.println(this.age);
}
}

2、构造方法

(1)格式:

image-20250211171906938

(2) 注意事项:

  • 如果没写任何构造方法,虚拟机会默认给一个空参构造方法;

  • 如果有写构造方法,虚拟机不会给默认构造,需要你根据你自己写的来new。

  • 带参构造和空参构造是同名的,说明构造方法是可以重载的;

  • 无论是否使用,都会手动写两种构造方法(空参构造和带所有参数的构造)。

3、标准JavaBean类

  1. 类名需要见名知意
  2. 成员变量使用private修饰
  3. 提供至少两个构造方法
    1. 无参构造方法
    2. 带全部参数的构造方法
  4. 成员方法
    1. 提供每一个成员变量对应的setXxx()/getXxx()
    2. 如果还有其他行为,也需要写上

快速生成:

1
2
3
4
//快捷键:
//alt+insert
//alt +Fn + insert
//插件PTG 1秒生成标准Javabean

4、对象内存图

1
Student s = new Student();
  1. 加载class文件
  2. 申明局部变量
  3. 在堆内存中开辟一个空间
  4. 默认初始化
  5. 显示初始化
  6. 构造方法初始化
  7. 将堆内存中的地址值赋值给左边的局部变量

4.1 一个对象的内存图

image-20250213221226267

4.2 两个对象的内存图

image-20250213221553447

4.3 两个引用指向同一个对象

image-20250213223022068

4.4 基本数据类型和引用数据类型

基本数据类型

定义:数据值是储存在自己的空间中

特点:赋值给其他变量,也是赋的真实的值。

image-20250213224444540

引用数据类型

image-20250213224752253

image-20250213224936082

定义:数据值是储存在其他的空间中,自己的空间中存储的是地址值

特点:赋值给其他变量,是赋的地址值。

4.5 this内存图

image-20250213225707711

image-20250213225843518

image-20250213230707803

4.6 成员变量和局部变量

区别 成员变量 局部变量
类中位置不同 类中,方法外 方法内、方法申明上
初始化值不同 有默认初始化值 没有,使用之前需要完成赋值
内存位置不同 堆内存 栈内存
生命周期不同 随着对象的创建而存在,随着对象的消失而消失 随着方法的调用而存在,随着方法的运行结束而消失
作用域 整个类中有效 当前方法中有效

image-20250213231122596

5、API与API帮助文档

(1)API

目前是JDK中提供的各种功能的Java类。

这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可。

(2)API帮助文档

帮助开发人员更好的使用API和查询API的一个工具。

6、字符串

6.1 字符串的众多操作和学习内容

操作

比较、替换、截取、查找、切割、检索、加密、打乱内容、大小写转换…

学习内容

  • String,StringBuilder,StringJonier,StringBuffer,Pattern,Matcher

    可以掌握字符串的一些常见操作了。

  • 实际开发中的一些常见案例

    掌握分析问题,解决问题的能力。

  • 字符串相关的底层原理

    掌握原理更好的通过面试,处理开发中的一些复杂问题。

  • 字符串的练习题

    锻炼独立解决问题的能力

6.2 String

6.2.1 定义

java.lang.String 类代表字符串,java程序中的所有字符串文字(例如“abc”)多为此类的对象。

6.2.3 注意点

字符串的内容是不会发生改变的,它的对象在创建后不能被更改。

6.2.4 创建String的方法

(1)直接赋值

1
String name = "abc";

(2)new

构造方法 说明
public String() 创建空白字符串,不含任何内容
public String(String original) 根据传入的字符串,创建字符串对象
public String(char[] chs) 根据字符数组,创建字符串对象
public String(byte[] chs) 根据字节数组,创建字符串对象

6.2.3 ==号的比较区别

image-20250417223036576直接赋值的字符串,不会创建新的,会复用

1
2
3
4
5
6
7
8
9
String s1="abc";
String s2="abc";
System.out.println(s1==s2);//true

String s1=new String("abc");//new出来的,都是在堆里开辟空间的
String s2="abc"; //直接赋值的是在字符串池里的
System.out.println(s1==s2);//false;

//键盘输入的也是new出来的

6.2.4 比较字符串

boolean equals() 完全一样的才会返回true
boolean equalslgnoreCase() 忽略大小写的比较

6.2.5 遍历字符串

1
2
3
4
5
6
7
8
for(int i=0;i<arr.length();i++){
System.out.println(arr[i]);
}//错误的!!!java里字符串不能这样输出单个字符

//正确的!!!!!
for (int i = 0; i < str.length(); i++) {
System.out.print(str.charAt(i));
}

6.2.6 拼接字符串

1
2
3
4
5
int[] arr={1,2,3};
String r="123"
for(int i=0;i<=arr.length;i++){
r=r+arr[i];
}

6.2.7 字符串反转

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
public class StringReverse {
public static void main(String[] args) {
String str = "hello";
// 使用 StringBuilder
String reversed = new StringBuilder(str).reverse().toString();
System.out.println(reversed); // 输出:olleh
}
}

public class StringReverse {
public static String reverse(String str) {
if (str == null || str.isEmpty()) {
return str; // 处理空字符串或null
}
char[] chars = str.toCharArray();
int left = 0;
int right = chars.length - 1;
while (left < right) {
// 交换左右字符
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
return new String(chars);
}

public static void main(String[] args) {
String str = "hello";
System.out.println(reverse(str)); // 输出:olleh
}
}

6.2.8 字符串截取

1
2
3
4
5
6
substring(int beginIndex,int endIndex)
//包头不包尾
substring(int beginIndex)
//截取到末尾
String arr="1234";
string r=arr.substring(0,3);//用这个方法要接收

6.3 StringBuilder

StringBuilder可以看成一个容器,创建之后里面的内容是可变的

6.3.1 作用:提高字符串的操作效率

方法名 说明
public StringBuilder() 创建一个空白可变的字符串对象,不含有任何内容
public StringBuilder(String str) 根据字符串的内容,来创建可变字符串对象
1
StringBuilder sb=new StringBuilder("abc");

6.3.2 StringBuildercyong方法

方法名 说明
public StringBuilder append(任意类型) 添加数据,并返回对象本身
public StringBuilder reverse() 反转容器中的内容
public int length() 返回长度
public String toString() 把StringBuilder转化为String
1
2
3
4
5
StringBuilder sb=new StringBuilder("abc");
sb.append(1.1);
sb.reverse();
int a=sb.length();
String str=sb.toString();

小技巧:

1
2
//如果不需要重复利用一个被方法处理的值,可以采用链式思想,或者连续处理同一个返回值类型的方法
sb.append(1.1).append(1.2).append(1.3).append(1.4);

6.4 StringJoiner

6.4.1 用于指定格式

方法名 说明
public StringJoiner(间隔符号) 创建一个public StringJoiner对象,指定拼接时的间隔符号
public StringJoiner(间隔符号,开始符号,结束符号) 。。。

6.4.2 成员方法

方法名 说明
public StringJoiner add(添加的内容) 添加数据,并返回本身
public int length() 返回长度(包括设定的符号)
public String toString() 返回字符串

6.5 字符串的底层原理

7、集合

7.1 初识集合

为什么要有集合

  • Java的数组创建完后是固定长度的,而集合长度是可变的,相当于C++里的vector。
  • 集合可以存引用类型,集合可以基本数据类型(但要用包装类)
  • 数组两个都可存

7.2 集合基础

1
2
ArrayList<String> list=new ArrayList<>();

成员方法
方法名 说明
boolean add(E e) 添加,返回是否成功
boolean remove(E e) 删除指定元素,返回是否成功
E remove(int index) 删除指定索引的元素,返回是否成功
E set(int index,E e) 修改指定索引的元素,返回原来的元素
E get(int index) 获取指定索引的元素
int size() 长度
基本数据类型对应的包装类
基本数据类型 包装类
byte Byte
short Short
char Character
int Integer
long Long
float Float
double Double
boolean Boolean
1
ArrayList<Integer> list=new ArrayList<>();

用集合ArrayList接对象是要记住,要把接数据的对象创建在循环里,不然会被覆盖

8、面向对象进阶

8.1 static

8.1.1 静态变量:

对所有同一个类的对象共享的属性用static,每一次赋值都会覆盖共享的值

调用方法:

类名调用(推荐)

对象名调用

特点:随着类的加载而加载,优于对象存在

8.1.2 静态方法:

方便直接用工具类的方法

调用方法:

类名调用(推荐)

对象名调用

特点:

多用于测试类和工具类当中

javabean类中很少会用

8.1.3 注意事项

静态方法只能访问静态变量和静态方法

非静态方法可以访问所有

静态方法没有this关键字

8.2 继承

8.1.1 什么是继承

image-20250419235154602

8.1.2 继承的特点

Java只支持单继承,不支持多继承(多父),但支持多层继承 (子子孙孙)

每一个类都直接或间接继承于Object

8.1.3 继承的内容

类别 非私有修饰符 private修饰符
构造方法 不能 不能
成员变量
成员方法 不能

构造方法:如果继承就违背了构造方法的结构(与类同名)

成员变量:私有的不能直接用

成员方法:虚方法会被继承

image-20250420010231132

8.1.4 继承结构语法

成员变量:

image-20250420010535449

this:本类的东西

super:当前类的父类的东西

成员方法:

直接调用满足就近原则

this:本类的东西

super:当前类的父类的东西

方法重写:

当父类的方法不能满足子类的使用时重写

书写格式

在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。

@Override重写注解
  1. @Override是放在重写后的方法上,校验子类重写时语法是否正确。
  2. 加上注解后如果有红色波浪线,表示语法错误。
  3. 建议重写方法都加@Override注解,代码安全,优雅!

方法重写的注意事项

如果出现了重写,被重写的方法会覆盖当前类的虚方表里的方法

  1. 重写方法的名称、形参列表必须与父类中的一致。
  2. 子类重写父类方法时,访问权限子类必须大于等于父类(暂时了解:空着不写<protected<public)
  3. 子类重写父类方法时,返回值类型子类必须小于等于父类
  4. 建议:重写的方法尽量和父类保持一致。
  5. 私有方法不能被重写。
  6. 子类不能重写父类的静态方法,如果重写会报错的。
构造方法:
  • 父类中的构造方法不会被子类继承。
  • 子类中所有的构造方法默认先访问父类中的无参构造,再执行自己。
为什么?
  • 子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
  • 子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化。
怎么调用父类构造方法的?
  • 子类构造方法的第一行语句默认都是:super(),不写也存在,且必须在第一行。
  • 如果想调用父类有参构造,必须手动写super进行调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class fu{
String name
fu(String name){
this.name=name;
}
}
public class zi{
public zi(){
super();
}
public zi(String name){
super(String name);
}
}
this、super的特点

this:当前调用者的地址值

8.3 多态

8.3.1 多态的形式

同类型的对象,表现出不同形态

1
//父类类型 对象名称 =子类对象

image-20250421223841268

8.3.2 使用前提

  • 要有继承关系

  • 要有父类引用指向子类对象

    1
    Fu f=new Zi();
  • 要有方法重写

8.3.3 用处

(1)用来接收多种同一父类的对象,即让多个对象可以共用的方法可以接收他们

1
2
public void register(Person P){
}

(2)根据传递对象的不同,还可以调用不同的方法

1
2
3
4
public void register(Person P){
if(){
}
}

(3)还可以向下转型

1
Zi z=(Zi) fu;

8.3.4 调用成员的特点

  • 变量调用:编译看左边,运行也看左边。
  • 方法调用:编译看左边,运行看右边。

即编译时会看左边的父类中有没有这个方法,

方法运行的时候调用的是子类的方法

8.3.5 多态的优势

在多态形式下,右边对象可以实现解耦合,便于拓展和维护

1
2
Person p=new Student();
p.work();//业务逻辑发生改变时,后续代码无需修改

定义方法时,可以方法可以接收所有子类对象

但是各个子类它们自己的方法,需要在方法里判断一下。

之后强转类型

1
2
3
if(fu instanceof zi){
Zi z=(Zi) fu;
}

8.3.6 多态的弊端:不能用子类的特有的功能

8.4 包、final、权限修饰符、代码块

8.4.1 包

其实就是文件夹

image-20250422211141205

使用其他包的类时,要用全类名

1
2
3
4
5
6
import com.gzgs.demo.Student;
public class Test{
public static void main(String[] args){
Student S=new Student();
}
}

使用其他类的规则

  • 使用同一个包中的类时,不需要导包
  • 使用java.lang包中的类时,不需要导包。
  • 其他情况都需要导包
  • 如果同时使用两个包中的同名类,需要用全类名。

8.4.2 final

被final修饰的就是不可变的

方法:表明方法是最终方法不能被重写

类:表明该类是最终类,不能被继承

变量:常量

常量

实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。
常量的命名规范:
单个单词:全部大写
多个单词:全部大写,单词之间用下划线隔开

细节

final修饰的变量是基本类型:那么变量存储的数据值不能发生改变。
final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,对象内部的可以改变。

注意:常量字符串改不了,因为字符串的源码用了private

8.4.3 权限修饰符

控制一个成员能够被访问的范围

权限修饰符的分类

有四种作用范围由小到大(private<空着不写<protected<public)

修饰符 同一个类中 同一个包中其他类 不同包下的子类 不同包下的无关类
private
空着不写
protected
public

private:就只能自己用

默认(default)(空着不写):同一个包用

protected:给自己有关系可以用(子类,同个包)

public:随便用

权限修饰符的使用规则

实际开发中,一般只用private和public

  • 成员变量私有
  • 方法公开

特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有。

8.4.4 代码块

局部代码块:提前结束变量的使用,节约内存,淘汰了

1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main (String[] args){
//局部代码块
{
int a=10;
System.out.println(a);
}

}
}

构造代码块:淘汰了

image-20250422213712507

image-20250422213843442

image-20250422214235653

静态代码块

  • 格式:static0

  • 特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次

  • 使用场景:在类加载的时候,做一些数据初始化的时候使用。

    image-20250422215008303

8.5 抽象类

把共性的行为写到父类当中去,让子类具体去实现。

  • 抽象方法:将共性的行为(方法)抽取到父类之后。
    • 由于每一个子类执行的内容是不一样
    • 所以,在父类中不能确定具体的方法体
    • 该方法就可以定义为抽象方法。
  • 抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类
1
2
public abstract 返回值类型 方法名(参数列表);
public abstract class 类名{}
抽象类和抽象方法的注意事项
  • 抽象类不能实例化
  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
  • 可以有构造方法
  • 抽象类的子类
    • 要么重写抽象类中的所有抽象方法
    • 要么是抽象类

抽象类的构造方法是给子类用的

8.6 接口

8.6.1 接口的意义

image-20250422225337642

接口是对一部分子类拥有共同的特殊行为的规则的定义

8.6.2 接口的定义和使用

  • 接口用关键字interface来定义
    • public interface接口名
  • 接口不能实例化
  • 接口和类之间是实现关系,通过implements关键字表示
    • public class类名implements接口名0
  • 接口的子类(实现类)
    • 要么重写接口中的所有抽象方法
    • 要么是抽象类
  • 注意1:接口和类的实现关系,可以单实现,也可以多实现。
    • public class类名implements接口名1,接口名2{
  • 注意2:实现类还可以在继承一个类的同时实现多个接口。
    • public class类名extends父类implements挂接口名1,接口名2

8.6.3 接口中成员的特点

  • 成员变量
    • 只能是常量
    • 默认修饰符:publicstaticfinal
  • 构造方法
    • 没有
  • 成员方法
    • 只能是抽象方法
    • 默认修饰符:publicabstract
  • JDK7以前:接口中只能定义抽象方法

接口只是规则,一般没有成员变量

接口和接口之间是继承关系,可以单继承,也可以多继承;

如果实现类实现了最下面的子接口,那么就需要重写所有的抽象方法,

即:接口1,接口2,接口3(继承于接口2,接口1),类A实现接口3,那么类A要把接口1到接口3的所有抽象方法都实现

8.6.4 接口和类之间的关系

  • 类和类的关系
    • 继承关系,只能单继承,不能多继承,但是可以多层继承
  • 类和接口的关系
    • 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
  • 接口和接口的关系
    • 继承关系,可以单继承,也可以多继承

8.6.5 从JDK8开始接口新增的方法

  • JDK7以前:接口中只能定义抽象方法
  • JDK8的新特性:接口中可以定义有方法体的方法(默认、静态)
  • JDK9的新特性:接口中可以定义私有方法

为何:当需求增加的时候,可以在父接口写一个带方法体的方法实现类暂时集体使用,之后想修改直接重写就行

1.允许在接口中定义默认方法,需要使用关键字default修饰

  • 作用:解决接口升级的问题

  • 接口中默认方法的定义格式:

    • 格式:public default返回值类型方法名(参数列表){}
    • 范例:public default void show(){}
  • 接口中默认方法的注意事项:

    • 默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字
    • public可以省略,default不能省略
    • 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写

2.允许在接口中定义定义静态方法,需要用static修饰

  • 接口中静态方法的定义格式:
    • 格式:public static 返回值类型方法名(参数列表){}
    • 范例:public static void show(){}
  • 接口中静态方法的注意事项:
    • 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
    • public可以省略,static不能省略

静态方法不能被重写

JDK9新增加的方法

接口中私有方法的定义格式:

  • 格式1:private 返回值类型方法名(参数列表){}
  • 范例1: private void show() {}
  • 格式2:private static返回值类型方法名(参数列表){}
  • 范例2: private static void method() { }

8.6.6 接口的应用

  1. 接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。
  2. 当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态

8.6.7 适配器设计模式

  1. 当一个接口中抽象方法过多,但是我只要使用其中一部分的时候,就可以适配器设计模式

  2. 书写步骤:

    编写中间类XXXAdapter实现对应的接口对接口中的抽象方法进行空实现让真正的实现类美继承中间类,并重写需要用的方法为了避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰

8.7 内部类

8.7.1 初识内部类

内部类:在A类里面对一个B类,B类就被称为内部类

1
2
3
4
5
public class Outer{
public class Innter{
//内部类
}
}

image-20250423225247014

内部类的作用:比如汽车的发动机,ArrayList的迭代器,人的心脏

8.7.2 内部类的分类

(1)成员内部类、静态内部类、局部内部类。不会自己写,一般在源码里出现

(2)匿名内部类以后会经常用到的

成员内部类:

image-20250424220102785

创建方法一:外部编写方法,对外提供内部类对象

1
2
3
4
5
6
pbulic Inner getInstanxe(){
return new Inner();
}

Outer o=new Outer();
Object inner =o.getInstanxe

创建方法二:直接创建

1
2
//格式:
Outer.INner oi =new Outer().new Inner();

内部类的变量调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Outer {
private int a = 10;

class Inner {
private int a = 20;

public void show() {
int a = 30;
System.out.println(a); // 30
System.out.println(this.a); // 20
System.out.println(Outer.this.a); // 10
}
}
}
静态内部类:

在内部类前面加上关键字static就行,但是有要注意的点

静态内部类只能访问外部类中的静态变量和方法,如果要访问非静态的要创建对象

创建静态内部类对象的格式:

1
外部类名.内部类名 对象名 =new 外部类名.内部类名();

调用非静态方法的格式:先创建对象,用对象调用

调用静态方法的格式:

1
外部类名.内部类名.方法名();
局部内部类:

1、将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。

2、外界是无法直接使用,需要在方法内部创建对象并使用。(套娃)

3、该类可以直接访问外部类的成员,也可以访问方法内的局部变量。

匿名内部类
本质

匿名内部类本质上就是隐藏了名字的内部类。

格式
1
2
3
new 类名或者接口名() {  
重写方法;
};
核心特点
  1. 继承/实现:基于“类名或接口名”实现继承或接口
  2. 方法重写:必须重写父类/接口中的抽象方法(若为接口则需实现所有抽象方法)
  3. 创建对象:语法上直接创建匿名对象,无需显式定义类名
举例
1
2
3
4
5
6
// 假设存在接口 Inter,包含抽象方法 show()  
new Inter() {
public void show() {
// 实现 show() 方法的具体逻辑
}
};

匿名内部类要继承类或实现接口!!!

格式中的new是用来new出匿名内部类来使用,()是指空参构造

用处:

image-20250426160430662

image-20250426160906029

image-20250426161024474

十四、常用API

1、Math

Math类的常用方法

方法名 说明
public static int abs(int a) 获取参数绝对值
public static double ceil(double a) 向上取整
public static double floor(double a) 向下取整
public static int round(float a) 四舍五入
public static int max(int a, int b) 获取两个int值中的较大值
public static double pow(double a, double b) 返回a的b次幂的值
public static double random() 返回值为double的随机值,范围[0.0, 1.0)

2、System

与系统相关的方法

System也是一个工具类,提供了一些与系统相关的方法

方法名 说明
public static void exit(int status) 终止当前运行的 Java 虚拟机
public static long currentTimeMillis() 返回当前系统的时间毫秒值形式
public static void arraycopy(数据源数组, 起始索引, 目的地数组, 起始索引, 拷贝个数) 数组拷贝

exit(0); 结束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 拷贝数组
int[] arr1 = {1,2,3,4,5,6,7,8,9,10};
int[] arr2 = new int[10];

// 把arr1数组中的数据拷贝到arr2中
// 参数一:数据源,要拷贝的数据从哪个数组而来
// 参数二:从数据源数组中的第几个索引开始拷贝
// 参数三:目的地,我要把数据拷贝到哪个数组中
// 参数四:目的地数组的索引
// 参数五:拷贝的个数
System.arraycopy(arr1, 0, arr2, 0, 5); // srcPos: 0, destPos: 0, length: 5

// 验证
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i] + " ");
}
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
public class SystemDemo3 {
public static void main(String[] args) {
// public static void arraycopy(数据源数组, 起始索引, 目的地数组, 起始索引, 拷贝个数) 数组拷贝
// 细节:
// 1. 如果数据源数组和目的地数组都是基本数据类型,那么两者的类型必须保持一致,否则会报错
// 2. 在拷贝的时候需要考虑数组的长度,如果超出范围也会报错
// 3. 如果数据源数组和目的地数组都是引用数据类型,那么子类型可以赋值给父类类型

Student s1 = new Student("zhangsan", 23);
Student s2 = new Student("lisi", 24);
Student s3 = new Student("wangwu", 25);

Student[] arr1 = {s1, s2, s3};
Person[] arr2 = new Person[3];

// 把arr1中对象的地址值赋值给arr2中
System.arraycopy(arr1, 0, arr2, 0, 3); // srcPos: 0, destPos: 0, length: 3

// 遍历数组arr2
for (int i = 0; i < arr2.length; i++) {
Student stu = (Student) arr2[i];
System.out.println(stu.getName() + ", " + stu.getAge());
}
}
}

2、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命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//1. 获取Runtime的对象
//Runtime r1 = Runtime.getRuntime();

//2. exit 停止虚拟机
//Runtime.getRuntime().exit(0);

//3. 获得CPU的线程数
System.out.println(Runtime.getRuntime().availableProcessors());//8

//4. 总内存大小,单位byte字节
System.out.println(Runtime.getRuntime().maxMemory() / 1024 / 1024);//4064

//5. 已经获取的总内存大小,单位byte字节
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);//254

//6. 剩余内存大小
System.out.println(Runtime.getRuntime().freeMemory() / 1024 / 1024);//251

//7. 运行cmd命令
Runtime.getRuntime().exec("notepad");

3、Object和Objects

Object

方法名 说明
public String toString() 返回对象的字符串表示形式
public boolean equals(Object obj) 比较两个对象是否相等
protected Object clone(int a) 对象克隆

可以子类重写这些方法

toString返回的是地址值

equals比较的是地址值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ObjectDemo3 {
public static void main(String[] args) {
String s = "abc";
StringBuilder sb = new StringBuilder("abc");

System.out.println(s.equals(sb));// false
// 因为equals方法是被s调用的,而s是字符串
// 所以equals要看String类中的
// 字符串中的equals方法,先判断参数是否为字符串
// 如果是字符串,再比较内部的属性
// 但是如果参数不是字符串,直接返回false

System.out.println(sb.equals(s));// false
// 因为equals方法是被sb调用的,而sb是StringBuilder
// 所以这里的equals方法要看StringBuilder中的equals方法
// 那么在StringBuilder当中,没有重写equals方法
// 使用的是Object中的
// 在Object当中默认是使用==号比较两个对象的地址值
// 而这里的s和sb记录的地址值是不一样的,所以结果返回false
}
}

clone:A对象的属性值拷贝到B对象(方便服务器内容迁移)

clone是无法直接调用的,因为clone方法是被protected修饰的

使用方法:

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
//Cloneable
//如果一个接口,没有抽象方法,表示当前接口是一个标记性接口
//现在Cloneable表示一旦实现了,那么当前对象就会被克隆
//如果没有实现,当前类的对象就不能被克隆
public class User implements Cloneable{
//成员变量

//构造方法
public User(){

}
//重写
protected Object clone() throws CloneNotSupportedException{
//调用父类中的clone方法
//相当于让Java帮我们克隆一个对象,并把克隆之后的对象返回出去。
return super.clone();
}

}

//测试类
public class Demo{
public static void main (String[] args){
int[] data ={1234}
User u1=new User(1,"张三","123",data);
//克隆对象
User u2=(User) u1.clone();

System.out.println(u1);
System.out.println(u2);
}

}

克隆方式:

第一种方法(直接拷贝)会导致,数组的内容发生改变的时候,两个对象的内容都会发生改变,这种方法叫做浅克隆,浅拷贝。

image-20250501202645407

第二种方法,深克隆

image-20250501212223660

克隆总结:

把A对象的属性值完全拷贝给B对象,也叫对象拷贝、对象复制。

1. 浅克隆

  • 核心特点:不管对象内部的属性是基本数据类型还是引用数据类型,都完全拷贝过来。
    • ✅ 基本数据类型:直接拷贝值。
    • ✅ 引用数据类型:拷贝引用地址(原对象和克隆对象共享同一份引用数据)。

2. 深克隆

  • 核心特点
    • ✅ 基本数据类型:直接拷贝值。
    • ✅ 字符串:复用(字符串常量池特性,不创建新对象)。
    • ✅ 引用数据类型:重新创建新的对象(原对象和克隆对象的引用数据完全独立)。

Object里的克隆方法是浅克隆,深克隆要自己写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected Object clone() throws CloneNotSupportedException{
//调用父类中的clone方法
//相当于让Java帮我们克隆一个对象,并把克隆之后的对象返回出去。
//先把被克隆的对象中的数组获取出来
int[] data =this.data;
//创建新的数组
int[] newdata = new int[data.length];
//拷贝数组中的数据,数组类型会变的,以后会用第三方方法
for(int i=0;i<data.length;i++){
newdata[i]=data[i];
}


//调用父类中的方法克隆对象
User u=(User) super.clone();
//因为父类中的克隆方法是浅克隆,所有要替换克隆出来的对象的数组地址值
u.data=newdata;
return u;
}
1
2
3
4
5
6
//第三方法(导入gson.jar)!!!!
Gson gson =new Gson();
//把对象变成一个字符串
String s=gson.toJson(u1);
//再把字符串变成对象就可以了
User user=gson.fromJion(s,User.class);

Objects

Objects是一个工具类,提供了一些功能

方法名 说明
public static boolean equals(Object a, Object b) 先做非空判断,比较两个对象
public static boolean isNull(Object obj) 判断对象是否为null,为null返回true,反之返回false
public static boolean nonNull(Object obj) 判断对象是否为null,跟isNull的结果相反
1
2
3
4
Objects.equals(s1,s2);
//方法底层会先判断是否为空,再调用对象重写的equals方法,没有重写就调用Object的方法
Objects.isNull(s1);
Objects.nonNull(s1);

4、BigInteger和BigDecimal

BigInteger:高精度整数

BigDecimal:高精度小数

BigInteger

方法名 说明
public BigInteger(int num, Random rnd) 获取随机大整数,范围:[0 ~ 2的num次方-1]
public BigInteger(String val) 获取指定的大整数
public BigInteger(String val, int radix) 获取指定进制的大整数
public static BigInteger valueOf(long val) 静态方法获取BigInteger的对象,内部有优化

对象一旦创建,内部记录的值不能发生改变

1
2
3
4
Random r= new Random();
BigInteger b1=new BigInteger(4,r);
//获取指定进制的大数字
BigInteger b1=new BigInteger("1010",2);
1
2
3
4
5
6
7
8
9
10
11
12
// 4. 静态方法获取BigInteger的对象,内部有优化
// 细节:
// 1. 能表示范围比较小,只能在long的取值范围之内,如果超出long的范围就不行了。
// 2. 在内部对常用的数字:-16 ~ 16 进行了优化。
// 提前把-16 ~ 16 先创建好BigInteger的对象,如果多次获取不会重新创建新的。
BigInteger bd5 = BigInteger.valueOf(16);
BigInteger bd6 = BigInteger.valueOf(16);
System.out.println(bd5 == bd6);// true

BigInteger bd7 = BigInteger.valueOf(17);
BigInteger bd8 = BigInteger.valueOf(17);
System.out.println(bd7 == bd8);// false

加法

1
2
3
BigInteger b1=new BigInteger("9");
BigInteger b2=new BigInteger("1");
BigInteger b3=b1.add(b2);
方法名 说明
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 boolean equals(Object x) 比较是否相同
public BigInteger pow(int exponent) 次幂
public BigInteger max/min(BigInteger val) 返回较大值/较小值
public int intValue(BigInteger val) 转为int类型整数,超出范围数据有误

原理:

在类里面,数字会被转化为补码

image-20250501233301902

存储方式:[符号位,第一个32位的十进制,第二个32位的十进制]

BigDecimal

方法名 说明
public static BigDecimal valueOf(double val) 获取对象
public BigDecimal add(BigDecimal val) 加法
public BigDecimal subtract(BigDecimal val) 减法
public BigDecimal multiply(BigDecimal val) 乘法
public BigDecimal divide(BigDecimal val) 除法
public BigDecimal divide(BigDecimal val, 精确几位, 舍入模式) 除法

与BigInteger差不多

5、正则表达式

作用:1、校验字符串是否满足规则2、在一段文本中查找满足的内容

字符类(只匹配一个字符)

正则表达式 说明
[abc] 只能是 a, b, 或 c
[^abc] 除了 a, b, c 之外的任何字符
[a-zA-Z] a 到 z、A 到 Z(包含范围)
[a-d[m-p]] a 到 d,或 m 到 p(并集)
[a-z&&[def]] a-z 和 def 的交集(结果为:d, e, f)
[a-z&&[^bc]] a-z 和非 bc 的交集(等同于 [a-ad-z]
[a-z&&[^m-p]] a-z 和除了 m-p 的交集(等同于 [a-lq-z]

预定义字符(只匹配一个字符)

正则表达式 说明
. 任何字符
\d 一个数字:[0-9]
\D 非数字:[^0-9]
\s 一个空白字符:[\t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w [a-zA-Z_0-9](英文、数字、下划线)
\W [^\w](一个非单词字符)
1
"a".matches("正则表达式");

数量词

正则表达式 说明
X? X,一次或0次
X* X,零次或多次
X+ X,一次或多次
X{n} X,正好n次
X{n,} X,至少n次
X{n,m} X,至少n但不超过m次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 验证手机号码:13112345678 13712345667 13945679027 139456790271
// 验证座机电话号码:020-2324242 02122442 027-42424 0712-3242434
// 验证邮箱号码:323232@qq.com zhangsan@itcast.cnn dlei0009@163.com dlei0009@pci.com.cn

String regex1 = "1[3-9]\\d{9}";

// 心得:
// 拿着一个正确的数据,从左到右依次去写。
// 13112345678
// 分成三部分:
// 第一部分:1 表示手机号码只能以1开头
// 第二部分:[3-9] 表示手机号码第二位只能是3-9之间的
// 第三部分:\\d{9} 表示任意数字可以出现9次,也只能出现9次
System.out.println("13112345678".matches(regex1));// true
System.out.println("13712345667".matches(regex1));// true
System.out.println("13945679027".matches(regex1));// true
System.out.println("139456790271".matches(regex1));// false

爬虫

十五、集合进阶

十六、Stream流

就是一个用来处理集合内容的东西

1
list1.stream().filter(name->name.startswith("张").filter(name.length()==3).forEach(name->System.out.println(name)));

Stream流的思想

流水线处理

Stream流的作用

结合了Lambda表达式,简化集合、数组的操作

Stream流的使用步骤:

① 先得到一条Stream流(流水线),并把数据放上去

② 利用Stream流中的API进行各种操作

操作类型 包含操作 特点
中间方法 过滤、转换 方法调用完毕之后,还可以调用其他方法(支持链式操作)
终结方法 统计、打印 最后一步,调用完毕之后,不能调用其他方法(流会关闭)
获取方式 方法名 说明
单列集合 default Stream<E> stream() Collection中的默认方法
双列集合 无法直接使用stream流
数组 public static <T> Stream<T> stream(T[] array) Arrays工具类中的静态方法
一堆零散数据 public static<T> Stream<T> of(T... values) Stream接口中的静态方法

十七、方法引用

基本特点

把已经有的方法拿过来用,当作函数式接口中的抽象方法的方法体

方法引用的使用条件

1. 引用处必须是函数式接口

即接口中只有一个抽象方法,例如 ComparatorRunnable 等。

示例

1
2
3
4
5
6
7
Java// 函数式接口 Comparator 的匿名内部类实现
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1; // 自定义比较逻辑(降序)
}
});

2. 被引用的方法必须已经存在

需引用项目中已定义或JDK自带的方法(不能引用未实现的抽象方法)。

3. 被引用方法的形参和返回值需与抽象方法保持一致

  • 形参列表:被引用方法的参数类型、个数、顺序需与函数式接口的抽象方法完全相同。
  • 返回值类型:被引用方法的返回值类型需与抽象方法的返回值类型相同(或兼容)。

4. 被引用方法的功能要满足当前需求

被引用方法的逻辑需与抽象方法的预期功能一致。

示例: 若需实现降序排序,可引用已存在的 subtraction 方法(其逻辑为 n2 - n1):

1
2
3
4
Java// 已存在的方法(形参和返回值与 Comparator.compare 一致)
public int subtraction(int n1, int n2) {
return n2 - n1; // 功能:返回 n2 - n1(满足降序需求)
}
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
//匿名内部类
Arrays.sort(arr,new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2){
return o2-o1;
}
})

//lambda表达式
Arrays.sort(arr,(Integer o1,Integer o2)->{
return o2-o1;
});

//lambda表达式简化格式
Arrays.sort(arr,(o1,o2)->o2-o1);

//方法引用,subtraction是静态的,要用类名去引用
//::就是方法引用符号
Arrays.sort(arr,类名::subtraction);



//提前写好的函数,可以是java写好的也可以是第三方工具类
public static int subtraction(int num1,int num2){
return o2-o1;
}

方法引用的分类

1. 引用静态方法

  • 语法类名::静态方法名
  • 说明:引用某个类的静态方法,直接通过类名调用。
1
2
格式:类名::静态方法
范例:Integer::parseInt

2. 引用成员方法

子类 语法示例 说明
Ⅰ. 引用其他类的成员方法 对象::成员方法名 通过其他类的实例对象引用其成员方法
Ⅱ. 引用本类的成员方法 this::成员方法名 在本类中通过 this 引用当前实例的方法
Ⅲ. 引用父类的成员方法 super::成员方法名 在子类中通过 super 引用父类的方法

3. 引用构造方法

  • 语法类名::new
  • 说明:引用类的构造方法,用于创建对象(需匹配函数式接口的抽象方法参数)。

4. 其他调用方式

类型 语法示例 说明
Ⅰ. 使用类名引用成员方法 类名::成员方法名 适用于函数式接口的第一个参数为该类实例的场景(如 Stream 中的 map 方法)
Ⅱ. 引用数组的构造方法 数组类型[]::new 引用数组的构造方法,用于创建指定长度的数组(如 int[]::new

十八、异常

十九、File

  • File对象就表示一个路径,可以是文件的路径、也可以是文件夹的路径
  • 这个路径可以是存在,也允许不存在的

File构造方法

方法名称 说明
public File(String pathname) 根据文件路径创建文件对象
public File(String parent, String child) 根据父路径名字符串和子路径名字符串创建文件对象
public File(File parent, String child) 根据父路径对应文件对象和子路径名字符串创建文件对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//根据文件路径创建文件对象
String s="C:\\Users\\cya\\Desktop\\a.txt";
File f1=new File(s);
System.out.println(f1);

//根据父路径名字字符串和子路径名字字符串创建文件对象
//父路径:去掉文件名的路径---C:\\Users\\cya\\Desktop
//子路径:文件本身-----a.txt
String parent="C:\\Users\\cya\\Desktop";
String child="a.txt";
File f2=new File(parent,child);//或者这样File f2=new File(parent+"\\"+child);
System.out.println(f2);

//把一个File对象的路径和String的路径进行拼接
String parent2="C:\\Users\\cya\\Desktop";
String child2="a.txt";
File f3=new File(parent2);
File f4=new File(parent2,child2);
System.out.println(f4);

File常见成员方法

判断和获取

方法名称 说明
public boolean isDirectory() 判断此路径名表示的File是否为文件夹
public boolean isFile() 判断此路径名表示的File是否为文件
public boolean exists() 判断此路径名表示的File是否存在
public long length() 返回文件的大小(字节数量)
public String getAbsolutePath() 返回文件的绝对路径
public String getPath() 返回定义文件时使用的路径
public String getName() 返回文件的名称,带后缀
public long lastModified() 返回文件的最后修改时间(时间毫秒值)

细节:方法length只能返回文件大小,单位是字节,而文件夹的大小,要通过遍历文件才能获取到大小

创建和删除

方法名称 说明
public boolean createNewFile() 创建一个新的空的文件
public boolean mkdir() 创建单级文件夹
public boolean mkdirs() 创建多级文件夹
public boolean delete() 删除文件、空文件夹

重点:delete方法默认只能删除文件和空文件夹,,delete方法直接删除不走回收站

createNewFile方法创建的一定只能是文件

一般直接使用mkdirs这个方法

delete删除不了不为空的文件夹

获取并遍历

核心方法:listFiles()

方法名称 说明
public File[] listFiles() 获取当前路径下所有内容(文件/文件夹),返回File数组

重点:listFiles() 返回值规则

(根据调用者File对象表示的路径状态,返回不同结果)

路径状态 返回值说明
路径不存在 null
路径是文件 null(仅用于文件夹遍历)
路径是空文件夹 长度为0File数组(new File
路径是有内容的文件夹 数组包含所有文件和文件夹的File对象(包括非隐藏文件)
路径包含隐藏文件 数组包含所有内容(包括隐藏文件/文件夹)
路径需要权限才能访问 null(无权限时无法获取内容)

image-20250502170015588

所有获取并遍历的方法

方法名称 说明
public static File[] listRoots() 列出可用的文件系统根(如Windows的C盘、D盘)
public String[] list() 获取当前路径下所有内容的名称(返回字符串数组)
public String[] list(FilenameFilter filter) 利用文件名过滤器获取当前路径下所有内容
public File[] listFiles() 获取当前路径下所有内容(返回File对象数组)
public File[] listFiles(FileFilter filter) 利用文件过滤器获取当前路径下所有内容
public File[] listFiles(FilenameFilter filter) 利用文件名过滤器获取当前路径下所有内容

二十、IO流

IO概述

存储和读取数据的解决方案(本地文件,网络)

image-20250502120610755

io流中,谁在读写,以谁为参照物:程序(内存)

image-20250502120934322

纯文本文件:能用win自带的记事本打开,且可以读懂的文件

IO流的体系

image-20250502121550665

IO基础流

字节流

image-20250502154844316

FileOutputStream

操作本地文件的字符输出流,可以把程序中的数据写到本地文件中

1
2
3
4
5
6
//
FileOutputStream fos=new FileOutputStream("指定地址");
//写数据
fos.write(97);//97代表ASCII值
//释放资源
fos.close();

书写细节

1、参数是字符串的路径也可以是File对象

2、如果文件不存在就会创建一个新的文件出来,但要确保父级路径要存在

3、如果文件已经存在,则会清空文件(覆盖)

4、write方法写入的是ASCII对应的字符

5、每次用完,都要释放资源,不然会占用后台,导致后续不能对这个文件进行操作

FlieOutputStream写数据的三种方式

方法名称 说明
void write(int b) 一次写一个字节数据
void write(byte[] b) 一次写一个字节数组数据
void write(byte[] b, int off, int len) 一次写一个字节数组的部分数据

off表示起始索引,len表示个数

想要不那么麻烦的写入内容可以这样写

1
2
3
4
5
FileOutputStream fos =new FileOutputStream("文件地址");
String str ="abcdefg";
byte[] bytes=str.getBytes();
fos.write(bytes);
fos.close();

换行和续写

换行:再写一个换行就好

win:\r\n,在java中只需要写其中一个就好

Linux:\n

Mac:\r

image-20250502212001876

续写:FileOutputStream fos =new FileOutputStream(“文件地址”,true);

把续写开关打开就行

FileIntputStream

操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来。

  1. 创建字节输入流对象
  2. 读数据
  3. 释放资源
1
2
3
4
5
6
7
8
FileIntputStream fis =new FileIntputStream("文件地址");

int b1=fis.read();
System.out.println(b1);
fis.close();
//读取文件中第一个字符的ASCII值
//想要直接读取字符,可以直接强转char
System.out.println((char)b1);

FileIntputStream书写细节

1、如果文件不存在直接报错

2、一次只读一个字节,读出来的是ASCII值

3、读到文件末尾了,read方法会返回-1

4、释放资源

FileIntputStream循环读取

1
2
3
4
int b;
while(b=fis.read()!=-1){
System.out.println((char)b);
}

文件拷贝(读写一起用)

1
2
3
4
5
6
7
8
9
10
FileIntputStream fis =new FileIntputStream("文件地址");
FileOutputStream fos=new FileOutputStream("指定地址\\文件名",true);
//核心思想:边读边写
int b;
while(b=fis.read()!=-1){
fos.wirte(b);
}
//释放资源,规矩:先开的流最后关闭
fos.close();
fis.close();

FileIntputStream读取问题(一次FileIntputStream)

FileIntputStream每次只读取一个字节,所以比较慢

FileInputStream 一次读多个字节

核心读取方法

方法名称 说明
public int read() 一次读一个字节数据(返回字节值,末尾返回 -1
public int read(byte[] buffer) 一次读一个字节数组数据(推荐,效率更高)

重点:read(byte[] buffer) 详解

作用

一次读取多个字节到缓冲区数组 buffer 中,减少 I/O 次数,提升读取效率。

返回值
  • 实际读取的字节数(int类型):
    • 若缓冲区未装满(如文件剩余数据不足),返回实际读取的字节数;
    • 若已读取到文件末尾,返回 -1
注意事项
  • 尽可能装满数组:每次读取时,会尝试将 buffer 数组填满(最多读取 buffer.length 个字节)。
  • 缓冲区大小建议:
    • 推荐使用 1024 的整数倍(如 10242048),平衡内存占用和效率;
    • 大文件可使用更大缓冲区(如 1024*1024*5,即 5MB),减少循环次数。
1
2
3
4
5
6
FileIntputStream fis=new FileIntputStream("文件路径");
byte[] bytes=new byte[2];
int len=fis.read(bytes);//2

String str=new String(bytes);//变成字符串
fis.close();

btyes数组在FileIntputStream的读取中会被反复覆盖(如果最后一次读取没读满数组,会留下脏数据)

处理方法一:用多个len去接各自的长度,然后String str=new String(bytes,0,len);就行

加快拷贝速度(改写拷贝方法)

1
2
3
4
5
6
7
8
9
10
11
FileIntputStream fis =new FileIntputStream("文件地址");
FileOutputStream fos=new FileOutputStream("指定地址\\文件名",true);
//核心思想:边读边写
int len;
byte[] bytes=new byte[1024*1024*5];
while(len=fis.read(bytes)!=-1){
fos.wirte(bytes,0,len);
}
//释放资源,规矩:先开的流最后关闭
fos.close();
fis.close();

IO流的异常处理

try…catch异常处理

1
2
3
4
5
6
7
8
try{
Fileoutputstream fos = new Fileoutputstream("a.txt");
fos.write(97);
}catch (IOException e){
e.printstackTrace();
} finally{
fos.close(); //被finally控制的语句一定会执行,除非JVM退出
}

IO流的异常处理新方法

基本方法 手动释放资源

1
2
3
4
5
6
7
try{
可能出现异常的代码;
}catch(异常类名变量名){
异常的处理代码;
}finally{
执行所有资源释放操作;
}

**接口:AutoCloseable ** 资源用完最终自动释放

JDK7方案

1
2
3
4
5
try(创建流对象1;创建流对象2){
可能出现异常的代码;
}catch(异常类名变量名){
异常的处理代码;
}

JDK9方案

1
2
3
4
5
6
7
创建流对象1;
创建流对象2
try(流1;流2){
可能出现异常的代码;
}catch(异常类名变量名){
异常的处理代码;
}

字符集

image-20250504154113233

字符集 发布时间 主要特点 应用场景
GB2312 1981 简体中文国标,基础字符集 早期中文系统,兼容性场景
BIG5 1984 台湾繁体标准,仅支持繁体 台湾、香港等繁体环境
GBK(系统显示:ANSI) 2000 Windows默认,兼容简繁及生僻字 中国大陆Windows系统、本地文件
Unicode 国际标准 全球语言统一编码,跨平台跨语言 全球化应用、互联网、编程开发

GBK是兼容ASCII的

image-20250504155053612

image-20250504155110035

Unicode字符集(面试会考)

image-20250504160201764

image-20250504160437705

image-20250504160528769

image-20250504160616513

image-20250504161619589

Unicode是字符集,UTF-8是一种编码方式

Java使用中文乱码的原因

1:读取数据时未读完整个汉字

2:编码和解码时的方式不一样

如何不产生乱码?

  1. 不要用字节流读取文本文件
  2. 编码解码时使用同一个码表,同一个编码方式

Java中的编码和解码方法

image-20250504163119262

idea默认是UTF-8

1
2
3
4
5
6
7
8
String str ="ai一二";
byte[] bytes1=str.getBytes();
//指定
byte[] bytes2=str.getBytes("GBK");

//解码(反过来的)
String str1=new String(bytes1);
String str2=new String(bytes2,"GBK");//要和编码的方式相同,不同会乱码

字符流

字符流的底层其实就是字节流

字符流=字节流+字符集

特点:

  • 输入流:一次读一个字节,遇到中文时,一次读多个字节
  • 输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中

image-20250504170218033

FileReader

1、创建字符输入流对象

构造方法 说明
public FileReader(File file) 创建字符输入流关联本地文件
public FileReader(String pathname) 创建字符输入流关联本地文件

细节1:如果文件不存在,就直接报错。

2、读取数据

成员方法 说明
public int read() 读取单个字符数据,读到末尾返回 -1
public int read(char[] buffer) 读取多个字符到缓冲区数组,读到末尾返回 -1

细节1:按字节进行读取遇到中文,一次读多个字节,读取后解码,返回一个整数
细节2:读到文件末尾了,read方法返回-1。

3、释放资源

就是close();

无参read代码演示

1
2
3
4
5
6
7
8
9
FileReader fr =new FileReader("文件地址");
//空参read的底层也字节流,是遇到中文才会一次读取多个
//最后返回字符集上的数字!!!
int ch;
while((ch=fr.read())!=-1){
System.out.println(ch);
}

fr.close();

有参read代码演示

1
2
3
4
5
6
7
8
9
FileReader fr =new FileReader("文件地址");
//最后返回字符集上的是强转后的字符!!!
char[] chars=new char[2];
int len;
while((len=fr.read(chars))!=-1){
System.out.print(new String(chars,0,len));//用print
}

fr.close();

FileWriter

构造方法

构造方法 说明
public FileWriter(File file) 创建字符输出流关联本地文件
public FileWriter(String pathname) 创建字符输出流关联本地文件
public FileWriter(File file, boolean append) 创建字符输出流关联本地文件,支持续写
public FileWriter(String pathname, boolean append) 创建字符输出流关联本地文件,支持续写

成员方法

成员方法 说明
void write(int c) 写出一个字符(c 为字符的ASCII值)
void write(String str) 写出一个字符串
void write(String str, int off, int len) 写出一个字符串的部分内容(从 off 索引开始,长度为 len
void write(char[] cbuf) 写出一个字符数组
void write(char[] cbuf, int off, int len) 写出字符数组的部分内容(从 off 索引开始,长度为 len

FileWriter书写细节

  1. 创建字符输出流对象

    细节1:参数是字符串表示的路径或者File对象都是可以的

    细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的

    细节3:如果文件已经存在,则会清空文件,如果不想清空可以打开续写开关

  2. 写数据

    细节:如果write方法的参数是整数,但是实际上写到本地文件中的是整数在字符集上对应的字符

  3. 释放资源

    细节:每次使用完流之后都要释放资源

1
2
fos.write(25105)//字节流编码格式超出一个字节会乱码
fw.write(25105)//FileWriter字符流会根据字符集的编码方式,编码之后再写到文件里去

字符流读取原理解析

  1. 创建字符输入流对象

    底层:关联文件,并创建缓冲区(长度为8192的字节数组)

  2. 读取数据

    底层:1.判断缓冲区中是否有数据可以读取

    ​ 2.缓冲区没有数据:就从文件中获取数据,装到缓冲区中,每次尽可能装满缓冲区

    ​ 如果文件中也没有数据了,返回-1

    3.缓冲区有数据:就从缓冲区中读取。

    空参的read方法:一次读取一个字节,遇到中文一次读多个字节,把字节解码并转成十进制返回

    有参的read方法:把读取字节,解码,强转三步合并了,强转之后的字符放到数组中

字符流输出原理解析

flush和close方法

成员方法 说明
public void flush() 将缓冲区中的数据,刷新到本地文件中
public void close() 释放资源/关闭流

flush刷新:刷新之后,还可以继续往文件中写出数据
close关流:断开通道,无法再往文件中写出数据

IO高级流

image-20250504230829831

缓冲流

image-20250504231117834

字节缓冲流

image-20250504231150892

方法名称 说明
public BufferedInputStream(InputStream is) 把基本字节输入流包装成高级缓冲流,提高读取数据的性能
public BufferedOutputStream(OutputStream os) 把基本字节输出流包装成高级缓冲流,提高写出数据的性能

原理:底层自带了长度为8192的缓冲区提高性能

转换流

序列化流

打印流

压缩流

Commons-io

二十一、多线程和JUC

二十二、网络编程

网络编程概述

在网络通信协议下,不同计算机上运行的程序,进行数据传输。

java中可以使用java.net包下的技术开发网络应用程序

常用架构

CS和BS

image-20250505211343248

BS:更新功能,不需要用户更新,只需要刷新网页即可。

BS/CS架构的优缺点对比

架构类型 优点 缺点
BS(Browser/Server)(浏览器/服务器架构) 1. 开发成本低:不需要开发客户端,只需开发服务端2. 使用便捷:用户无需下载安装,打开浏览器即可使用 1. 体验受限:应用过大时,页面加载慢,用户体验受影响2. 功能依赖浏览器:复杂交互和本地资源访问能力较弱
CS(Client/Server)(客户端/服务器架构) 1. 用户体验好:界面可做的非常精美,交互流畅2. 功能强大:支持复杂业务逻辑和本地资源访问(如桌面应用) 1. 开发成本高:需同时开发客户端和服务端2. 维护麻烦:用户需要下载安装客户端,更新时需重新安装

核心差异总结

维度 BS架构 CS架构
客户端依赖 无(依赖浏览器) 必须安装专用客户端
开发工作量 服务端单端开发 客户端+服务端双端开发
适用场景 轻量应用、跨平台访问(如网页应用、OA系统) 复杂交互、高性能需求(如图形软件、ERP系统)
更新方式 服务端更新,用户无感知 客户端手动更新

网络编程三要素

  • IP:设备在网络中的地址,是唯一的标识。
  • 端口号:应用程序在设备中唯一的标识。
  • 协议:数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp。

IP

  • 全称:InternetProtocol,是互联网协议地址,也称IP地址。是分配给上网设备的数字标签
  • 通俗理解:上网设备在网络中的地址,是唯一的
  • 常见的IP分类为:IPv4、IPv6

IPV4

image-20250505213943816

IPV4的细节

IPv4的地址分类形式

  • 公网地址(万维网使用)和私有地址(局域网使用)。
  • 192.168.开头的就是私有址址,范围即为192.168.0.0–192.168.255.255,专门为组织机构内部使用,以此节省IP

特殊IP地址

  • 127.0.0.1,也可以是localhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机。

常用的CMD命令

  • ipconfig:查看本机IP地址
  • ping:检查网络是否连通

IPV6

image-20250505214151541

image-20250505214352394

InetAddress的使用

1
2
3
4
5
6
7
8
InetAddress address =InetAddress.getByName("");//String host
//主机名称可以是机器名称,也可以是IP地址
String getHostname()//获取IP地址的主机名,如果返回的是IP,说明网络不好
String getHostAddress()//返回文本显示中的IP地址
System.out.println(address);


//以上的代码是前置代码,用于获取设备的IP地址

端口号

应用程序在设备中唯一的标识。
端口号:

  • 由两个字节表示的整数,取值范围:0~65535
  • 其中0~1023之间的端口号用于一些知名的网络服务或者应用
  • 我们自己使用1024以上的端口号就可以了。

注意:一个端口号只能被一个应用程序使用。

协议

计算机网络中,连接和通信的规则被称为网络通信协议

  • OSI参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推广
  • TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。
OSI参考模型 TCP/IP参考模型 TCP/IP参考模型各层对应协议 面向哪些
应用层 一把是应用程序需要关注的。如浏览器,邮箱。程序员一般在这一层开发
表示层 应用层 HTTP、FTP、Telnet、DNS…
会话层
传输层 传输层 TCP、UDP、… 选择传输使用的TCP,UDP协议
网络层 网络层 IP、ICMP、ARP… 封装自己的IP,对方的IP等信息
数据链路层 物理+ 硬件设备。 转换成二进制利用物理
物理层 数据链路层 010100101010100101010… 设备传输

UDP协议和TCP协议

image-20250506155521331

  • UDP协议:速度快、可以应用在一些丢失数据不会出现大影响的场景如,视频会议,语音通话、在线视屏、直播
  • TCP协议:可以应用在一些不能丢失数据的场景如,下载软件、文字聊天、发邮件、传输文件

UDP通信程序

发送数据:

步骤 描述
① 找快递公司 创建发送端的DatagramSocket对象
② 打包礼物 数据打包(DatagramPacket
③ 快递公司发送包裹 发送数据
④ 付钱走人 释放资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//创建DatagramSocket对象(快递公司)
//空参:所有可用端口中随机一个进行使用
//有参:指定一端口进行绑定
DatagramSocket ds=new DatagramSocket();

//打包数据
String str="你好";
byte[] bytes=str.getBytes();
InetAddress address =InetAddress.getByName("127.0.0.1");
int port =10086;
DatagramPacket dp =new DatagramPacket(bytes,bytes.length,address,port);
//(发送的内容,发生的长度,要发送到的设备,发给那个端口)
//发送数据
ds.send(dp);

//释放资源
ds.close();

接收数据:

步骤 描述
① 找快递公司 创建接收端的DatagramSocket对象(需指定端口)
② 接收箱子 创建数据包对象(DatagramPacket)用于接收数据
③ 从箱子里面获取礼物 接收数据并解析数据包内容
④ 签收走人 释放资源(关闭DatagramSocket
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
//创建DatagramSocket对象
//在接收的时候,端口一定要写
//而且要写和发送的端口一样,如上面发送的端口是10086,就填10086
DatagramSocket ds=new DatagramSocket(10086);


//接收数据
//新建空间
byte[] bytes=new byte[1024];
//新建一个“箱子”去接收数据
DatagramPacket dp =new DatagramPacket(bytes,bytes.length);
//bytes.length:要用多少来接数据


//该方法是堵塞的
//程序执行到这一步,会一直在这里等发送端发消息
ds.receive(dp);

//解析数据
byte[] bytes=dp.getData();
int len=dp.getLength();
InetAddress address =dp.getAddress();
int port =dp.getPort();


dp.close();

要先运行发送的程序,在运行接收的程序

UDP的三种通信方式

通信方式 说明 关键信息
① 单播 一对一通信,之前的基础UDP代码默认为此方式 - 目标地址为单个IP(如 192.168.1.100)- 代码示例:普通UDP发送/接收
② 组播 一对多通信,发送到组播地址,加入该组的主机均可接收 - 组播地址范围224.0.0.0 ~ 239.255.255.255- 预留地址224.0.0.0 ~ 224.0.0.255(用于本地网络组播)
③ 广播 一对所有通信,发送到广播地址,同一网段内所有主机均可接收 - 广播地址255.255.255.255(限制在本地子网,无法跨路由)

**单播:**给一个设备发数据

之前的代码就是单播

**组播:**给一组设备发数据

发送数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//创建MulticastSock对象
MulticastSock ms=new MulticastSock();

//创建DatagramPacket对象
String s="你好";
byte[] bytes=s.getBytes();
InetAddress address=InetAddress.getByName("224.0.0.1");//指定组播地址
int port=10000;

DatagramPacket datagramPacket =new DatagramPacket(bytes,bytes.length,address,port);

ms.send(datagramPacket);

ms.close();

接收数据(因为是组播,所以要多建几个,但是必须是同个组播地址):

1
2
3
4
5
6
7
8
9
10
11
12
//创建MulticastSock对象
MulticastSock ms=new MulticastSock(10000);
//将当前本机添加到224.0.0.1中
InetAddress address=InetAddress.getByName("224.0.0.1");
ms.joinGroup(address);

byte[] bytes=new byte[1024];
DatagramPacket dp =new DatagramPacket(bytes,bytes.length);

ms.receive(dp);


广播:

只需要改一个地方(在单播的代码里改)

1
InetAddress address=InetAddress.getByName("225.255.255.255");//改为广播地址

TCP通信程序

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象
通信之前要保证连接已经建立
通过Socket产生lO流来进行网络通信

image-20250506201505375

Client的发送数据

1
2
3
4
5
6
7
8
9
10
11
//创建Socket对象
//在创建对象同时会连接服务器,如果连接不上,代码会报错
Socket socket=new Socket("127.0.0.1",10000);

//可以从连接通道中获取输出流
OutputStream os=socket.getOutputStream();

os.write("你好你好",getBytes());

os.close();
socket.close();

Server的接收数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//创建ServerSocket对象
ServerSocket ss=new ServerSocket(10000);

//监听客户端的链接,该方法是堵塞的
Socket socket =ss.accept();

//从连接通道中获取输入流读取数据
InputStream is =socket.getInputStream();
int b;
while((b=is.read())!=-1){
System.out.print((char)b);
}

socket.close();
ss.close();

服务器用字节流接收数据会乱码,要用字符流。是要转换

1
2
3
4
5
6
7
8
9
10
//从连接通道中获取输入流读取数据
InputStream is =socket.getInputStream();
InputStreamReader isr =new InputStreamReader(is);
//为了提高效率,用缓冲流
BufferedReader br=new BufferedReader(isr);
//可以写在一起:BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
int b;
while((b=br.read())!=-1){
System.out.print((char)b);
}

三次握手,四次挥手

三次握手

image-20250506212717419

四次挥手

image-20250506212859635

二十三、反射

二十四、动态代理

其他文章
cover
Web笔记
  • 25/03/29
  • 17:48
  • 17.3k
  • 72
cover
Hello World
  • 23/09/01
  • 17:48
  • 75
  • 1
目录导航 置顶
  1. 1. 一、思想:
  2. 2. 二、Win系统快捷键
  3. 3. 三、CMD
    1. 3.1. 1、CMD常见代码:
    2. 3.2. 2、CMD注意事项
  4. 4. 四、Java学习的前项准备
    1. 4.1. 1、JDK相关链接
    2. 4.2. 2、JDK的内容
    3. 4.3. 3、手动配置环境变量(在电脑的高级系统设置里)
      1. 4.3.1. 3.1 操作界面
      2. 4.3.2. 3.2 变量设置
      3. 4.3.3. 3.3 部分问题
    4. 4.4. 4、Hello World程序(在非集成环境下)
      1. 4.4.1. 4.1 代码:
      2. 4.4.2. 4.2 编译(要在文件所在的盘符下启动命令行):
      3. 4.4.3. 4.3 运行(要在文件所在的盘符下启动命令行):
    5. 4.5. 5、高级记事本的使用(以Notepad++为例)
  5. 5. 五、Java的开发方向
    1. 5.1. 1、Java的三大平台
    2. 5.2. 2、Java SE
    3. 5.3. 3、Java ME(已经没落了)
    4. 5.4. 4、Java EE
    5. 5.5. 5、Java的运用
  6. 6. 六、Java的优点与特点
    1. 6.1. 1、优点
    2. 6.2. 2、自身优越性
  7. 7. 七、Java可以跨平台的原因
    1. 7.1. 1、高级语言的编译运行方式
    2. 7.2. 2、编译型(不能跨平台)
    3. 7.3. 3、解释型
    4. 7.4. 4、混合型
  8. 8. 九、JRE和JDK
    1. 8.1. 1、JDK(Java开发工具包)
    2. 8.2. 2、JRE(Java运行环境)(不需要修改,只需要运行)
    3. 8.3. 3、包含关系
  9. 9. 十、基础语法
    1. 9.1. 1、class
    2. 9.2. 2、字面量
    3. 9.3. 3、输出和输入
    4. 9.4. 4、转义字符
    5. 9.5. 5、变量
    6. 9.6. 6、计算机的存储规则
      1. 9.6.1. 6.1 任意进制转十进制
      2. 9.6.2. 6.2 十进制转其他进制
      3. 9.6.3. 6.3 ASCII码表
      4. 9.6.4. 6.4 图片
      5. 9.6.5. 6.5 声音
    7. 9.7. 7、标识名
  10. 10. 十一、IDEA
    1. 10.1. 1、IDEA工程组成
    2. 10.2. 2、IDEA简化语句
      1. 10.2.1. 2.1 创建main函数
      2. 10.2.2. 2.2 创建带布尔的if语句
      3. 10.2.3. 2.3 创建完整的for语句/带布尔的while语句
      4. 10.2.4. 2.4 创建对象的语句
      5. 10.2.5. 2.5 创建输出的语句
      6. 10.2.6. 2.6 创建异常的语句
      7. 10.2.7. 2.7 List各种操作的语句
    3. 10.3. 3、IDEA快捷键
      1. 10.3.1. (1)推荐操作
      2. 10.3.2. (2)代码阅读
      3. 10.3.3. (3)对文件操作
      4. 10.3.4. (4)Debug
  11. 11. 十二、补充
    1. 11.1. 1、数据类型转换
      1. 11.1.1. 1.1 隐式转换(自动类型提升)
      2. 11.1.2. 1.2 强制转换(手动)
      3. 11.1.3. 1.3 字符串“+”操作
    2. 11.2. 2、逻辑运算符
    3. 11.3. 3、短路逻辑运算符
    4. 11.4. 4、三元运算符
    5. 11.5. 5、运算符优先级
    6. 11.6. 6、原码、反码、补码
    7. 11.7. 7、分支语句
      1. 11.7.1. 7.1 switch的相关知识点
      2. 11.7.2. 7.2 if和switch的使用区别
      3. 11.7.3. 7.3 while的补充
      4. 11.7.4. 7.4 数组的补充
      5. 11.7.5. 7.5 数组的内存图
    8. 11.8. 8、方法(函数)
      1. 11.8.1. 8.1 完整格式:
      2. 11.8.2. 8.2 函数重载
      3. 11.8.3. 8.3 方法的内存原理
      4. 11.8.4. 8.4 方法的值传递
  12. 12. 十三、Java的对象
    1. 12.1. 1、设计对象
      1. 12.1.1. 1.1 定义类
      2. 12.1.2. 1.2 得到类的对象
      3. 12.1.3. 1.3 对象的三大特征
      4. 12.1.4. 1.4 创建类的注意事项
    2. 12.2. 2、构造方法
      1. 12.2.1. (1)格式:
      2. 12.2.2. (2) 注意事项:
    3. 12.3. 3、标准JavaBean类
    4. 12.4. 4、对象内存图
      1. 12.4.1. 4.1 一个对象的内存图
      2. 12.4.2. 4.2 两个对象的内存图
      3. 12.4.3. 4.3 两个引用指向同一个对象
      4. 12.4.4. 4.4 基本数据类型和引用数据类型
      5. 12.4.5. 4.5 this内存图
      6. 12.4.6. 4.6 成员变量和局部变量
    5. 12.5. 5、API与API帮助文档
      1. 12.5.1. (1)API
      2. 12.5.2. (2)API帮助文档
    6. 12.6. 6、字符串
      1. 12.6.1. 6.1 字符串的众多操作和学习内容
      2. 12.6.2. 6.2 String
      3. 12.6.3. 6.3 StringBuilder
      4. 12.6.4. 6.4 StringJoiner
      5. 12.6.5. 6.5 字符串的底层原理
    7. 12.7. 7、集合
      1. 12.7.1. 7.1 初识集合
      2. 12.7.2. 7.2 集合基础
    8. 12.8. 8、面向对象进阶
      1. 12.8.1. 8.1 static
      2. 12.8.2. 8.2 继承
      3. 12.8.3. 8.3 多态
      4. 12.8.4. 8.4 包、final、权限修饰符、代码块
      5. 12.8.5. 8.5 抽象类
      6. 12.8.6. 8.6 接口
      7. 12.8.7. 8.7 内部类
  13. 13. 十四、常用API
    1. 13.1. 1、Math
    2. 13.2. 2、System
    3. 13.3. 2、Runtime
    4. 13.4. 3、Object和Objects
    5. 13.5. 4、BigInteger和BigDecimal
      1. 13.5.1. BigInteger
      2. 13.5.2. BigDecimal
    6. 13.6. 5、正则表达式
  14. 14. 十五、集合进阶
  15. 15. 十六、Stream流
    1. 15.1. Stream流的思想
      1. 15.1.1. Stream流的作用
      2. 15.1.2. Stream流的使用步骤:
  16. 16. 十七、方法引用
    1. 16.1. 基本特点
      1. 16.1.1. 方法引用的使用条件
    2. 16.2. 方法引用的分类
  17. 17. 十八、异常
  18. 18. 十九、File
    1. 18.1. File构造方法
    2. 18.2. File常见成员方法
      1. 18.2.1. 判断和获取
      2. 18.2.2. 创建和删除
      3. 18.2.3. 获取并遍历
      4. 18.2.4. 所有获取并遍历的方法
  19. 19. 二十、IO流
    1. 19.1. IO概述
    2. 19.2. IO流的体系
    3. 19.3. IO基础流
      1. 19.3.1. 字节流
      2. 19.3.2. IO流的异常处理
      3. 19.3.3. 字符集
      4. 19.3.4. Unicode字符集(面试会考)
      5. 19.3.5. Java使用中文乱码的原因
      6. 19.3.6. Java中的编码和解码方法
      7. 19.3.7. 字符流
    4. 19.4. IO高级流
  20. 20. 二十一、多线程和JUC
  21. 21. 二十二、网络编程
    1. 21.1. 网络编程概述
      1. 21.1.1. BS/CS架构的优缺点对比
      2. 21.1.2. 核心差异总结
    2. 21.2. 网络编程三要素
      1. 21.2.1. IP
      2. 21.2.2. 端口号
      3. 21.2.3. 协议
  22. 22. 二十三、反射
  23. 23. 二十四、动态代理
请输入关键词进行搜索