一、java是什么 Java 是由 Sun Microsystems(后被 Oracle 收购)于 1995 年推出的跨平台面向对象编程语言 ,核心设计理念是「Write Once, Run Anywhere(一次编写,到处运行)」,凭借简洁性、安全性、可移植性成为全球最主流的编程语言之一,广泛应用于企业级开发、移动开发、大数据、云计算等领域。
核心特性
跨平台性 :通过 JVM(Java 虚拟机)实现 ——Java 代码编译为与平台无关的字节码(.class 文件),JVM 负责将字节码解释 / 编译为对应操作系统的机器码,无需针对不同系统修改代码。
面向对象 :完全遵循封装、继承、多态三大特性,万物皆对象(除基本数据类型),代码模块化、易维护。
安全性 :内置安全机制(如字节码验证、沙箱机制),避免内存溢出、非法访问,适合网络 / 分布式应用。
健壮性 :自动垃圾回收(GC)管理内存,减少内存泄漏;强类型检查、异常处理机制降低程序崩溃风险。
多线程 :内置多线程 API,支持并发编程,适合高并发场景(如电商、服务器开发)。
开源生态 :拥有丰富的标准库(IO、网络、集合等)和第三方框架(Spring、MyBatis、Hadoop 等),开发效率极高。
二、java概述 JDK 基本介绍 JDK 的全称(JavaDevelopment Kit Java 开发工具包) JDK =JRE+java 的开发工具 [java,javac,javadoc,javap 等] JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE。所以安装了JDK,就不用在单独 安装JRE了。 JRE 基本介绍 JRE(Java Runtime Environment ) JRE =JVM+Java 的核心类库[类] Java 运行环境) 包括Java虚拟机(JVMJavaVirtual Machine)和 Java 程序所需的核心类库等,如果想要运行一个开发好的Java程序, 计算机中只需要安装JRE即可。 JDK、JRE 和 JVM的包含关系 1) JDK=JRE+ 开发工具集(例如Javac,java编译工具等) JRE=JVM+JavaSE标准类库(java核心类库) 三、环境变量配置 流程: 在我的电脑右击属性,选择高级系统设置,选择环境变量,再系统变量选择新建, 名称为 %JAVA_HOME% 值为下载的 jdk路径 再path编辑输入 %JAVA_HOME%\bin即可 四、变量
分类
别名
定义
修饰
生命周期
调用方式
示例
局部变量
方法变量
定义在方法 / 代码块内
无权限修饰、不能加static
方法调用时创建,执行完销毁
仅方法内直接使用
int a = 10;
成员变量 (实例变量)
对象变量
定义在类中、方法外
可加private/public/protected
对象创建时存在,对象回收销毁
对象。变量名
User.name;
静态变量 (类变量)
全局变量
类中方法外,加static
必带static
类加载时初始化,全局唯一
类名。变量名
Math.PI
1 2 3 4 5 6 7 8 9 10 11 package com.Variable_1;public class variable { private int age; private static int age2; public void test () { int name; } }
基本数据类型(8类):
数据类型
占用字节
默认值
取值 / 说明
书写注意
byte
1
0
-128 ~ 127
字节类型
short
2
0
-32768 ~ 32767
短整型
int
4
0
日常整型默认
最常用
long
8
0L
长整型
数值后加 L
float
4
0.0f
单精度浮点数
数值后加 F/f
double
8
0.0
双精度浮点数
小数默认类型
char
2
\u0000
单个字符
单引号 'a'
boolean
1
false
只有 true /false
不参与运
引用数据类型:
引用类型分类
代表类型
默认值
特点
示例
字符串类型
String
null
不可变字符序列,引用类型
String s = "abc";
数组
基本类型数组 / 对象数组
null
固定长度,存储批量数据
int[] arr = new int[5];
自定义类
自己写的实体类
null
new 实例化,封装属性方法
User user = new User();
集合框架
List、Set、Map
null
长度可变,增删灵活
List<String> list = new ArrayList<>();
系统类
Object、Date、Scanner 等
null
JDK 内置工具 / 实体类
Date date = new Date();
数据强转: 1.隐式转换 规则:小范围 → 大范围,自动转,无损
优先级(从小到大)
byte → short → int → long → float → double
char → int
1 2 int a = 10 ;double b = a;
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 public class CastDemo { public static void main (String[] args) { double d = 5.99 ; int num = (int ) d; System.out.println(num); int a = 130 ; byte b = (byte ) a; System.out.println(b); int code = 97 ; char ch = (char ) code; System.out.println(ch); long lo = 9999L ; int in = (int ) lo; System.out.println(in); float f = 10.8f ; byte by = (byte ) f; System.out.println(by); } }
五、转义符和注释 1.转义符:
转义符
作用
说明
\n
换行
常用,Windows/Linux 通用
\r
回车
回到当前行开头
\r\n
回车 + 换行
Windows 系统默认换行
\t
制表符(空格缩进)
相当于按 Tab 键
\\
反斜杠本身
打印 \
\"
双引号
打印 “
\'
单引号
打印 ‘
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class NewLineDemo { public static void main (String[] args) { System.out.print("第一行\n第二行" ); System.out.println("--------" ); System.out.print("A\r\nB" ); System.out.println("--------" ); System.out.println("姓名\t年龄" ); System.out.println("张三\t18" ); } }
2.注释 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 IDE相关特殊标记
六、运算符 1.算数运算符
符号
名称
作用
示例
+
加
求和、字符串拼接
5+3
-
减
求差
5-3
*
乘
乘积
5*3
/
除
整数相除取整
5/2 = 2
%
取模 / 取余
求余数
5%2 = 1
++
自增
自身 + 1
a++
--
自减
自身 - 1
a--
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Operator { public static void main (String[] args) { int a = 10 ; int b = 3 ; System.out.println(a + b); System.out.println(a - b); System.out.println(a * b); System.out.println(a / b); System.out.println(a % b); int x = 5 ; System.out.println(x++); System.out.println(++x); } }
2.赋值运算符
符号
作用
等价写法
=
普通赋值
a = 10
+=
加后赋值
a += 5 → a = a + 5
-=
减后赋值
a -= 5 → a = a - 5
*=
乘后赋值
a *= 5 → a = a * 5
/=
除后赋值
a /= 5 → a = a / 5
%=
取余赋值
a %= 5 → a = a % 5
1 2 3 4 5 6 7 8 int num = 10 ;num += 5 ; num -= 3 ; num *= 2 ; num /= 4 ; num %= 4 ; System.out.println(num);
3.关系运算符
符号
含义
>
大于
<
小于
>=
大于等于
<=
小于等于
==
等于(比较值)
!=
不等于
1 2 3 4 5 6 7 8 9 int m = 20 ;int n = 15 ;System.out.println(m > n); System.out.println(m < n); System.out.println(m >= 20 ); System.out.println(m <= 15 ); System.out.println(m == n); System.out.println(m != n);
4.逻辑运算符
符号
名称
特点
&&
短路与
左边 false,右边不执行
||
短路或
左边 true,右边不执行
!
逻辑非
取反
1 2 3 4 5 6 7 8 9 10 int score = 80 ;System.out.println(score >= 60 && score <= 100 ); System.out.println(score < 60 || score > 50 ); System.out.println(!(score > 50 ));
5.位运算符(了解)
符号
名称
规则(核心口诀)
&
按位与
同为 1 才是 1,有 0 则 0
`
`
按位或
同为 0 才是 0,有 1 则 1
^
按位异或
相同为 0,不同为 1
~
按位取反
0 变 1,1 变 0
<<
左移
整体左移,低位补 0 → 等价 ×2
>>
右移(符号右移)
整体右移,高位补符号位 → 等价 ÷2
>>>
无符号右移
整体右移,高位统一补 0
6.三元运算符
1 2 3 4 int age = 17 ;String res = age >= 18 ? "成年" : "未成年" ;System.out.println(res);
七、标识符规则 标识符就是:变量名、类名、方法名、常量名 合法字符: 由 字母 (A-Za-z)、数字 (0-9)、下划线_、美元符号 $ 组成
不能以数字开头
可以用中文(但绝对不推荐 )
强制禁止: 不能是 Java 关键字 (while、for、if、class、public 等)
不能有 空格、特殊符号 (# @ ! * - 都不行)
区分大小写:name 和 Name 是两个不同标识符
八、Scanner和Random API 1.Scanner键盘输入
方法
作用
说明
nextInt()
读取整数
只能输入 int 类型,遇到空格 / 回车结束
nextDouble()
读取小数
读取浮点型数字
next()
读取单个单词
遇到空格、回车自动截断,不能读带空格的句子
nextLine()
读取一整行
可以读取带空格的完整一句话,按回车结束
nextBoolean()
读取布尔值
只能输入 true /false
nextByte()
读取 byte 类型
字节整数
nextShort()
读取 short 类型
短整型
nextLong()
读取 long 类型
长整型
nextFloat()
读取 float 类型
单精度小数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.API;import java.util.Scanner;public class scanner { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); System.out.println("输入数字:" ); int i = scanner.nextInt(); System.out.println("输出:" + i); scanner.close(); } }
2.Random
r.nextInt(n)
随机 int 整数
正负全部整数
r.nextInt(n,m)
随机整数
0 ~ n-1
r.nextDouble(n)
随机小数
0.0 ~ 1.0
r.nextBoolean(n)
随机布尔
true / false
r.nextLong(n)
随机长整数
大范围正负长整型
1 2 3 4 5 6 7 8 9 10 11 package com.API;import java.util.Random;public class random { public static void main (String[] args) { Random random = new Random (); int i = random.nextInt(10 ); System.out.println(i); } }
九、流程控制语句 1. if语句 1 2 3 4 5 6 7 8 9 if (条件1 ){ }else if (条件2 ){ } ... else { 都不满足执行 }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package com.ProcessControl_3;import java.util.Scanner;public class If { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); System.out.print("请输入数字:" ); int count = scanner.nextInt(); if (count == 1 ){ System.out.println(1 ); }else if (count == 2 ){ System.out.println(2 ); }else if (count == 3 ){ System.out.println(3 ); }else { System.out.println(count); } } }
2. switch语句 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 package com.ProcessControl_3;import java.util.Scanner;public class Switch { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); System.out.print("请输入数字:" ); int count = scanner.nextInt(); switch (count){ case 1 ,4 : System.out.println("星期1" ); break ; case 2 : case 5 : System.out.println("星期2" ); break ; case 3 : System.out.println("星期3" ); break ; default : System.out.println("其他" ); } switch (count){ case 1 -> System.out.println("星期1" ); case 2 -> System.out.println("星期2" ); default -> System.out.println("其他" ); } } }
3. for语句 1 2 3 for (初始化表达式; 判断条件; 步进表达式){ 循环体; }
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.ProcessControl_3;public class For { public static void main (String[] args) { for (int i = 0 ; i < 12 ; i++){ System.out.println(i); } for (int i = 0 ,j = 0 ; i < 12 ; i++,j++){ System.out.println(i + j); } } }
4. while语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.ProcessControl_3;public class While { public static void main (String[] args) { int count = 0 ; while (true ){ System.out.println(111 ); count++; if (count == 10 ){ break ; } } } }
5. do-while语句(了解)
6.跳转控制语句 1. break 退出整个循环,一般用于 while或for循环 2.continue 退出当前循环 3.return 退出整个函数 十、数组 数组是 同一类型、固定长度、连续存放的一组容器 1.定义方式 1 2 3 4 5 6 7 int [] arr = new int [5 ];int [] arr = new int []{10 ,20 ,30 };int [] arr = {10 ,20 ,30 };
2.数组遍历 1 2 3 4 5 6 7 8 9 10 11 int [] arr = {11 ,22 ,33 ,44 };for (int i = 0 ; i < arr.length; i++){ System.out.println(arr[i]); } for (int i : arr){ System.out.println(arr[i]); }
3.传递机制 基本数据类型传递机制是值拷贝,引用数据类型是传递的地址,为地址拷贝 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int [] arr = {11 ,33 ,44 };int [] arr1 = arr; arr1[0 ] = 77 ; for (int i = 0 ;i < arr.length; i++){ System.out.println(arr[i]); } int [] arr2 = {55 ,33 ,22 ,44 };int [] arr3 = new int [arr2.length];arr3[0 ] = 66 ; for (int i = 0 ;i < arr2.length;i++){ System.out.println(arr2[i]); }
4.二维数组 定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int [][] arr = new int [3 ][2 ];int [][] arr = new int [3 ][];arr[0 ] = new int [2 ]; arr[1 ] = new int [4 ]; int [][] arr = { {1 ,2 ,3 }, {4 ,5 }, {6 ,7 ,8 ,9 } }; arr[0 ][1 ];
遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int [][] arr = { {1 ,2 ,3 }, {4 ,5 ,6 }, {7 ,8 ,9 } }; for (int i = 0 ; i < arr.length; i++) { for (int j = 0 ; j < arr[i].length; j++) { System.out.print(arr[i][j] + " " ); } System.out.println(); } for (int [] row : arr) { for (int n : row) { System.out.print(n + " " ); } System.out.println(); }
5.Arrays API方法
方法
作用
Arrays.toString(数组)
把一维数组 转成字符串打印
Arrays.sort(数组)
数组升序排序
Arrays.binarySearch(数组, key)
二分查找元素下标(必须先排序 )
Arrays.copyOf(原数组, 新长度)
拷贝数组,可扩容 / 缩容
Arrays.copyOfRange(arr, 起始, 结束)
范围拷贝,左闭右开
Arrays.fill(数组, 值)
给数组全部填充同一个值
Arrays.equals(数组1, 数组2)
判断两个数组内容是否完全一样
Arrays.deepToString(二维数组)
打印二维数组
Arrays.deepEquals(二维数组1, 二维数组2)
判断二维数组内容是否相等
十一、类与对象 1. 什么是类? 类:是模板、图纸、抽象概念 比如:人类、学生类、手机类
2. 什么是对象? 对象:是模板造出来的具体实例、真实个体 根据「人类」这个模板,造出:张三、李四 就是对象。
3. 关系 类 → 模板****对象 → 模板 new 出来的真实个体 一句话:类是抽象,对象是具体
1.定义类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class Student { String name; int age; String gender; public void study () { System.out.println(name + " 在认真学习" ); } public void eat (name) { System.out.println(name + " 在吃饭" ); } public int count () { return 10 ; } }
2.创建、使用对象 1 2 3 4 5 6 7 8 9 10 11 Student s = new Student ();s.name = "小明" ; s.age = 18 ; s.gender = "男" ; s.study(); s.eat();
3.内存细节 1 2 3 4 5 new Student() 成员变量存在堆内存里 引用变量 s 存在栈内存,存的是堆内存地址值 多个对象互不干扰,各自有自己的成员变量
4.成员变量和局部变量
区别
成员变量
局部变量
定义位置
类中、方法外
方法里、代码块里
作用范围
整个类都能用
只能在当前方法 / 代码块
默认初始值
有默认值(int0,boolean false 等)
没有默认值,必须手动赋值
内存位置
堆内存
栈内存
生命周期
对象消失才消失
方法执行完立刻消失
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class chenyuan { String name; 代表成员变量 public void show () { int a; 代表局部变量 System.out.println(name); 输出为 null System.out.println(a); 此时会报错 因为局部变量一定要赋值!!!!!!!!!!! } public void show (int a) { 参数也属于局部变量 如括号里的 int a } }
5.构造方法 什么是构造方法?? 创建对象时,自动调用的方法 无参构造方法 1 2 3 4 5 6 class love { public love () { } }
有参构造器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class love { private String name; private int age; public love (String name,int age) { this .name = name; this .age = age; } public love (String name) { this .name = name; } }
6. this关键字 Java虚拟机给每个对象分配this,代表当前对象。 this 属性 如果参数和类的属性相同,就要使用this关键字(一般与构造器相对) 用法1: 局部变量和成员变量同名时,用 this. 指代类的成员变量 1 2 3 4 5 6 7 8 9 10 class Person { String name; public void setName (String name) { this .name = name; } }
用法2: this. 方法 () 调用本类方法 1 2 3 4 5 6 7 8 9 10 class love { public void a () { System.out.println("a方法" ); } public void b () { this .a(); } }
用法3: this () 调用本类构造方法 1 2 3 4 5 6 7 8 9 10 11 class Person { public Person () { this ("李四" , 20 ); } public Person (String name, int age) { System.out.println("有参构造" ); } }
7.方法重载 同一个类中,方法名相同,但参数列表不同的多个方法,就是方法重载。
方法名必须完全一样
参数列表必须不同 (满足任意一种即可)
参数个数 不同
参数类型 不同
参数顺序 不同(类型不同时)
返回值、访问修饰符(public/private)不影响重载
只看方法名 + 参数列表!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Calculator { public int add (int a, int b) { return a + b; } public int add (int a, int b, int c) { return a + b + c; } public double add (double a, double b) { return a + b; } public double add (int a, double b) { return a + b; } }
8.可变参数
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 public class Demo { public static int getSum (int ... nums) { int sum = 0 ; for (int n : nums) { sum += n; } return sum; } public static void main (String[] args) { System.out.println(getSum()); System.out.println(getSum(1 )); System.out.println(getSum(1 ,2 ,3 )); System.out.println(getSum(10 ,20 ,30 ,40 )); int [] arr = {5 ,6 ,7 }; System.out.println(getSum(arr)); } }
9.访问修饰符
修饰符
本类内部
同包无关类
不同包子类
不同包无关类
private 私有
✅ 可以
❌ 不行
❌ 不行
❌ 不行
default 默认 (包访问)
✅ 可以
✅ 可以
❌ 不行
❌ 不行
protected 受保护
✅ 可以
✅ 可以
✅ 可以
❌ 不行
public 公共
✅ 可以
✅ 可以
✅ 可以
✅ 可以
1 注:如果用来修饰类,只允许public和默认修饰符!!!
十二、包 包就是文件夹 用来分类管理类、防止类名冲突 。
1.作用: 区分同名类 :不同包里可以有一模一样的类名
分类管理 :按功能分层(实体类、工具类、测试类)
控制访问权限 :同包有权限可直接访问
2.导入包: 1 2 3 4 5 import java.util.Scanner;import java.util.*;
3.命名规范 全部小写
公司域名倒着写
例:com.baidu.项目名.模块名
十三、面向对象三大特性 面向对象三大特征:封装、继承、多态!!! 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 25 26 27 28 public class Person { private String name; private int age; public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { if (age > 0 && age < 150 ) { this .age = age; } else { System.out.println("年龄不合法" ); } } }
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 class Animal { public void eat () { System.out.println("动物会吃东西" ); } } class Dog extends Animal { public void bark () { System.out.println("狗会汪汪叫" ); } } public class Test { public static void main (String[] args) { Dog d = new Dog (); d.eat(); d.bark(); } }
super关键字 1. 访问父类的成员变量 格式:super.变量名区分子类和父类重名属性
2. 访问父类的成员方法 格式:super.方法名()子类重写 方法后,想调用父类原方法
3. 调用父类的构造方法 格式:super(参数)必须放在子类构造方法第一行
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 class Father { String name = "父亲" ; public void show () { System.out.println("父类方法" ); } } class Son extends Father { String name = "儿子" ; public void test () { System.out.println(name); System.out.println(super .name); show(); super .show(); } } class Father { public Father (String name) { System.out.println("父类有参构造" ); } } class Son extends Father { public Son () { super ("张三" ); System.out.println("子类构造" ); } }
方法重写 又叫方法覆盖,子类根据父类继承的方法进行重新编写 重写时可以用super.方法来保留父类的方法 父类的构造方法无法重写!!!!!! 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 class Animal { public void eat () { System.out.println("动物吃东西" ); } } class Dog extends Animal { @Override public void eat () { System.out.println("狗吃骨头" ); } } public class Test { public static void main (String[] args) { Dog dog = new Dog (); dog.eat(); } }
3.多态 父类引用指向子类对象 ,调用方法时执行子类重写后的逻辑 。多态是方法的多态,属性没有多态,要看编译类型! 1.多态实现的三个前提(缺一不可)
必须有继承
必须有方法重写
父类引用指向子类对象
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 class Animal { public void eat () { System.out.println("动物吃东西" ); } } class Dog extends Animal { @Override public void eat () { System.out.println("狗吃骨头" ); } } class Cat extends Animal { @Override public void eat () { System.out.println("猫吃鱼" ); } } public class Test { public static void main (String[] args) { Animal a1 = new Dog (); Animal a2 = new Cat (); a1.eat(); a2.eat(); } }
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 class Animal { public void eat () { System.out.println("动物吃东西" ); } } class Dog extends Animal { @Override public void eat () { System.out.println("狗吃骨头" ); } } class Cat extends Animal { @Override public void eat () { System.out.println("猫吃鱼" ); } } public class Test { public static void main (String[] args) { Animal a1 = new Dog (); Animal a2 = new Cat (); Dog d = (Dog) a2; a1.eat(); a2.eat(); } }
4.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 47 48 49 50 51 52 53 54 55 public class Father { public int i = 10 ; public int getI () { return i; } public int sum () { return getI() + 10 ; } public int sun1 () { return i; } } public class Son extends Father { public int i = 20 ; public int getI () { return i; } public int sun1 () { return i + 10 ; } } public class Test { public static void main (String[] args) { Father f = new Son (); System.out.println(f.sum()); } }
5.Object类 java.lang.Object 是 Java 中所有类的根父类 任何类,默认直接 / 间接继承 Object 所有对象、数组,都可以用 Object 引用接收 自带方法:
方法名
修饰符
作用功能
重点考点
toString()
public
对象转为字符串输出
默认:类名 @哈希值,必须重写
equals(Object obj)
public
判断对象是否相等
默认和 == 一样比地址,比内容要重写
hashCode()
public
返回对象哈希码 int 值
重写 equals必须同步重写 hashCode
getClass()
public final
获取对象运行时真实类型
不能重写 ,反射基础,区分编译 / 运行类型
clone()
protected
克隆对象(浅拷贝)
需实现Cloneable接口,默认浅克隆
finalize()
protected
垃圾回收前回调
JDK9 + 废弃,现在不用
wait()
public final
线程等待,释放锁
必须在synchronized中调用
wait(long timeout)
public final
限时等待
线程通信
wait(long, int)
public final
精确纳秒级限时等待
极少用
notify()
public final
随机唤醒一个等待线程
同步锁内使用
notifyAll()
public final
唤醒所有等待线程
同步锁内使用
注:只要创建的对象都可以直接使用这些方法!!!!! 十四、面向对象高级内容 1.静态变量 用 static 修饰的成员变量,整个类只有一份 ,所有对象共享这一个值。 特点: 属于类 ,不属于某个对象
内存中只存一份 ,所有对象共用
可以通过 类名.变量名 直接访问
常用于:常量、计数器、共享配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Student { static String school = "第一中学" ; String name; } public class Test { public static void main (String[] args) { System.out.println(Student.school); Student s1 = new Student (); Student s2 = new Student (); Student.school = "第二中学" ; System.out.println(s1.school); System.out.println(s2.school); } }
2.静态方法 用 static 修饰的方法,属于类,不属于对象 。 特点: 可以通过 类名.方法名 () 直接调用
不能直接访问普通成员变量 / 普通方法 (因为没有对象)
只能访问静态变量 和静态方法
常用于:工具方法(Math、Arrays)、主方法 main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Calc { public static int add (int a, int b) { return a + b; } } public class Test { public static void main (String[] args) { int sum = Calc.add(3 ,5 ); System.out.println(sum); } }
3. main方法 1 2 3 4 main方法是java虚拟机调用的,所以必须是public访问权限。 main方法调用不会创建对象,所以方法必须是static(静态方法) 该方法接收String类型的数组参数,该数组保存执行java命令时传递给运行时的类的参数。 所以格式:public static void main(String[] args){}
4.代码块 代码块又称初始化块,属于类中的一员,类似于方法,将逻辑语句封装在方法体里面,通过{}包裹起来 但和方法不同,没有方法名、返回、参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时, 或创建类时隐式调用!!! 普通代码块 1 2 3 4 5 6 7 8 9 10 public class Demo { public static void main (String[] args) { { int a = 10 ; System.out.println(a); } } }
构造代码块 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Person { { System.out.println("构造代码块执行" ); } public Person () { System.out.println("构造方法执行" ); } public Person (int age) { 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 class Person { static { System.out.println("静态代码块执行" ); } { System.out.println("构造代码块执行" ); } public Person () { System.out.println("构造方法执行" ); } public Person (int age) { System.out.println("构造方法执行" ); } }
5. final关键字 可以修饰类、属性、方法和局部变量 使得不可变 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 void test () { final int a = 10 ; }
6.抽象类 抽象:指从具体事物抽出、概括它们共同的方面、本质特征 抽象类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 abstract class 类名 { }
抽象方法 1 2 public abstract void eat () ;
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 abstract class Animal { public abstract void eat () ; public void sleep () { System.out.println("动物睡觉" ); } } class Dog extends Animal { @Override public void eat () { System.out.println("狗吃骨头" ); } } public class Test { public static void main (String[] args) { Animal a = new Dog (); a.eat(); a.sleep(); } }
7.接口 接口是多个类的公开规范,接口是引用数据类型,最重要的内容就是其中的抽象方法 接口时比抽象类更抽象的抽象类,规范了子类的约束 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface 接口名 { } public class 类名 implements 接口名{}
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 interface Animal { String TYPE = "生物" ; void eat () ; default void sleep () { System.out.println("动物睡觉" ); } static void show () { System.out.println("接口静态方法" ); } } class Dog implements Animal { @Override public void eat () { System.out.println("狗吃骨头" ); } } public class Test { public static void main (String[] args) { Animal a = new Dog (); a.eat(); a.sleep(); Animal.show(); } }
8.内部类 类的五大成员[属性、方法、构造器、代码块、内部类],内部类的特点就是可以直接访问私有属性,并且可以体现 类与类之间的包含关系 注:内部类是学习的难点,同时也是重点,后面看底层代码时,有大量的内部类!!! 1.成员内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Outer { class Inner { public void show () { System.out.println("成员内部类" ); } } } public static void main (String[] args) { Outer.Inner in = new Outer ().new Inner (); in.show(); }
2.静态内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Outer { static class Inner { public void show () { System.out.println("静态内部类" ); } } } public static void main (String[] args) { Outer.Inner in = new Outer .Inner(); in.show(); }
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 class Outer { public void test () { class Inner { public void show () { System.out.println("局部内部类" ); } } new Inner ().show(); } }
4.匿名内部类 没有类名 ,直接 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 30 31 32 interface Animal { void eat () ; } public class Test { public static void main (String[] args) { Animal a = new Animal () { @Override public void eat () { System.out.println("小狗吃骨头" ); } }; a.eat(); Aniaml b = () -> System.println.out("小喵吃小鱼" ); b.eat(); } }
十五、枚举类 枚举类 是用来定义固定、有限、不变的常量集合 的特殊类(比如:性别、季节、订单状态、颜色、星期)。简单说:当一个变量只有几种固定可选值时,用枚举类最规范、最安全。 特点 实例有限且固定 ,不能随意创建对象
枚举常量默认 public static final
自带常用方法:values(), valueOf(), name(), ordinal()
比常量(public static final)更易读、更安全、更易维护
格式 1 2 3 4 public enum Season { SPRING, SUMMER, AUTUMN, WINTER; }
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 public enum OrderEnum { PENDING(1 , "待支付" ), PAID(2 , "已支付" ), SHIPPED(3 , "已发货" ), COMPLETED(4 , "已完成" ), CANCELLED(5 , "已取消" ); private final int code; private final String desc; OrderEnum(int code, String desc) { this .code = code; this .desc = desc; } public int getCode () { return code; } public String getDesc () { return desc; } }
自带方法 1 2 3 4 5 6 7 for (OrderStatus status : OrderStatus.values()) { System.out.println(status.name() + ":" + status.getDesc()); } OrderStatus status = OrderStatus.valueOf("PAID" );
十六、注解 注解就是给类、方法、变量、参数 打标签、加标记 。本身不写业务逻辑 ,只做元数据标记 ,给编译器、框架(Spring、MyBatis)看。 语法 1 2 @Override public void test () {}
相关注解
注解
作用
适用场景
@Override
校验方法重写 ,签名不对编译报错
重写父类 / 接口方法
@Deprecated
标记类、方法、字段已过时
旧版本兼容、废弃接口
@SuppressWarnings
压制编译器警告
去掉黄色波浪线警告
元注解(用于自定义注解) 定义注解的注解,4 个必记
元注解
作用
记忆
@Target
限定注解能写在哪
标记位置
@Retention
限定注解保留周期
标记存活时间
@Documented
生成 JavaDoc 文档时带上注解
文档可见
@Inherited
子类自动继承 父类的注解
可被继承
@Target 可选取值(全列表)
取值
可标注位置
TYPE
类、接口、枚举、注解
FIELD
成员变量、常量
METHOD
普通方法
PARAMETER
方法参数
CONSTRUCTOR
构造方法
LOCAL_VARIABLE
局部变量
ANNOTATION_TYPE
注解类型上
PACKAGE
包上
TYPE_PARAMETER
泛型参数
TYPE_USE
任意类型使用处
@Retention 三档
级别
存活阶段
场景
SOURCE
仅源码,编译后丢弃
@Override
CLASS
保留到 class 文件,运行时丢失
默认级别
RUNTIME
运行时可反射读取
Spring、自定义注解必用
自定义注解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String values () ; int num () default 100 ; } public class Test { @MyAnnotation(values = "你好",num = 12) public void hello () { System.out.println("hello" ); } }
十七、包装类 Java 为8 种基本数据类型 ,分别提供了一个对应的引用类型 ,就是包装类 。
基本类型
包装类(引用类型)
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
char
Character
boolean
Boolean
1.装箱 1 2 int a = 10 ;Integer num = Integer.valueOf(a);
2.拆箱
3.自动装箱/拆箱(JDK1.5) 1 2 3 4 5 Integer x = 100 ; int y = x;
4.通用方法(所有的包含这些) Integer专属方法
常量
含义
Integer.MAX_VALUE
int 最大值 2147483647
Integer.MIN_VALUE
int 最小值 -2147483648
Integer.SIZE
占位数 32 位
Integer.BYTES
占用字节 4 字节
parseInt(String s)
字符串转 int
parseInt(String s,int radix)
指定进制字符串转十进制 int
valueOf(int i)
int 转 Integer(走缓存)
valueOf(String s)
字符串转 Integer
toBinaryString(int i)
转二进制字符串
toOctalString(int i)
转八进制字符串
toHexString(int i)
转十六进制字符串
compare(int a,int b)
比较两个 int 大小
max(int a,int b)
取最大值
min(int a,int b)
取最小值
sum(int a,int b)
求和
1 2 3 4 5 6 7 8 9 10 11 public class integer { public static void main (String[] args) { String s = "13" ; int parseInt = Integer.parseInt(s); Integer valueOf = Integer.valueOf(s); int compare = Integer.compare(20 , 19 ); System.out.println(compare); System.out.println(Integer.sum(12 , 29 )); } }
Character
常量
作用
Character.MAX_VALUE
char 最大值
Character.MIN_VALUE
char 最小值
isDigit(char ch)
判断是不是数字
isLetter(char ch)
判断是不是字母
isLetterOrDigit(ch)
判断字母或数字
isUpperCase(ch)
是否大写字母
isLowerCase(ch)
是否小写字母
toUpperCase(ch)
转大写
toLowerCase(ch)
转小写
isWhitespace(ch)
是否空格 / 空白字符
Boolean
方法
作用
parseBoolean(String s)
字符串转 boolean
valueOf(boolean b)
boolean 转 Boolean
valueOf(String s)
字符串转 Boolean
booleanValue()
Boolean 拆箱为 boolean
equals(Object obj)
比较是否同为 true/false
Double
方法
作用
parseBoolean(String s)
字符串转 boolean
valueOf(boolean b)
boolean 转 Boolean
valueOf(String s)
字符串转 Boolean
booleanValue()
Boolean 拆箱为 boolean
equals(Object obj)
比较是否同为 true/false
十八、字符串类 1. String String 是不可变字符序列 底层 JDK8 及以前:private final char[] value JDK9+:改成 private final byte[] value 节省空间 被 final 修饰 :不能被继承一旦创建,内容不能修改 ,每次拼接都是新建新字符串 1.创建方式 1 2 3 4 5 String s1 = "abc" ;String s2 = new String ("abc" );
2.相关方法
方法分类
方法签名
作用说明
获取长度
int length()
返回字符串字符个数
获取指定字符
char charAt(int index)
根据下标获取单个字符
查找索引
int indexOf(String str)
从头找子串,返回首次索引,找不到返回 -1
反向查找
int lastIndexOf(String str)
从后往前找子串,返回最后一次索引
截取子串
String substring(int beginIndex)
从起始下标截取到末尾
截取子串
String substring(int begin, int end)
左闭右开 [begin,end) 区间截取
内容比较
boolean equals(Object obj)
比较字符串内容,区分大小写
忽略大小写比较
boolean equalsIgnoreCase(String another)
忽略大小写比较内容
开头判断
boolean startsWith(String prefix)
判断是否以指定前缀开头
结尾判断
boolean endsWith(String suffix)
判断是否以指定后缀结尾
包含判断
boolean contains(CharSequence s)
判断是否包含某个子串
判空
boolean isEmpty()
判断是否为空字符串 ""
转大写
String toUpperCase()
所有字母转大写
转小写
String toLowerCase()
所有字母转小写
转字符数组
char[] toCharArray()
字符串转为 char 数组
任意类型转字符串
static String valueOf(任意类型)
基本类型 / 对象 转字符串
去除首尾空格
String trim()
只去掉首尾 空格,中间不动
替换字符
String replace(char old, char new)
替换所有匹配的字符
替换子串
String replace(CharSequence old, CharSequence new)
替换所有匹配的子串
分割字符串
String[] split(String regex)
按正则规则分割成字符串数组
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 public class StringDemo { public static void main (String[] args) { String s = "HelloJava" ; String str = " Java Study " ; System.out.println(s.length()); System.out.println(s.charAt(0 )); System.out.println(s.indexOf("Java" )); System.out.println(s.lastIndexOf("a" )); System.out.println(s.substring(5 )); System.out.println(s.substring(0 , 5 )); System.out.println("Hello" .equals("hello" )); System.out.println("Hello" .equalsIgnoreCase("hello" )); System.out.println(s.startsWith("He" )); System.out.println(s.endsWith("va" )); System.out.println(s.contains("ava" )); System.out.println("" .isEmpty()); System.out.println(s.isEmpty()); System.out.println(s.toUpperCase()); System.out.println(s.toLowerCase()); char [] arr = s.toCharArray(); for (char c : arr) { System.out.print(c + " " ); } System.out.println(); String numStr = String.valueOf(12345 ); System.out.println(numStr); System.out.println(str.trim()); System.out.println(s.replace('a' , 'A' )); System.out.println(s.replace("Java" , "Java编程" )); String line = "a,b,c,d" ; String[] splitArr = line.split("," ); for (String item : splitArr) { System.out.print(item + " " ); } } }
2. StringBuffer String保存的是字符串的常量,里面的值不可以改变,每次String类的更新实际上是更改地址,效率较低 而StringBuffer保存的是字符串变量,里面的值可以更改,不会变动地址!!!放在 char[] value里面 1.StringBuffer的直接父类是 AbatractStringBuilder; 2.StringBuffer实现了 Serializable,则StringBuffer的对象可以串行化(序列化) 3.在父类中 AbatractStringBuilder 有属性 char[] value,不是final类型!!!! 4.StringBuffer是一个final类,不可以被继承 1.创建
构造方法
作用
StringBuffer()
空构造,默认容量 16
StringBuffer(int capacity)
指定初始容量
StringBuffer(String str)
用字符串初始化,容量 = 字符串长度 + 16
2.相关方法
方法
作用
append(任意类型)
末尾追加 (最常用)
delete(int start,int end)
删除 [start,end) 区间字符
deleteCharAt(int index)
删除指定下标单个字符
insert(int offset, 数据)
在指定位置插入 内容
replace(int start,int end,String str)
替换区间内容
reverse()
字符串反转
length()
返回实际字符长度
capacity()
返回底层数组容量
substring(int start)
截取子串,返回 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 33 34 public class StringBufferDemo { public static void main (String[] args) { StringBuffer sb = new StringBuffer ("abc" ); sb.append("123" ); System.out.println("追加后:" + sb); sb.insert(3 , "XYZ" ); System.out.println("插入后:" + sb); sb.replace(0 , 3 , "AAA" ); System.out.println("替换后:" + sb); sb.delete(3 , 6 ); System.out.println("删除区间:" + sb); sb.deleteCharAt(0 ); System.out.println("删除下标0:" + sb); sb.reverse(); System.out.println("反转后:" + sb); System.out.println("实际长度:" + sb.length()); System.out.println("底层容量:" + sb.capacity()); } }
3. StringBuilder 一个可变的字符序列。此类提供和StringBuffer兼容的API,但不保证同步(存在线程安全问题)。 该类被设置用在StringBuffer的简易替换,用在字符串缓冲区被单个线程使用的时候。如果可以,建议先采取该类 因为他比StringBuffer快。他为单线程,一个线程在工作,其他的会暂停!!! 1.Stringilder的直接父类是 AbatractStringBuilder; 2.StringBuilder实现了 Serializable,则StringBuffer的对象可以串行化(序列化) 3.StringBuilder是一个final类,不可以被继承 4.在父类中 AbatractStringBuilder 有属性 char[] value 5.主要操作时append和insert,可以重载这些方法,以接受各种数据类型; 1.创建
构造方法
作用
默认容量
StringBuilder()
空构造
初始容量 16
StringBuilder(int capacity)
指定初始容量
自定义
StringBuilder(String str)
用字符串初始化
字符串长度 + 16
2.相关方法
方法
作用
append(任意类型)
末尾追加(最常用)
insert(int offset, 数据)
指定下标插入内容
delete(int start, int end)
删除 [左闭右开) 区间
deleteCharAt(int index)
删除指定下标单个字符
replace(int start,int end,String str)
替换区间内容
reverse()
字符串反转
length()
实际字符长度
capacity()
底层数组容量
substring(int start)
截取,返回 String
substring(int start,int end)
区间截取
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 public class StringBuilderTest { public static void main (String[] args) { StringBuilder sb = new StringBuilder ("abc" ); sb.append(123 ); System.out.println("追加:" + sb); sb.insert(3 , "XYZ" ); System.out.println("插入:" + sb); sb.replace(0 , 3 , "AAA" ); System.out.println("替换:" + sb); sb.delete(3 , 6 ); System.out.println("删区间:" + sb); sb.deleteCharAt(0 ); System.out.println("删下标0:" + sb); sb.reverse(); System.out.println("反转:" + sb); System.out.println("实际长度:" + sb.length()); System.out.println("底层容量:" + sb.capacity()); String sub = sb.substring(1 ); System.out.println("截取子串:" + sub); } }
4.三者区别 String:不可变字符序列,效率低,但复用率高 StringBuffer: 可变字符序列,效率较高,线程安全 StringBuilder: 可变字符序列,效率最高,线程不安全 十九、Math类 Math类包含执行基本数学运算的方法,如初等函数等。 所有方法
常量
含义
Math.PI
圆周率 3.14159265358979
Math.E
自然常数 2.71828182845905
方法
作用
Math.abs(数值)
求绝对值
Math.max(a,b)
取两个数最大值
Math.min(a,b)
取两个数最小值
Math.ceil(double)
向上取整 往大数靠
Math.floor(double)
向下取整 往小数靠
Math.round(double)
四舍五入 长整型
Math.pow(a,b)
求 a 的 b 次幂
Math.sqrt(double)
开平方根
Math.cbrt(double)
开立方根
Math.random()
随机数 [0.0, 1.0)
Math.sin/cos/tan(弧度)
三角函数
Math.log(double)
自然对数
Math.log10(double)
以 10 为底对数
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 public class MathDemo { public static void main (String[] args) { System.out.println("圆周率:" + Math.PI); System.out.println("自然常数:" + Math.E); System.out.println("绝对值:" + Math.abs(-9 )); System.out.println("最大值:" + Math.max(10 , 20 )); System.out.println("最小值:" + Math.min(10 , 20 )); System.out.println("向上取整 3.2:" + Math.ceil(3.2 )); System.out.println("向下取整 3.8:" + Math.floor(3.8 )); System.out.println("四舍五入 3.5:" + Math.round(3.5 )); System.out.println("2的3次方:" + Math.pow(2 ,3 )); System.out.println("16平方根:" + Math.sqrt(16 )); System.out.println("8立方根:" + Math.cbrt(8 )); System.out.println("随机数[0,1):" + Math.random()); } }
二十、System类 提供系统级工具方法与静态字段 ,用于标准 I/O、数组拷贝、时间获取、系统属性 / 环境变量读取、JVM 控制等 相关方法
常量
类型
作用
System.in
InputStream
标准键盘输入流
System.out
PrintStream
标准控制台正常输出流
System.err
PrintStream
标准控制台错误输出流 (红色)
方法签名
功能说明
常用场景
arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
高效数组拷贝,native 底层
数组批量复制、集合底层扩容
currentTimeMillis()
获取当前时间毫秒时间戳(1970 至今)
生成时间戳、计算业务耗时、日期转换
nanoTime()
获取高精度纳秒相对时间
代码性能测速、精确计时
exit(int status)
终止当前 JVM 进程
程序主动退出、异常终止
gc()
建议 JVM 执行垃圾回收
手动提醒 GC 释放内存
getProperty(String key)
获取 JVM / 系统属性
读取系统版本、项目路径、编码
getProperty(String key, String defaultValue)
获取系统属性,取不到给默认值
防止属性为空报错
getenv(String name)
获取操作系统环境变量
读取 PATH、自定义环境变量
二十一、BigInteger和BigDecimal类 BigInteger :超大整数 ,超出 long 范围也能存,无上限BigDecimal :超大小数 ,解决 float/double 浮点精度丢失问题创建 1 2 3 4 5 6 7 new BigInteger ("数字字符串" )BigInteger.valueOf(普通整数) new BigDecimal ("小数字符串" ) BigDecimal.valueOf(普通小数)
相关方法
方法
作用
add()
加法
subtract()
减法
multiply()
乘法
divide()
除法
remainder()
取余
abs()
绝对值
negate()
取相反数
仅BigInteger
方法
作用
pow(int n)
幂运算
gcd()
最大公约数
isPrime()
判断是否质数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 BigInteger a = BigInteger.valueOf(100 );BigInteger b = new BigInteger ("999999999999999999999" );BigInteger res = a.add(b); res = a.subtract(b); res = a.multiply(b); BigDecimal d1 = new BigDecimal ("0.1" );BigDecimal d2 = new BigDecimal ("0.2" );BigDecimal sum = d1.add(d2);BigDecimal res = sum.setScale(2 , RoundingMode.HALF_UP);
二十二、日期类 1.第一代日期类(date)
方法签名
功能说明
Date()
创建当前系统日期时间
Date(long)
根据毫秒值创建日期
getTime()
返回时间毫秒值
setTime()
设置时间毫秒值
方法签名
功能说明
SimpleDateFormat(String)
构造方法,传入日期格式模板
format(Date)
日期对象 → 格式化字符串
parse(String)
日期字符串 → 解析为 Date 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;public class ParseDemo { public static void main (String[] args) throws ParseException { String str = "2025-12-01 18:30:00" ; SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" ); Date date = sdf.parse(str); System.out.println(date); } }
2.第二代日期类(Calendar) Calendar本身是一个抽象类,它为特定瞬间与一组YEAR、MONTH等日历字段之间的转换提供了方法。 Calender是一个抽象类,并且构造器是private,无法直接new一个;可以通过 getInstance() 获取!!!!
方法签名
功能说明
getInstance()
获取日历实例对象
get(field)
获取年、月、日、时、分、秒
set(field,value)
设置指定时间字段
add(field,amount)
对时间进行加减
getTime()
Calendar 转为 Date
setTime(Date)
Date 转为 Calendar
3.第三代日期类 1.创建日期
写法
作用
LocalDate.now()
获取当前 年月日
LocalDateTime.now()
获取当前 年月日时分秒
LocalTime.now()
获取当前 时分秒
LocalDate.of (年,月,日)
手动指定固定年月日
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class localDate { public static void main (String[] args) { LocalDateTime now = LocalDateTime.now(); System.out.println(now); LocalDate now1 = LocalDate.now(); System.out.println(now1); LocalTime now2 = LocalTime.now(); System.out.println(now2); LocalDate localDate = LocalDate.of(2025 , 12 , 6 ); System.out.println(localDate); } }
2.修改时间(with 系列)
写法
作用
withYear()
修改年份
withMonth()
修改月份
withDayOfMonth()
修改日期
1 2 3 4 5 LocalDate localDate = LocalDate.of(2025 , 12 , 6 );System.out.println(localDate); LocalDate localDate1 = localDate.withYear(2026 ); System.out.println(localDate1);
3.增加、减少时间(plus /minus)
分类
方法
作用
增加
plusYears()、plusMonths()、plusDays()
加年、加月、加天
减少
minusYears()、minusMonths()、minusDays()
减年、减月、减天
4.时间比较
方法
作用
isAfter()
判断当前时间是否在之后 ,返回 boolean
isBefore()
判断当前时间是否在之前 ,返回 boolean
5.格式化时间
步骤
写法
作用
定义格式
DateTimeFormatter.ofPattern (“格式”)
自定义日期格式模板
格式化
时间对象.format (格式化器)
日期时间转字符串
1 2 3 4 5 6 7 8 9 LocalDateTime now = LocalDateTime.now(); System.out.println(now); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss" ); String format = now.format(dateTimeFormatter);System.out.println(format);
6.时间戳
写法
说明
Instant.now()
获取当前时间戳
with()、plus()、minus()
可修改、加减只支持:秒、毫秒、纳秒
7.计算时间差
用法
说明
Duration.between (时间 1, 时间 2)
计算两个 LocalDateTime 时间间隔
toDays()、toSeconds()、toMinutes()
获取相差天数、秒数、分钟数可精确到:日、时、分、秒、毫秒、纳秒
8. 时区 ZonedDateTime
写法
作用
ZoneId.getAvailableZoneIds()
获取系统所有时区名称
ZonedDateTime.now(Clock.systemUTC())
获取世界标准 UTC 时间
ZonedDateTime.now()
获取电脑默认时区时间
ZonedDateTime.now (ZoneId.of (“时区名”))
指定任意时区创建时间
二十三、集合 前面我们使用了数组,但数组也有不足的地方,缺点: 1.长度必须开始时指定,一旦指定就无法修改; 2.保存必须为同一类型的元素; 3.使用数组增加元素比较繁琐 集合的好处: 1.可以动态保存任意多个对象,使用比较方便;2.提供了一系列方法如:add、remove等;3.添加、删除元素更简洁 集合的形式: Collection 接口有两个重要的子接口 List Set,他们实现的子类都是单列集合 Map 接口的实现子类,是双列集合,存放的 k-v(键值 和python字典类似) 1. Collection 常用方法:
方法名
作用
返回值
add(E e)
添加单个元素
boolean
addAll(Collection<?> c)
批量添加另一个集合所有元素
boolean
clear()
清空集合所有元素
void
contains(Object o)
判断是否包含指定元素
boolean
containsAll(Collection<?> c)
判断是否包含另一个集合所有元素
boolean
isEmpty()
判断集合是否为空
boolean
remove(Object o)
删除指定单个元素
boolean
removeAll(Collection<?> c)
删除和另一个集合的交集元素
boolean
retainAll(Collection<?> c)
保留和另一个集合的交集,其余删除
boolean
size()
获取集合元素个数
int
toArray()
集合转 Object 数组
Object[]
toArray(T[] a)
集合转指定类型数组
T[]
iterator()
获取迭代器,用于遍历
Iterator
静态工具类
方法
作用
sort(List<T> list)
对 List 自然排序
sort(List<T>, Comparator)
自定义规则排序
reverse(List<?> list)
反转集合元素顺序
shuffle(List<?> list)
随机打乱顺序(洗牌)
max(Collection)
取集合最大值
min(Collection)
取集合最小值
binarySearch(List, key)
二分查找(必须先排序 )
addAll(集合, 元素1,元素2...)
批量添加元素
emptyList() / emptySet() / emptyMap()
返回空不可变集合
synchronizedList/Set/Map()
转成线程安全 集合
unmodifiableList/Set/Map()
转成不可变只读 集合
2. List List 是 Java Collection 旗下的子接口 ,属于单列集合 。1. ArrayList实现类 特点: 有序、可重复、有索引
查询快、随机访问极快
中间 / 头部增删慢 (要移位复制)
线程不安全 ,多线程不用
允许存 null 相关方法
方法名
作用
返回值
add(E e)
末尾添加单个元素
boolean
get(int index)
根据索引获取元素
E
set(int index, E e)
根据索引修改元素,返回旧值
E
remove(int index)
根据索引删除元素,返回被删元素
E
size()
获取集合元素个数
int
isEmpty()
判断集合是否为空
boolean
clear()
清空集合所有元素
void
contains(Object o)
判断是否包含指定元素
boolean
add(int index, E e)
在指定索引位置插入元素
void
indexOf(Object o)
返回元素第一次出现的索引
int
addAll(Collection c)
批量添加另一个集合所有元素
boolean
remove(Object o)
根据元素对象删除
boolean
forEach()
Lambda 遍历集合
void
removeIf()
按条件批量删除元素
boolean
lastIndexOf(Object o)
返回元素最后一次出现的索引
int
subList(int from, int to)
截取子集合(左闭右开)
List
toArray()
集合转为 Object 数组
Object[]
toArray(T[] a)
集合转为指定类型数组
T[]
iterator()
获取迭代器遍历
Iterator
containsAll(Collection c)
是否包含另一个集合所有元素
boolean
removeAll(Collection c)
删除两集合交集元素
boolean
retainAll(Collection c)
保留两集合交集元素
boolean
listIterator()
获取列表迭代器
ListIterator
ensureCapacity(int num)
手动预扩容,减少自动扩容
void
trimToSize()
收缩底层数组容量到实际元素个数
void
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 public class Conllections { public static void main (String[] args) { ArrayList<String> list = new ArrayList <>(); list.add("Java" ); list.add("Python" ); list.add("C++" ); list.add(1 , "Go" ); System.out.println("添加后:" + list); System.out.println("元素个数:" + list.size()); System.out.println("索引1元素:" + list.get(1 )); list.set(2 , "JavaScript" ); System.out.println("修改后:" + list); System.out.println("是否包含Java:" + list.contains("Java" )); list.remove(0 ); list.remove("C++" ); System.out.println("删除后:" + list); System.out.println("是否为空:" + list.isEmpty()); System.out.print("遍历结果:" ); for (String s : list) { System.out.print(s + " " ); } list.clear(); System.out.println("\n清空后是否为空:" + list.isEmpty()); } }
2. LinkedList实现类 特点: 底层是双向链表
增删快、查询慢 (ArrayList 相反)
实现了 List、Deque 接口,可当列表、队列、栈 用
适合频繁插入、删除 场景
独有方法(其他方法和ArrayList一致)
独有方法
功能
addFirst(E e)
头部添加元素
addLast(E e)
尾部添加元素
getFirst()
获取第一个元素
getLast()
获取最后一个元素
removeFirst()
删除并返回第一个元素
removeLast()
删除并返回最后一个元素
peekFirst()
获取第一个元素,不删除
peekLast()
获取最后一个元素,不删除
pollFirst()
取出并删除第一个元素
pollLast()
取出并删除最后一个元素
push(E e)
入栈(头部添加)
pop()
出栈(删除头部)
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 public class LinkedListDemo { public static void main (String[] args) { LinkedList<String> link = new LinkedList <>(); link.add("张三" ); link.add("李四" ); System.out.println("普通添加:" + link); link.addFirst("王五" ); link.addLast("赵六" ); System.out.println("首尾添加后:" + link); System.out.println("第一个元素:" + link.getFirst()); System.out.println("最后一个元素:" + link.getLast()); System.out.println("索引2元素:" + link.get(2 )); link.removeFirst(); link.removeLast(); System.out.println("删除首尾后:" + link); System.out.println("是否包含李四:" + link.contains("李四" )); System.out.println("元素个数:" + link.size()); System.out.println("是否为空:" + link.isEmpty()); System.out.print("遍历所有元素:" ); for (String name : link) { System.out.print(name + " " ); } link.clear(); System.out.println("\n清空后是否为空:" + link.isEmpty()); } }
3. Vector实现类 特点: 底层也是动态数组 ,和 ArrayList 底层结构一样
JDK1.0 古老类 ,最早的动态数组
默认线程安全 (所有方法加了 synchronized)
扩容机制和 ArrayList 不一样
所有方法和ArrayList一样
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 public class VectorDemo { public static void main (String[] args) { Vector<String> vec = new Vector <>(); vec.add("苹果" ); vec.add("香蕉" ); vec.add("橙子" ); System.out.println("全部元素:" + vec); System.out.println("索引1:" + vec.get(1 )); vec.set(2 , "葡萄" ); System.out.println("修改后:" + vec); vec.remove(0 ); System.out.println("删除后:" + vec); for (String s : vec) { System.out.print(s + " " ); } System.out.println("\n元素个数:" + vec.size()); System.out.println("是否为空:" + vec.isEmpty()); } }
3. Set 1.set接口是无序的,没有索引!!! 2.不允许重复元素!!(类似于python的集合) 3.和List接口一样,set也是Collection的子接口,因此,常用方法和Collection一样!! 4.遍历:1.可以使用迭代器;2.增强for循环;不可以使用索引的方式来获取 1.HashSet实现类 特点: 底层:基于 HashMap 实现
无序、无索引、元素不可重复
允许存 null,只能存一个 null
没有 get(index)、没有 set(index),不能用普通 for 循环遍历
查询、增删效率极高
常用方法
方法名
作用
返回值
add(E e)
添加元素,重复元素不存入
boolean
remove(Object o)
删除指定元素
boolean
contains(Object o)
判断是否包含指定元素
boolean
size()
获取集合中元素个数
int
isEmpty()
判断集合是否为空
boolean
clear()
清空集合所有元素
void
iterator()
获取迭代器,用于遍历
Iterator
clone()
克隆当前集合副本
Object
isEmpty()
判断是否无元素
boolean
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 public class HashSetDemo { public static void main (String[] args) { HashSet<String> set = new HashSet <>(); set.add("Java" ); set.add("Python" ); set.add("C++" ); set.add("Java" ); System.out.println("集合元素:" + set); System.out.println("是否包含Java:" + set.contains("Java" )); set.remove("C++" ); System.out.println("删除后:" + set); System.out.println("元素个数:" + set.size()); System.out.println("是否为空:" + set.isEmpty()); System.out.print("遍历元素:" ); for (String s : set) { System.out.print(s + " " ); } set.clear(); System.out.println("\n清空后是否为空:" + set.isEmpty()); } }
2. LinkHashSet实现类 特点: 去重、不允许重复
存取有序 (存入顺序 = 取出顺序)
无索引,不能用普通 for 循环
底层:哈希表 + 双向链表
常用方法
方法名
作用
返回值
add(E e)
添加元素,自动去重
boolean
remove(Object o)
删除指定元素
boolean
contains(Object o)
判断是否包含元素
boolean
size()
获取元素个数
int
isEmpty()
判断是否为空集合
boolean
clear()
清空所有元素
void
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 public class LinkedHashSetDemo { public static void main (String[] args) { LinkedHashSet<String> set = new LinkedHashSet <>(); set.add("张三" ); set.add("李四" ); set.add("王五" ); set.add("张三" ); System.out.println("集合元素:" + set); System.out.println("是否包含李四:" + set.contains("李四" )); set.remove("王五" ); System.out.println("删除后:" + set); System.out.println("元素个数:" + set.size()); System.out.println("是否为空:" + set.isEmpty()); System.out.print("遍历:" ); for (String name : set) { System.out.print(name + " " ); } set.clear(); System.out.println("\n清空后是否为空:" + set.isEmpty()); } }
3.TreeSet实现类 特点: 底层:红黑树
元素自动升序排序
不允许重复、无索引
不能存普通自定义对象,需要比较器规则
常用方法
方法名
作用
返回值
add(E e)
添加元素,自动去重 + 排序
boolean
remove(Object o)
删除指定元素
boolean
contains(Object o)
判断是否包含元素
boolean
size()
获取元素个数
int
isEmpty()
判断集合是否为空
boolean
clear()
清空所有元素
void
first()
获取最小元素
E
last()
获取最大元素
E
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 public class TreeSetDemo { public static void main (String[] args) { TreeSet<Integer> ts = new TreeSet <>(); ts.add(5 ); ts.add(1 ); ts.add(9 ); ts.add(3 ); ts.add(5 ); System.out.println("自动排序后:" + ts); System.out.println("最小元素:" + ts.first()); System.out.println("最大元素:" + ts.last()); System.out.println("是否包含3:" + ts.contains(3 )); ts.remove(3 ); System.out.println("删除3后:" + ts); System.out.println("元素个数:" + ts.size()); System.out.println("是否为空:" + ts.isEmpty()); System.out.print("遍历元素:" ); for (Integer num : ts) { System.out.print(num + " " ); } ts.clear(); System.out.println("\n清空后是否为空:" + ts.isEmpty()); } }
修改排序规则 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 TreeSetSortDemo { public static void main (String[] args) { TreeSet<Integer> ts = new TreeSet <>(new Comparator <Integer>() { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } }); ts.add(5 ); ts.add(1 ); ts.add(9 ); ts.add(3 ); System.out.println("自定义降序:" + ts); } }
4.Map 1.Map和Collection是同级别的,用于保存映射关系的数据:key:value(类似于python的字典) 2.Map中的key和value可以是任何引用数据的类型,会封装到HashMap$None对象中 3.Map里面的key不可以重复,但value可以!! 4.常用String类作为Map的key 也可以使用new Object()作为key! 5.key和value是单向一对一关系,通过指定的key可以找到对应的value 使用方法get(key); 注:最常用的是HashMap,但没有实现同步所有线程是不安全的!! 常用方法
方法名
作用
返回值
put(K key, V value)
添加 / 替换键值对
V
get(Object key)
根据键获取值
V
remove(Object key)
根据键删除整组键值对
V
containsKey(Object key)
判断是否包含指定键
boolean
containsValue(Object value)
判断是否包含指定值
boolean
size()
获取键值对个数
int
isEmpty()
判断 Map 是否为空
boolean
clear()
清空所有键值对
void
keySet()
获取所有键的集合
Set
values()
获取所有值的集合
Collection
entrySet()
获取所有键值对对象集合
Set<Map.Entry<K,V>>
putIfAbsent(K,V)
键不存在才添加,存在不覆盖
V
1.HashMap实现类 特点: 底层:哈希表(数组 + 链表 + 红黑树)
键无序、键唯一、值可重复
允许 null 键、null 值 (最多一个 null 键)
线程不安全、效率高
无索引
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 public class HashMapDemo { public static void main (String[] args) { HashMap<String, Integer> map = new HashMap <>(); map.put("张三" , 18 ); map.put("李四" , 20 ); map.put("王五" , 19 ); map.put("张三" , 25 ); System.out.println("原始Map:" + map); System.out.println("李四年龄:" + map.get("李四" )); System.out.println("是否包含王五:" + map.containsKey("王五" )); System.out.println("是否包含年龄19:" + map.containsValue(19 )); System.out.println("键值对个数:" + map.size()); map.remove("王五" ); System.out.println("删除王五后:" + map); map.putIfAbsent("赵六" , 22 ); map.putIfAbsent("李四" , 99 ); System.out.println("putIfAbsent后:" + map); System.out.println("\n--- keySet遍历 ---" ); Set<String> keySet = map.keySet(); for (String key : keySet) { System.out.println(key + " : " + map.get(key)); } System.out.println("\n--- entrySet遍历 ---" ); for (Map.Entry<String, Integer> entry : map.entrySet()) { System.out.println(entry.getKey() + " : " + entry.getValue()); } System.out.println("\n是否为空:" + map.isEmpty()); map.clear(); System.out.println("清空后是否为空:" + map.isEmpty()); } }
2.hashTable实现类 特点: JDK1.0 古老集合,线程安全 (方法都加 synchronized)
键和值都不能存 null
底层哈希表,键无序、唯一
效率低,开发基本不用 ,老旧项目偶尔见到
方法和 HashMap 大部分一样
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 public class HashtableDemo { public static void main (String[] args) { Hashtable<String, Integer> ht = new Hashtable <>(); ht.put("张三" , 20 ); ht.put("李四" , 22 ); ht.put("王五" , 18 ); System.out.println("Hashtable:" + ht); System.out.println("李四年龄:" + ht.get("李四" )); System.out.println("包含张三?" + ht.containsKey("张三" )); System.out.println("包含18?" + ht.containsValue(18 )); ht.remove("王五" ); System.out.println("删除后:" + ht); System.out.println("数量:" + ht.size()); System.out.println("是否为空:" + ht.isEmpty()); for (Map.Entry<String, Integer> entry : ht.entrySet()) { System.out.println(entry.getKey() + " = " + entry.getValue()); } ht.clear(); System.out.println("清空后:" + ht.isEmpty()); } }
3.Properties实现类 特点: 继承 Hashtable ,属于 Map 集合
键和值只能是 String 类型
专门用来读取 / 写入配置文件 (.properties 配置文件)
自带加载配置文件、保存配置文件方法
常用方法
方法名
作用
返回值
setProperty(String key,String value)
设置键值对(存配置)
Object
getProperty(String key)
根据键获取值
String
getProperty(String key,String defaultValue)
按键取值,没有就返回默认值
String
load(InputStream is)
加载 .properties 配置文件
void
store(OutputStream os,String comments)
把配置写入文件
void
size()
获取配置个数
int
clear()
清空所有配置
void
1 2 3 4 username =root password =666888 driver =com.mysql.cj.jdbc.Driver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class LoadProperties { public static void main (String[] args) { Properties prop = new Properties (); try { prop.load(new FileInputStream ("db.properties" )); String user = prop.getProperty("username" ); String pwd = prop.getProperty("password" ); String driver = prop.getProperty("driver" ); System.out.println("用户名:" + user); System.out.println("密码:" + pwd); System.out.println("驱动:" + driver); } catch (Exception e) { e.printStackTrace(); } } }
4.TreeMap 特点: 底层:红黑树 键自动排序 (默认自然升序)
键唯一、值可重复
无索引
可以自定义键的排序规则
不允许 null 键(可以有 null 值)
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 public class TreeMapDemo { public static void main (String[] args) { TreeMap<Integer, String> map = new TreeMap <>(); map.put(5 , "王五" ); map.put(1 , "张三" ); map.put(3 , "李四" ); map.put(5 , "老王" ); System.out.println("TreeMap自动排序:" + map); System.out.println("最小键:" + map.firstKey()); System.out.println("最大键:" + map.lastKey()); System.out.println("键3对应值:" + map.get(3 )); System.out.println("是否包含键1:" + map.containsKey(1 )); map.remove(3 ); System.out.println("删除键3后:" + map); for (Integer key : map.keySet()) { System.out.println(key + " -> " + map.get(key)); } map.clear(); System.out.println("清空后是否为空:" + map.isEmpty()); } }
二十四、泛型 泛型 = 规定集合 / 类只能存什么类型 可以写的位置: 集合 / 接口 声明处 (最常用)
自定义类 上
自定义方法 上
通配符 引用处 (参数、变量)
1.泛型集合 1 2 3 4 5 6 7 8 9 10 11 12 13 ArrayList list = new ArrayList ();list.add("java" ); list.add(123 ); String s = (String) list.get(1 ); ArrayList<String> list = new ArrayList <>(); list.add("Java" );
2.泛型接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public interface GenericInterface <T> { T getValue () ; void setValue (T value) ; } public class StringImpl implements GenericInterface <String> { private String value; @Override public String getValue () { return value; } @Override public void setValue (String value) { this .value = value; } }
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 public class Goods <T,B> { private T data; public Goods () {} public Goods (T data) { this .data = data; } public T getData () { return data; } public void setData (T data) { this .data = data; } public <T> void show (T datas) { System.out.println("存储的数据:" + datas); } }
4.泛型通配符 无界通配符 :<?>
上界通配符 :<? extends 父类> (上限)
下界通配符 :<? super 子类> (下限)
1 2 3 4 5 6 7 8 9 10 11 import java.util.ArrayList;import java.util.List;public class Test { public static void main (String[] args) { List<?> list1 = new ArrayList <String>(); List<?> list2 = new ArrayList <Integer>(); List<?> list3 = new ArrayList <Object>(); } }
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 static void showPerson (List<? extends Person> list) { for (Person p : list) { System.out.println(p); } } public static void main (String[] args) { List<Student> sList = new ArrayList <>(); List<Teacher> tList = new ArrayList <>(); List<Person> pList = new ArrayList <>(); showPerson(sList); showPerson(tList); showPerson(pList); }
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 public static void addStudent (List<? super Student> list) { list.add(new Student ()); Object o = list.get(0 ); } public static void main (String[] args) { List<Person> pList = new ArrayList <>(); List<Object> oList = new ArrayList <>(); List<Student> sList = new ArrayList <>(); addStudent(pList); addStudent(oList); addStudent(sList); }
二十五、线程 其他相关概念: 1.程序:指完成特定任务,用某种语言编写的一组指令的集合 2.进程:指在运行的程序,如打开了QQ,系统会自动分配内存空间,当又启动了迅雷,就又分配一个内存空间 如果关闭了,他就会释放空间;它有着自身的产生、存在和消亡的过程!! 线程 1.线程是由多个进程创建的,是进程的一个实体。 2.单线程:同一时间,只允许一个线程 3.多线程:同一时间,可以执行多个线程;如:打开了QQ,可以同时开多个窗口 4.并发:同一时刻,多个任务交替执行,造成一种”貌似同时”的错觉,简单说就是单核Cpu就是实现多任务就是并发 5.并行:同一时刻,多个任务同时执行,多核Cpu可以实现并行 1.创建方式一(继承 Thread 类) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class MyThread extends Thread { @Override public void run () { for (int i = 0 ; i < 5 ; i++) { System.out.println("线程执行:" + i); } } } public class TestThread { public static void main (String[] args) { MyThread t = new MyThread (); t.start(); } }
2.创建方式二(实现 Runnable 接口) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class MyRunnable implements Runnable { @Override public void run () { for (int i = 0 ; i < 5 ; i++) { System.out.println("Runnable 线程:" + i); } } } public class Test { public static void main (String[] args) { MyRunnable r = new MyRunnable (); Thread t = new Thread (r); t.start(); } }
3.常用方法
方法
作用
start()
启动线程
run()
线程任务逻辑
sleep(long ms)
休眠,暂停指定毫秒
getName()
获取线程名
setName()
设置线程名
currentThread()
获取当前正在执行的线程
yield()
礼让线程
join()
插队线程
4.用户线程和守护线程 我希望主线程执行完后,即使子线程没有结束,也让他自动结束!! 1.用户线程:也叫工作线程,当线程的任务执行完毕或者通知方式结束 2.守护线程:一般是为工作线程服务,当所有的用户线程结束,守护线程自动结束
对比项
用户线程
守护线程
默认类型
普通线程默认是用户线程
需手动 setDaemon(true)
JVM 行为
JVM 会等待全部执行完
JVM 不等待,随用户线程结束而终止
生命周期
独立,自身逻辑控制
依赖用户线程,用户线程全灭则终止
典型场景
核心业务(订单、支付、计算)
GC、日志、监控、心跳、定时任务
优先级
默认 5(NORM_PRIORITY)
通常较低,可手动调整
子线程默认
创建的子线程默认是用户线程
创建的子线程默认是守护线程
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 public class UserThreadDemo { public static void main (String[] args) { Thread userThread = new Thread (() -> { System.out.println("用户线程开始..." ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("用户线程结束" ); }); userThread.start(); System.out.println("主线程结束" ); } } public class DaemonThreadDemo { public static void main (String[] args) { Thread daemonThread = new Thread (() -> { while (true ) { try { Thread.sleep(1000 ); System.out.println("守护线程运行中..." ); } catch (InterruptedException e) { e.printStackTrace(); } } }); daemonThread.setDaemon(true ); daemonThread.start(); try { Thread.sleep(3000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("主线程结束,JVM 退出" ); } }
5.线程声明周期 新建 :new 线程对象
就绪 :调用 start (),等待 CPU 调度
运行 :抢到 CPU,执行 run ()
阻塞 :sleep、wait、锁等待
死亡 :run 执行完毕 / 异常终止
6.线程同步机制 在多线程编程。一些敏感的数据不允许被多个线程访问,此时就使用同步访问技术,保证数据在任何时刻 最多有一个线程访问,以保证数据完整性!!! 理解:即当有一个线程对内存进行操作时,其他线程不可以操作,直到该线程完成其他线程才能操作!!! 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 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class SellTicket { public static void main (String[] args) { SellTicket2 sellTicket2 = new SellTicket2 (); new Thread (sellTicket2).start(); new Thread (sellTicket2).start(); new Thread (sellTicket2).start(); } } class SellTicket2 implements Runnable { private int ticketnum = 100 ; public void run () { while (true ){ if (ticketnum <= 0 ){ System.out.println("票以售空" ); break ; } try { Thread.sleep(50 ); } catch (InterruptedException e) { throw new RuntimeException (e); } System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票," + "剩余票数" + (--ticketnum)); } } }
2.互斥锁(synchronized) 在java语言中引入了对象互斥锁的概念,来保证共享数据的完整性。 synchronized关键字来与对象的互斥锁联系,当某个对象用synchronized修饰时,该对象在任意时刻只能由一个线程访问 同步的局限性:导致程序执行效率降低 同步方法(非静态的)的锁可以是this,也可以时其他对象(要求时同一个对象) 1.写到代码块 1 2 3 4 5 6 synchronized (this ) {}synchronized (obj) {}synchronized (ClassName.class) {}
2.写到成员方法\静态方法 1 2 3 public synchronized void test () {}public static synchronized void test () {}
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 public class SellTicket { public static void main (String[] args) { SellTicket2 sellTicket2 = new SellTicket2 (); new Thread (sellTicket2).start(); new Thread (sellTicket2).start(); new Thread (sellTicket2).start(); } } class SellTicket2 implements Runnable { private int ticketnum = 1000 ; private boolean falg = true ; public synchronized void m () { if (ticketnum <= 0 ){ System.out.println("票以售空" ); falg = false ; return ; } try { Thread.sleep(10 ); } catch (InterruptedException e) { throw new RuntimeException (e); } System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票," + "剩余票数" + (--ticketnum)); } public void run () { while (falg) { m(); } } }
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 public class DeadLock { public static void main (String[] args) { DeadLockDemo A = new DeadLockDemo (true ); DeadLockDemo B = new DeadLockDemo (false ); A.start(); B.start(); } } class DeadLockDemo extends Thread { static Object o1 = new Object (); static Object o2 = new Object (); boolean flag; public DeadLockDemo (boolean flag) { this .flag = flag; } public void run () { if (flag){ synchronized (o1){ System.out.println(Thread.currentThread().getName() + "进入1" ); synchronized (o2){ System.out.println(Thread.currentThread().getName() + "进入2" ); } } }else { synchronized (o2){ System.out.println(Thread.currentThread().getName() + "进入3" ); synchronized (o1){ System.out.println(Thread.currentThread().getName() + "进入4" ); } } } } }
7.更多相关线程内容 点击这里
二十六、异常 异常是什么 程序运行中非正常情况 ,打断正常流程;Java 用异常类对象 封装错误信息。
异常体系总根 Throwable ├─ Error 系统级严重错误(程序管不了)└─ Exception 程序可处理异常(我们要管) ├─ 编译时异常(受检异常) └─ 运行时异常(RuntimeException)
三大分类(必背)
Error 错误 虚拟机崩溃、内存溢出、栈溢出;不用捕获、处理不了 。例:StackOverflowError、OutOfMemoryError
编译时异常(受检异常) 除了 RuntimeException 及其子类,都是编译异常;必须 try-catch 或 throws 抛出去 ,否则编译报错。例:IOException、SQLException
运行时异常(非受检异常) RuntimeException 及其子类;编译不报错,运行才崩 ,可捕获可不捕获,靠代码规范避免。例:空指针 NullPointerException数组越界 ArrayIndexOutOfBoundsException类型转换 ClassCastException除数为 0 ArithmeticException
1.常见异常类
异常分类
异常类名
中文名称
典型触发场景
运行时异常(非受检异常,RuntimeException 子类)
NullPointerException
空指针异常
调用 null 对象的方法 / 属性、数组为 null 时操作数组元素
ArrayIndexOutOfBoundsException
数组下标越界异常
访问数组时,下标小于 0 或大于等于数组长度
StringIndexOutOfBoundsException
字符串下标越界异常
调用 charAt ()、substring () 等方法时,下标超出字符串长度范围
IndexOutOfBoundsException
索引越界异常
数组 / 字符串 / 集合下标越界的父类异常,通用索引越界场景
ClassCastException
类型强制转换异常
不兼容的类型强制转换,如把 String 强制转为 Integer、子类对象向上转型后错误向下转型
ArithmeticException
算术运算异常
整数除法中除数为 0、对负数开平方根等非法算术运算
IllegalArgumentException
非法参数异常
方法入参不符合要求,如传入 null、数值超出合法范围、格式错误
IllegalStateException
非法状态异常
调用方法时,对象的状态不支持该操作,如未初始化就调用业务方法、重复调用关闭方法
UnsupportedOperationException
不支持的操作异常
调用了不支持的方法,如对不可变集合执行 add/remove 操作、未实现的接口方法被调用
NumberFormatException
数字格式转换异常
字符串转数字时,字符串内容不符合数字格式,如把 “abc” 转为 Integer
NegativeArraySizeException
数组长度为负异常
创建数组时,指定的长度为负数
ConcurrentModificationException
并发修改异常
遍历集合(如 ArrayList)时,同时对集合进行 add/remove 等修改操作(非迭代器自身的 remove)
NoSuchElementException
无此元素异常
调用迭代器的 next () 时,已无更多元素;或从空集合中获取元素
编译时异常(受检异常,Exception 直接子类)
IOException
输入输出异常
文件读写、网络流操作、资源关闭失败等 IO 相关操作出错,是所有 IO 异常的父类
FileNotFoundException
文件未找到异常
尝试打开不存在的文件、路径错误、无文件访问权限
EOFException
文件已结束异常
从文件 / 流中读取数据时,已到达文件末尾仍继续读取
SocketException
套接字异常
网络 Socket 操作出错,如连接超时、端口被占用、网络断开
SQLException
数据库操作异常
数据库连接、SQL 执行、结果集处理出错,是所有数据库相关异常的父类
ClassNotFoundException
类未找到异常
反射加载类时,指定的类路径 / 类名错误、类文件不存在
NoSuchMethodException
方法未找到异常
反射调用方法时,指定的方法名 / 参数列表不存在
NoSuchFieldException
字段未找到异常
反射操作字段时,指定的字段名不存在
IllegalAccessException
非法访问异常
反射访问类的私有方法 / 字段时,无访问权限;或访问权限不符合要求
InterruptedException
线程中断异常
线程在 sleep ()、wait ()、join () 等阻塞状态时,被其他线程调用 interrupt () 中断
TimeoutException
超时异常
异步操作、线程等待、网络请求等超出指定的超时时间
系统错误(Error 子类,程序无法处理)
StackOverflowError
栈溢出错误
方法递归调用过深、无限循环调用方法,导致虚拟机栈内存溢出
OutOfMemoryError
内存溢出错误
堆内存不足、元空间溢出、直接内存溢出,虚拟机无法分配新的内存
NoClassDefFoundError
类定义未找到错误
编译时类存在,运行时类文件缺失 / 版本不匹配,虚拟机无法加载类定义
ExceptionInInitializerError
静态初始化异常
类的静态代码块、静态变量初始化时抛出异常,导致类加载失败
VirtualMachineError
虚拟机错误
虚拟机内部运行出错,是所有虚拟机相关错误的父类
2. try-catch 捕获异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 try { 可能出异常的代码 }catch (异常类型 e){ 异常处理逻辑 } ... finally { } try (定义资源1 ; 定义资源2 ){ }catch (异常类型 e){ }
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 Try { public static void main (String[] args) { try { int a = 1 /0 ; }catch (Exception e){ System.out.println("捕获异常" ); }finally { System.out.println("无论有没有异常都执行" ); } } } try ( FileReader fr = new FileReader ("a.txt" ); BufferedReader br = new BufferedReader (fr) ){ String line; while ((line = br.readLine()) != null ){ System.out.println(line); } } catch (IOException e) { e.printStackTrace(); }
3. throw 将异常抛给下一个调用者 1 2 3 public void read () throws IOException {}public void test () throws Exception{}
4. throws 主动抛出异常 1 2 3 4 public void test () throws Exception { System.out.println("即将抛出异常" ); throw new Exception (); }
二十七、IO流 1.文件 文件是用于保存数据的地方,比如word文件、txt文件等,既可以保存一张图片也可以保存视频、声音。 文件流:文件在程序中是以流的形式来操作的 形式: java程序(内存)——>文件(磁盘) 这叫输入流 数据从数据源和程序的路径 java程序(内存)<——文件(磁盘) 这叫输出流 数据从程序到数据源的路径 2.File类 创建文件
构造方法
作用说明
核心特点
new File(String pathname)
根据完整路径字符串 创建 File 对象
直接传入文件 / 目录的完整路径,最常用
new File(File parent, String child)
根据父目录 File 对象 + 子路径 创建
先定义父目录文件,再拼接子路径,更灵活
new File(String parent, String child)
根据父目录字符串 + 子路径字符串 创建
用两个字符串拼接路径,代码更简洁
file.createNewFile()
boolean
创建空文件 ,路径中的目录必须存在,否则报错
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 package File.CreateFileAndMkdir;import java.io.File;import java.io.IOException;public class FileCreate { public static void main (String[] args) { File file = new File ("E:/IO流复习" ,"new1.txt" ); try { file.createNewFile(); System.out.println("创建成功" ); } catch (IOException e) { throw new RuntimeException (e); } String path = "E:/IO流复习/new2.txt" ; File file1 = new File (path); try { file1.createNewFile(); System.out.println("创建成功" ); } catch (IOException e) { throw new RuntimeException (e); } File filepath = new File ("E:/IO流复习" ); File file3 = new File (filepath,"new3.txt" ); try { file3.createNewFile(); System.out.println("创建成功" ); } catch (IOException e) { throw new RuntimeException (e); } } }
文件方法
方法名
功能说明
createNewFile
创建空文件,已存在返回 false
mkdir
创建单级 空目录
mkdirs
创建多级 目录(常用)
delete
删除文件 / 空目录,不走回收站
renameTo
重命名 / 移动文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class CreateMkdir { public static void main (String[] args) { File file = new File ("E:\\IO流复习\\ddd" ); boolean mkdir = file.mkdir(); System.out.println(mkdir); File file1 = new File ("E:\\IO流复习\\ccc\\bbb\\ggg" ); boolean mkdirs = file1.mkdirs(); System.out.println(mkdirs); System.out.println(file.delete()); } }
方法名
功能说明
exists
判断文件或目录是否存在
isFile
判断是否是普通文件
isDirectory
判断是否是文件夹
isHidden
判断是否为隐藏文件
canRead
判断是否可读
canWrite
判断是否可写
canExecute
判断是否可执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 System.out.println(file.exists()); System.out.println(file.isFile()); System.out.println(dir.isDirectory()); System.out.println(file.isHidden()); System.out.println(file.canRead()); System.out.println(file.canWrite()); System.out.println(file.canExecute());
方法名
功能说明
getName
获取文件 / 目录名称
getPath
获取相对路径(构造时传入路径)
getAbsolutePath
获取绝对路径
getCanonicalPath
获取规范绝对路径(去冗余)
getParent
获取父路径字符串
getParentFile
获取父路径对应的 File 对象
length
获取文件大小(字节)
lastModified
获取最后修改时间(毫秒值)
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 System.out.println(file.getName()); System.out.println(file.getPath()); System.out.println(file.getAbsolutePath()); System.out.println(file.getCanonicalPath()); System.out.println(file.getParent()); System.out.println(file.getParentFile()); System.out.println(file.length()); long l = file.lastModified();Instant instant = Instant.ofEpochMilli(l);LocalDateTime localDate = instant.atZone(ZoneId.of("Asia/Shanghai" )).toLocalDateTime();DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss" );String format = dateTimeFormatter.format(localDate);System.out.println(format);
方法名
功能说明
list
返回目录下所有子名称 String []
listFiles
返回目录下所有子文件 File []
list(FilenameFilter)
按过滤器筛选文件名数组
listFiles(FilenameFilter)
按过滤器筛选 File 对象数组
1 2 3 4 5 6 File file1 = new File ("E:/Io流复习/listFile" );File[] files = file1.listFiles(); for (File file2 : files){ System.out.println(file2.getName()); }
3.IO流分类 1.数据方向 输入流 :读数据(从文件 → 程序)输出流 :写数据(从程序 → 文件)2.数据类型 字节流
处理一切文件:文本、图片、视频、音频
基类:
输入:InputStream
输出:OutputStream
字符流
3. 四大抽象基类 作用: FileInputStream:文件字节输入流 专门从本地文件 读取字节数据,属于 InputStream 子类。
构造:
构造方法
说明
FileInputStream(String path)
通过文件路径创建读取流
FileInputStream(File file)
通过 File 对象创建读取流
常用方法
方法
作用
read()
读 1 个字节,返回字节 int,读完返回 -1
read(byte[] b)
读数据到字节数组,返回实际读取长度
read(byte[] b, int off, int len)
从数组 off 位置开始,最多读 len 个字节
available()
获取文件剩余可读字节数
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 public class ByteInputStream { public static void main (String[] args) throws Exception { FileInputStream fileInputStream = new FileInputStream ("E:/IO流复习/ByteIn/ccc.txt" ); byte [] bytes = new byte [1024 ]; int read = fileInputStream.read(bytes); System.out.print(new String (bytes)); fileInputStream.close(); } }
(2)FileOutputStream 作用: 文件字节输出流 ,OutputStream 子类负责:程序 → 写入数据到本地文件
构造:
构造方法
功能说明
FileOutputStream(String path)
创建字节输出流,覆盖 原文件内容
FileOutputStream(String path, boolean append)
append=true 追加写入 ,不覆盖
FileOutputStream(File file)
通过 File 对象创建,覆盖写入
FileOutputStream(File file, boolean append)
File 对象 + 追加模式
常用方法
方法
作用
write(int b)
写入 1 个字节
write(byte[] b)
写入整个字节数组
write(byte[] b,int off,int len)
从数组 off 开始,写入 len 个字节
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 public class ByteOutputStream { public static void main (String[] args) throws Exception { FileOutputStream fileOutputStream = new FileOutputStream ("E:/IO流复习/ByteOut/ccc.txt" ,true ); String str = "hhhhh\nssssss" ; fileOutputStream.write(str.getBytes()); fileOutputStream.close(); } }
5. FileReader、FileWriter字符流 (1)FileReader 作用: FileReader :文件字符输入流,读纯文本
构造:
构造方法
作用
FileReader(String path)
根据文件路径创建字符读流
FileReader(File file)
根据 File 对象创建字符读流
方法
方法名
功能
read()
读单个字符,读完返回 -1
read(char[] cbuf)
读入字符数组,返回读取个数
read(char[] cbuf,int off,int len)
从偏移量开始读指定长度
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 public class fileReader { public static void main (String[] args) throws Exception { FileReader fileReader = new FileReader ("E:/IO流复习/Writer/111.txt" ); CharBuffer charBuffer = CharBuffer.allocate(128 ); int read1 = fileReader.read(charBuffer); System.out.println(new String (charBuffer.array())); fileReader.close(); }
(2)FileWriter 作用: FileWriter :文件字符输出流,写纯文本
构造:
构造方法
作用
FileWriter(String path)
覆盖写入
FileWriter(String path, boolean append)
append=true 追加写入
FileWriter(File file)
覆盖写入
FileWriter(File file, boolean append)
追加写入
常用方法
方法名
功能
write(int c)
写单个字符
write(char[] cbuf)
写整个字符数组
write(char[] cbuf,int off,int len)
写数组指定范围
write(String str)
直接写字符串(超好用)
write(String str,int off,int len)
写字符串指定部分
flush
刷新缓冲区
close
关闭流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class fileWriter { public static void main (String[] args) throws Exception { FileWriter fileWriter = new FileWriter ("E:/IO流复习/Writer/222.txt" ,true ); String str = "你好,python" ; fileWriter.append(str); fileWriter.close(); } }
作用: 属于字节包装流 ,包装 FileInputStream / FileOutputStream
自带内置缓冲区 ,减少磁盘 IO,读写速度超快
用法和普通字节流一样,只是套了一层包装
构造:
构造方法
说明
BufferedInputStream(InputStream in)
包装字节输入流,默认缓冲大小
BufferedOutputStream(OutputStream out)
包装字节输出流,默认缓冲大小
方法和非包装一摸一样!!!! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class BufferInput { public static void main (String[] args) throws Exception { BufferedInputStream bufferedInputStream = new BufferedInputStream ( new FileInputStream ("E:/IO流复习/BufferByte/111.txt" )); byte [] bytes = new byte [1024 ]; int read = bufferedInputStream.read(bytes); System.out.print(new String (bytes)); bufferedInputStream.close(); } }
7. BufferedReader、BufferedWriter包装字符流 (1)BufferedReader 作用: 包装 FileReader ,属于字符包装流
自带缓冲区,读取文本更快
独有核心功能:按行读取 readLine()
构造:
构造方法
说明
BufferedReader(Reader r)
包装任意字符输入流,常用包装 FileReader
常用方法
方法名
作用
read()
读单个字符,读完返回 -1
read(char[] cbuf)
读入字符数组,返回读取长度
read(char[] cbuf,int off,int len)
指定位置和长度读取
readLine()
读一整行文本 ,无内容返回 null(独有)
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 public class bufferReader { public static void main (String[] args) throws Exception { BufferedReader bufferedReader = new BufferedReader ( new FileReader ("E:/IO流复习/BufferReader/111.txt" )); String str; while ((str = bufferedReader.readLine()) != null ){ System.out.println(str); } bufferedReader.close(); } }
(2)BufferedWriter 作用: 字符包装流 ,包装 FileWriter
自带缓冲区,写入速度更快
独有方法:newLine () 自动换行 (跨平台通用)
构造:
构造方法
说明
BufferedWriter(Writer w)
包装字符输出流,常用包装 FileWriter
常用方法
方法名
作用
write(int c)
写入单个字符
write(char[] cbuf)
写入整个字符数组
write(char[] cbuf,int off,int len)
写入数组指定范围
write(String str)
直接写字符串
newLine()
换行 (独有,跨平台)
flush()
刷新缓冲区,强制写入文件
close()
先刷新再关流,自动关闭内层流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class bufferWriter { public static void main (String[] args) throws Exception { BufferedWriter bufferedWriter = new BufferedWriter ( new FileWriter ("E:/IO流复习/BufferReader/222.txt" ,true )); String str = "哈哈哈哈哈" ; bufferedWriter.write(str); bufferedWriter.newLine(); String str2 = "你时水水水水" ; bufferedWriter.write(str2); bufferedWriter.close(); } }
作用: InputStreamReader:字节输入流 → 字符输入流 的转换桥梁
把 FileInputStream 字节流 转成 字符流
可以手动指定编码 UTF-8 / GBK ,解决中文乱码
属于 字符流 Reader 的子类
常被 BufferedReader 包装 按行读取
构造:
构造方法
说明
InputStreamReader(InputStream in)
使用系统默认编码转换
InputStreamReader(InputStream in,String charset)
指定编码 转换(常用)
常用方法
方法
作用
read()
读单个字符,返回 - 1 结束
read(char[] cbuf)
读取到字符数组
read(char[] cbuf,int off,int len)
读取指定范围
close()
关闭流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class InputToReader { public static void main (String[] args) throws Exception { InputStreamReader inputStreamReader = new InputStreamReader ( new FileInputStream ("E:/IO流复习/new2.txt" ), "UTF-8" ); char [] chars = new char [128 ]; int read = inputStreamReader.read(chars); System.out.println(new String (chars)); inputStreamReader.close(); } }
(2)OutputStreamWriter 作用: OutputStreamWriter :字节输出流 → 字符输出流
转换桥梁可以指定编码 (UTF-8 / GBK)写入文件,解决写中文乱码 。
属于 Writer 子类。
构造:
构造方法
说明
OutputStreamWriter(OutputStream out)
使用系统默认编码
OutputStreamWriter (OutputStream out,String 编码)
指定编码写入(常用)
常用方法
方法
作用
write(int c)
写单个字符
write(char[] cbuf)
写字符数组
write(char[] cbuf,int off,int len)
写数组指定区间
write(String str)
直接写字符串
flush
刷新缓冲区
close
关闭流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class OutputToWriter { public static void main (String[] args) throws Exception { OutputStreamWriter outputStreamWriter = new OutputStreamWriter ( new FileOutputStream ("E:/IO流复习/new4.txt" ),"GBK" ); outputStreamWriter.write("指定GBK编码格式!!!!" ); outputStreamWriter.close(); } }
作用: ObjectInputStream :读取对象 (反序列化)
把文件中保存的对象数据,还原成 Java 对象。
属于 字节输入流、包装流 。
注意:
要被读取的类必须:
实现 Serializable 接口(标记接口,无方法)
序列化和反序列化 版本号一致
构造:
构造方法
说明
ObjectInputStream(InputStream in)
包装字节输入流,常用 new FileInputStream ()
常用方法
方法名
作用
readObject()
读取一个序列化对象,返回 Object,需强转
readInt()
读取 int 类型
readByte()
读取 byte 类型
readShort()
读取 short 类型
readLong()
读取 long 类型
readFloat()
读取 float 类型
readDouble()
读取 double 类型
readBoolean()
读取 boolean 类型
readChar()
读取 char 类型
readUTF()
读取 UTF-8 编码字符串
readFully(byte[] b)
一次性读满整个字节数组
readFully(byte[] b,int off,int len)
读取指定长度填满数组指定位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class ObjectInput { public static void main (String[] args) throws Exception { ObjectInputStream objectInputStream = new ObjectInputStream ( new FileInputStream ("E:/IO流复习/student.txt" )); Object object = objectInputStream.readObject(); System.out.println(object); objectInputStream.close(); } }
(2)ObjectOutputStream 作用: ObjectOutputStream :
把 Java 对象 写入文件 / 网络流,即序列化 内存对象 → 写到文件保存
构造:
构造方法
说明
ObjectOutputStream(OutputStream out)
包装字节输出流,常用包装 FileOutputStream
常用方法
方法
作用
writeObject()
写入一个对象 (最核心)
writeInt()
写 int
writeByte()
写 byte
writeShort()
写 short
writeLong()
写 long
writeFloat()
写 float
writeDouble()
写 double
writeBoolean()
写 boolean
writeChar()
写 char
writeUTF()
写 UTF-8 编码字符串
write(byte[] b)
写字节数组
write(byte[] b,int off,int len)
写数组指定范围
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 public class Student implements Serializable { private static final long serialVersionUID = -8433626682217889602L ; private String name; private int age; public Student (String name, int age) { this .name = name; this .age = age; } public String getName () { return name; } public void setName (String name) { this .name = name; } @Override public String toString () { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}' ; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } } public class Objectoutput { public static void main (String[] args) throws Exception { Student student = new Student ("xiaochen" ,20 ); ObjectOutputStream objectOutputStream = new ObjectOutputStream ( new FileOutputStream ("E:/IO流复习/student.txt" )); objectOutputStream.writeObject(student); objectOutputStream.close(); } }
10.标准输入输出流 作用: Java 自带默认不用创建、直接能用 的流
标准输入流 :System.in
标准输出流 :System.out
底层:
名称
类型
作用
System.in
InputStream 字节输入流
从控制台键盘 读数据
System.out
PrintStream 字节打印流
向控制台窗口 写数据
特点: 程序启动自动创建 ,不用 new
不用手动关闭 ,JVM 自动管理
默认绑定:键盘输入、控制台输出
可以重定向 :把输入输出改成文件
1 2 3 4 5 6 7 8 9 10 11 12 13 import java.io.BufferedReader;import java.io.InputStreamReader;public class SysInDemo { public static void main (String[] args) throws Exception { BufferedReader br = new BufferedReader (new InputStreamReader (System.in)); System.out.print("请输入:" ); String line = br.readLine(); System.out.println("你输入了:" + line); } }
11.打印流 特点: 只能输出、不能输入
不会抛 IOException ,代码简洁
可以原样输出任意类型 :int、double、对象、字符串
有自动换行、自动刷新
开发最常用:System.out 本质就是 PrintStream
区别:
类名
所属
特点
PrintStream
字节打印流
字节流,处理一切文件,System.out 就是它
PrintWriter
字符打印流
字符流,适合文本,可指定编码
构造:
构造
作用
PrintStream(OutputStream out)
包装字节输出流
PrintStream(String fileName)
直接传文件路径
构造
作用
PrintWriter(Writer out)
包装字符输出流
PrintWriter(OutputStream out)
包装字节流(自动转字符)
PrintWriter(String fileName)
直接文件路径
常用方法
方法
作用
print (任意类型)
不换行打印
println (任意类型)
打印并自动换行
printf (格式,参数)
格式化打印
flush()
刷新缓冲区
close()
关闭流
1 2 3 4 5 6 7 8 9 10 11 import java.io.PrintStream;public class PSMain { public static void main (String[] args) throws Exception { PrintStream ps = new PrintStream ("a.txt" ); ps.println("你好打印流" ); ps.println(123 ); ps.println(3.14 ); ps.close(); } }
作用: 专门处理 ZIP 格式 压缩包
ZipInputStream:解压流 → 读取 zip 包、解压里面文件
构造:
构造
作用
ZipInputStream(InputStream in)
包装文件字节输入流
常用方法
方法
作用
getNextEntry()
获取压缩包里下一个条目,无返回 null
closeEntry()
关闭当前条目
read(byte[] b)
读取条目里的文件内容
close()
关闭流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ZipStreamDemo1 { public static void main (String[] args) throws Exception { ZipInputStream zipInputStream = new ZipInputStream (new FileInputStream ("E:/IO流复习/Zip.zip" )); ZipEntry zipEntry; while ((zipEntry = zipInputStream.getNextEntry()) != null ){ System.out.println(zipEntry); } zipInputStream.close(); } }
(2)ZipOutputStream 作用: ZipOutputStream:压缩流 → 把多个文件 / 文件夹打成 zip 压缩包
构造:
构造
作用
ZipInputStream(InputStream in)
包装文件字节输入流
常用方法
方法
作用
getNextEntry()
获取压缩包里下一个条目,无返回 null
closeEntry()
关闭当前条目
read(byte[] b)
读取条目里的文件内容
close()
关闭流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mport java.io.*; import java.util.zip.ZipOutputStream;import java.util.zip.ZipEntry;public class ZipDemo { public static void main (String[] args) throws IOException { ZipOutputStream zos = new ZipOutputStream (new FileOutputStream ("out.zip" )); zos.putNextEntry(new ZipEntry ("a.txt" )); FileInputStream fis = new FileInputStream ("a.txt" ); byte [] buf = new byte [1024 ]; int len; while ((len = fis.read(buf)) != -1 ) { zos.write(buf, 0 , len); } fis.close(); zos.closeEntry(); zos.finish(); zos.close(); } }
13.更多内容 点击这里
二十八、反射 Java 反射(Reflection)是运行时 动态获取类信息、创建对象、调用方法 / 访问字段的机制,核心是通过java.lang.Class对象反向操作类的元数据。 正常(正向) :编译期已知类,直接new对象、调用方法。反射(反向) :编译期未知类,运行时通过Class对象 “看透” 类结构并操作。本质 :JVM 加载类后,在方法区生成唯一Class对象,反射即操作该对象及关联的Field/Method/Constructor。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 25 26 27 28 Class<User> clazz1 = User.class; User user = new User ();Class<? extends User > clazz2 = user.getClass(); Class<?> clazz3 = Class.forName("com.example.User" ); ClassLoader classloder = car.getClass().getClassLoader();Class cls2 = classloder.loadClass(classAllPath);System.out.println(cls2);
2.有Class对象的类型 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 String.class Object .class User .classList.class Runnable .class int [].class String [].class User [][].class byte .class short .class int .class long .class float .class double .class char .class boolean .class Integer.class Double .class Boolean .class Season.class Override.class Autowired .class void .class
3.类加载 把 .class 字节码文件加载到内存,转换成运行时数据结构,并生成 Class 对象的过程 。(1)类加载全过程 5 步 加载 → 验证 → 准备 → 解析 → 初始化
1. 加载(Load)
读取 .class 字节码到内存
在堆内存生成唯一 Class 对象
方法区存放类的元数据
2. 验证(Verify) 保证字节码安全、合规:
文件格式验证
元数据验证
字节码验证
符号引用验证
3. 准备(Prepare) 给静态变量分配内存、赋默认初始值
int → 0
boolean → false
引用 → null
⚠️ 不会赋代码里的自定义初始值
4. 解析(Resolve) 把符号引用 替换成 直接内存地址引用 静态绑定、常量池解析都在这步
5. 初始化(Init) 执行静态代码块、给静态变量赋代码中定义的初始值 只在第一次主动使用类 时触发,且只执行一次。
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 public class ClassLoad03 { public static void main (String[] args) throws ClassNotFoundException { B b = new B (); } } class B { static { System.out.println("B 静态代码块被执行" ); num = 300 ; } static int num = 100 ; public B () { System.out.println("B() 构造器被执行" ); } }
(2)类的主动引用(会触发初始化) new 对象
调用类的静态方法
使用类的静态常量(非 final )
反射 Class.forName()
初始化子类,先初始化父类
(3)动态加载和静态加载 静态加载 编译期间就把类依赖写死,编译时必须能找到类,找不到直接编译报错 语法:new 类名()、直接使用类、继承、接口实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class loo2 { public static void main (String[] args) { Car car = new Car (); CCC c = new CCC (); } } public class Car { public String brand = "宝马" ; public int price = 5000000 ; public String color = "浅蓝色" ; @Override public String toString () { return "Car{" + "brand='" + brand + '\'' + ", price=" + price + ", color='" + color + '\'' + '}' ; } }
动态加载 运行期间才加载类,编译时不依赖类,运行时通过反射加载 语法:Class.forName("全类名")、类加载器加载
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 public class loo { public static void main (String[] args) throws Exception { Scanner scanner = new Scanner (System.in); System.out.println("输入一个数字:" ); int i = scanner.nextInt(); switch (i){ case 1 -> System.out.println(Class.forName("com.Xc.Car" )); case 2 -> System.out.println(Class.forName("com.Xc.cat" )); case 3 -> System.out.println(Class.forName("com.Xc.duhs" )); } } } public class Car { public String brand = "宝马" ; public int price = 5000000 ; public String color = "浅蓝色" ; } public class cat { public String name = "招财猫" ; public int age; }
4.获取类信息 测试类: 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 public class Person { public String publicName; protected int protectedAge; String defaultAddr; private double privateSalary; public static String staticPublicInfo; public static final String NATIONALITY = "中国" ; private static final int MAX_AGE = 150 ; public Person () { } public Person (String name) { this .publicName = name; } protected Person (int age) { this .protectedAge = age; } Person(String name, int age) { this .publicName = name; this .protectedAge = age; } private Person (double salary) { this .privateSalary = salary; } public void publicSay () { System.out.println("公有方法" ); } protected void protectedWork () { System.out.println("保护方法" ); } void defaultSleep () { System.out.println("默认权限方法" ); } private void privateShowInfo () { System.out.println("私有方法:" + privateSalary); } public static void staticHello () { System.out.println("静态公有方法" ); } private static void staticPrivateTip () { System.out.println("静态私有方法" ); } public final void finalMethod () { System.out.println("final 不可重写方法" ); } }
1.基本信息
功能
方法
完整全限定类名
getName
简单类名
getSimpleName
获取直接父类
getSuperclass
获取实现的所有接口
getInterfaces
获取修饰符 int 编码
getModifiers
判断是否接口
isInterface
判断是否数组
isArray
判断是否基本类型
isPrimitive
判断是否枚举
isEnum
判断是否注解
isAnnotation
获取所在包
getPackage
是否存在指定注解
isAnnotationPresent
获取指定注解
getAnnotation
获取所有注解
getAnnotations
获取本类直接注解
getDeclaredAnnotations
1 2 3 4 5 6 7 8 9 10 11 public class BeaseText { public static void main (String[] args) throws Exception { Class<?> aClass = Class.forName("com.Xc.Car" ); System.out.println(aClass.getName()); System.out.println(aClass.getSimpleName()); System.out.println(aClass.getSuperclass()); System.out.println(aClass.getModifiers()); System.out.println(aClass.getPackage()); } }
2.获取构造方法
功能
方法
获取本类所有构造器 (所有权限)
getDeclaredConstructors
获取本类所有 public 构造器
getConstructors
获取指定参数类型的私有 / 任意构造器
getDeclaredConstructor(Class…)
获取指定参数类型的 public 构造器
getConstructor(Class…)
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 BeaseText { public static void main (String[] args) throws Exception { Class<?> aClass = Class.forName("com.Xc.Person" ); Constructor<?> constructor1 = aClass.getConstructor(); System.out.println("获取无参构造器:" + constructor1); Constructor<?> constructor = aClass.getConstructor(String.class); System.out.println("获取指定构造器:" + constructor); System.out.println("=====" ); Constructor<?>[] constructors = aClass.getConstructors(); for (Constructor c : constructors){ System.out.println(c); } System.out.println("=====" ); Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors(); for (Constructor c : declaredConstructors){ System.out.println(c); } } }
3.创建实例
功能
方法
通过构造器创建实例
构造器.newInstance()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class BeaseText { public static void main (String[] args) throws Exception { Class<?> aClass = Class.forName("com.Xc.Person" ); Constructor<?> constructor1 = aClass.getConstructor(); Constructor<?> constructor = aClass.getConstructor(String.class); Person object1 = (Person)constructor1.newInstance(); System.out.println(object1); Person object = (Person)constructor.newInstance("小陈" ); System.out.println(object); } }
4.获取成员字段
功能
方法
获取本类所有字段 (所有权限)
getDeclaredFields
获取本类 + 父类所有 public 字段
getFields
获取指定字段名 (任意权限)
getDeclaredField(“字段名”)
获取指定 public 字段名
getField(“字段名”)
功能
方法
获取对象的字段值
get(“实例名”)
设置对象的字段值
set(“实例名”,值)
获取字段类型
getType
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 public class BeaseText { public static void main (String[] args) throws Exception { Class<?> aClass = Class.forName("com.Xc.Person" ); Constructor<?> constructor = aClass.getDeclaredConstructor(String.class); System.out.println("获取指定构造器:" + constructor); Object p1 = constructor.newInstance("小陈" ); System.out.println(p1); Field publicName = aClass.getField("publicName" ); publicName.set(p1,"小王" ); System.out.println(publicName.get(p1)); System.out.println(publicName.getType()); Field protectedAge = aClass.getDeclaredField("protectedAge" ); protectedAge.setAccessible(true ); protectedAge.set(p1,10 ); System.out.println(protectedAge.get(p1)); Field[] fields = aClass.getFields(); for (Field field : fields) { System.out.println(field); } System.out.println("================================" ); Field[] declaredFields = aClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } } }
5.获取成员方法
功能
方法
获取本类所有方法 (所有权限)
getDeclaredMethods
获取本类 + 父类所有 public 方法
getMethods()
获取指定方法名 + 参数类型 (任意权限)
getDeclaredMethod(“方法名”,Class…参数)
获取指定 public 方法名 + 参数类型
getMethod(“方法名”,Class…参数)
功能
方法
反射调用方法
invoke
获取返回值类型
getReturnType
获取方法参数类型
getParameterTypes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class BeaseText { public static void main (String[] args) throws Exception { Class<?> aClass = Class.forName("com.Xc.Person" ); Constructor<?> constructor = aClass.getDeclaredConstructor(String.class); System.out.println("获取指定构造器:" + constructor); Object p1 = constructor.newInstance("小陈" ); System.out.println(p1); Method method = aClass.getMethod("publicSay" ); method.invoke(p1); System.out.println(method.getReturnType()); Method privateShowInfo = aClass.getDeclaredMethod("privateShowInfo" ,String.class); privateShowInfo.setAccessible(true ); privateShowInfo.invoke(p1,"小陈" ); } }
6.反射爆破 反射爆破 (Reflection Blast),在 Java 里就是:利用反射 + setAccessible (true),强行突破 private/protected 封装, 访问 / 修改私有字段、调用私有方法、甚至调用私有构造器 。
功能
方法
开启暴力访问,绕过 private 检查
setAccessible(true)
1 2 3 4 field.setAccessible(true ); method.setAccessible(true ); constructor.setAccessible(true );
案例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class BeaseText { public static void main (String[] args) throws Exception { Class<?> aClass = Class.forName("com.Xc.Person" ); Constructor<?> constructor = aClass.getDeclaredConstructor(String.class); System.out.println("获取指定构造器:" + constructor); Object p1 = constructor.newInstance("小陈" ); System.out.println(p1); Field publicName = aClass.getField("publicName" ); publicName.set(p1,"小王" ); System.out.println(publicName.get(p1)); System.out.println(publicName.getType()); Method privateShowInfo = aClass.getDeclaredMethod("privateShowInfo" ,String.class); privateShowInfo.setAccessible(true ); privateShowInfo.invoke(p1,"小陈" ); } }
7.动态代理 动态代理 :不改动原目标类源码,在运行时自动生成代理类 ,对原方法做前后增强 (日志、事务、权限、拦截)。
1.两种分类 JDK 动态代理
要求:目标类必须实现接口
原理:基于接口生成代理类
只能代理接口里的方法
Cglib 动态代理
要求:目标类不用实现接口 ,普通类就行
原理:继承目标类生成子类 做代理
不能代理 final 类、final 方法
JDK动态代理 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 public interface UserService { void addUser () ; } public class UserServiceImpl implements UserService { @Override public void addUser () { System.out.println("执行:新增用户" ); } } public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler (Object target) { this .target = target; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("前置:权限校验/日志" ); Object result = method.invoke(target, args); System.out.println("后置:记录日志/提交事务" ); return result; } }
二十九、正则表达式 正则表达式(Regex/RegExp)是一套用符号描述文本匹配规则 的语法,用于匹配、提取、替换或校验字符串,几乎所有编程语言都原生支持。下面从核心语法、常用示例、贪婪 / 非贪婪、零宽断言、实战案例 五部分快速掌握。
1.语法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class One { public static void main (String[] args) { Pattern p = Pattern.compile("[a-zA-Z0-9]+" ); String phone = "13812345678" ; Matcher matcher = p.matcher(phone); while (matcher.find()){ System.out.println("找到:" + matcher.group(0 )); } } }
2.相关规则 (1)字符匹配
规则
含义
Java 写法
.
任意一个字符(除换行)
.
\d
数字 0-9
\\d
\D
非数字
\\D
\w
字母、数字、下划线
\\w
\W
非字母数字下划线
\\W
\s
空白(空格、制表、换行)
\\s
\S
非空白
\\S
[abc]
a、b、c 中任意一个
[abc]
[^abc]
不是 a、b、c
[^abc]
[a-z]
小写字母
[a-z]
[A-Z]
大写字母
[A-Z]
[a-zA-Z]
所有字母
[a-zA-Z]
[0-9]
数字
[0-9]
(2)量词\限定符
规则
含义
?
0 次或 1 次
*
0 次或多次
+
1 次或多次(至少 1 次)
{n}
恰好 n 次
{n,}
至少 n 次
{n,m}
n ~ m 次
(3)边界匹配
规则
含义
Java 写法
^
字符串开头
^
$
字符串结尾
$
\b
单词边界
\\b
\B
非单词边界
\\B
(4)选择匹配符
(5)分组与引用
符号
作用
(表达式)
捕获分组,可通过 group (1)、\1、$1 引用
(?:表达式)
非捕获分组,只分组不编号、不占用分组索引
\1 \2 ...
反向引用,引用第 1、2… 个捕获分组内容
(?i)
分组内忽略大小写
(?s)
单行模式,. 匹配换行
(?m)
多行模式,^ $ 匹配每行首尾
(6)贪婪匹配
规则
含义
.*
贪婪(尽可能多匹配)
.*?
非贪婪(尽可能少匹配)
(7)断言
写法
名称
作用
(?=xxx)
正向先行断言
后面必须是 xxx
(?!xxx)
负向先行断言
后面不能是 xxx
(?<=xxx)
正向后行断言
前面必须是 xxx
(?<!xxx)
负向后行断言
前面不能是 xxx
3.Pattern类 静态方法
方法
作用
static Pattern compile(String regex)
编译正则,返回 Pattern 对象
static Pattern compile(String regex, int flags)
编译正则 + 指定模式标志
static boolean matches(String regex, CharSequence input)
快速全串匹配,不用手动创建 Pattern/Matcher
static String[] split(CharSequence input, String regex)
用正则分割字符串
实例方法
方法
作用
Matcher matcher(CharSequence input)
创建匹配器(你常用的那种写法)
String pattern()
返回当前编译的正则字符串
int flags()
返回当前编译的模式标志
String[] split(CharSequence input)
用当前正则分割字符串
String[] split(CharSequence input, int limit)
分割,指定分割次数限制
匹配模式
常量
值
作用
Pattern.CASE_INSENSITIVE
2
忽略大小写匹配
Pattern.MULTILINE
8
多行模式:^ $ 匹配每行开头结尾
Pattern.DOTALL
16
单行模式:. 可以匹配换行符
Pattern.COMMENTS
4
允许正则里写注释,忽略空白
Pattern.UNIX_LINES
1
仅 \n 作为行结束符
4.Match类 作用 :负责匹配、查找、提取、分组、替换 ,由 Pattern 的 matcher() 方法创建。1 2 Pattern p = Pattern.compile("正则" );Matcher m = p.matcher(待匹配字符串);
相关方法
方法
作用
boolean matches()
整个字符串 完全匹配正则
boolean find()
向后查找下一个 匹配的子串
boolean lookingAt()
从开头 开始匹配,不用整串匹配
String group()
获取整体匹配 的内容
String group(int n)
获取第 n 个分组 内容(分组从 1 开始)
int groupCount()
获取一共有多少个分组
int start()
获取匹配内容的起始索引
int end()
获取匹配内容的结束索引
String replaceAll(String repl)
把所有匹配到的替换成新字符串
String replaceFirst(String repl)
只替换第一个 匹配
Matcher reset()
重置匹配器,回到开头
Matcher reset(CharSequence input)
重置并绑定新字符串
5.反向引用 反向引用 :用 () 括号分组捕获 后,在同一个正则里 ,用 \1 \2 \3 引用前面第 1、2、3 个分组 匹配到的内容。语法
写法
含义
(...)
捕获分组,编号从 1 开始
\1
引用第 1 个分组 匹配到的内容
\2
引用第 2 个分组 匹配到的内容
\3
引用第 3 个分组
1 2 3 4 5 6 7 8 9 10 11 public class Test { public static void main (String[] args) { String str = "11 22 34 55 67" ; Pattern p = Pattern.compile("(\\d)\\1" ); Matcher m = p.matcher(str); while (m.find()) { System.out.println("重复数字:" + m.group()); } }
三十、断言类(了解) 作用:开发调试用 ,校验条件是否为 true,不用于业务异常、不替代 if 判断。 1.原生断言 1 2 3 4 5 assert 布尔表达式;assert 布尔表达式 : 错误信息;
需要先开启虚拟机断言: 点击运行按钮编辑配置,点击修改选项,勾选下方,在输入 -ea即可
案例: 1 2 3 4 5 6 7 8 9 public class One { public static void main (String[] args) { int age = -5 ; assert age > 10 : "错误" ; System.out.println("程序正常执行" ); } }
2.JDK 官方断言工具类(生产可用,无需 -ea)
方法
作用
抛出异常
requireNonNull(T obj)
非空校验
NullPointerException
requireNonNull(T obj, String msg)
非空 + 自定义提示
NullPointerException
requireNonNull(T obj, Supplier msgSupplier)
懒加载提示
NullPointerException
isNull(Object obj)
判断是否为 null
返回 boolean
nonNull(Object obj)
判断是否非 null
返回 boolean
1 2 String str = null ;Objects.requireNonNull(str, "字符串不能为空" )
三十一、基础网络编程 1.基本概念 1.概念:两台设备之间通过网络实现数据传输 2.网络通信:将数据从一台设备传输到另一台设备 3.java.net包下面提供了一系列的类或接口,共程序员使用,完成网络通讯 4.网络根据不同范围分成 局域网、城域网、广域网 局域网:范围最小,仅仅一个教室或机房 城域网:可以覆盖一个城市 广域网:全国、全球等,万维网是广域网的代表!! 2. IP地址 IP 地址 :互联网 / 局域网中设备的唯一身份编号 ,用来定位、通信。分为两大类:
IPv4 :32 位,常用 192.168.1.1
IPv6 :128 位,解决地址枯竭,格式 2409:xxxx::1
(1)基本格式 格式:4 段十进制,用点分隔 A.B.C.D 每一段范围:0 ~ 255 例:192.168.0.1
本质:32 位二进制 ,每 8 位一段
1 段:8 位 → 0~255
整体 32 位 → 总约 42.9 亿个地址
IP
(2)IP 地址 5 大类地址 A 类
第一段:0~127
默认子网掩码:255.0.0.0
大型网络
B 类
第一段:128~191
掩码:255.255.0.0
中型企业网
C 类
第一段:192~223
掩码:255.255.255.0
家用 / 小型局域网最常用
D 类
E 类
(3)特殊IP 127.0.0.1 本地回环、本机测试0.0.0.0 任意地址、监听所有网卡255.255.255.255 全网广播网段最后一位 255 :本网段广播 网段最后一位 0 :代表整个网段 (4)公网 IP / 私网 IP 私网 IP(只能内网用,不能直接上网)
A 类:10.0.0.0 ~ 10.255.255.255
B 类:172.16.0.0 ~ 172.31.255.255
C 类:192.168.0.0 ~ 192.168.255.255
公网 IP 运营商分配,全球唯一,可直接互联网访问
(5)CIDR 斜杠表示法 写法:IP/位数例:192.168.1.0/24``/24 = 前 24 位是网络位 = 掩码 255.255.255.0
常用对应:
/24 → 255.255.255.0
/16 → 255.255.0.0
/8 → 255.0.0.0
3.域名 域名 :给 IP 地址 起的好记的名字 。
IP 难记:110.242.68.4域名好记:www.baidu.com
本质:域名 = IP 的别名 访问域名 → DNS 解析 → 找到 IP → 访问服务器
(1)域名结构 示例:www.baidu.com从右到左层级:
顶级域名 (最右边)
二级域名
三级域名(子域名)
拆分示例
com 顶级域名
qq 二级域名(主体域名,企业自己注册)
mail 三级 / 子域名
(2)顶级域名分类 1. 通用顶级域名
.com 商业公司(最常用)
.net 网络机构
.org 非营利组织
.gov 政府
.edu 教育院校
.info 信息类
2. 国家顶级域名
.cn 中国
.jp 日本
.us 美国
.hk 香港
(3)本地DNS “C:\Windows\System32\drivers\etc\hosts” 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # Copyright (c) 1993-2009 Microsoft Corp. # # This is a sample HOSTS file used by Microsoft TCP/IP for Windows. # # This file contains the mappings of IP addresses to host names. Each # entry should be kept on an individual line. The IP address should # be placed in the first column followed by the corresponding host name. # The IP address and the host name should be separated by at least one # space. # # Additionally, comments (such as these) may be inserted on individual # lines or following the machine name denoted by a '#' symbol. # # localhost name resolution is handled within DNS itself. # 127.0.0.1 localhost # ::1 localhost 192.168.200.129 www.itchen.com #当访问 www.itchen.com 优先匹配本地DNS # 192.168.200.129 www.itchenmall.com # 192.168.200.129 www.itchencrm.com
4.端口 端口(Port) :操作系统里的逻辑编号(0~65535) ,用来区分同一台电脑上的不同网络程序 / 服务 。(1)端口范围与分类 端口是16 位数字 ,范围 0 ~ 65535 ,共 65536 个。
1. 知名端口(0~1023)
系统 / 标准服务专用,固定分配
Linux 绑定需 root 权限
常用:
22:SSH(远程登录)
80:HTTP(网页)
443:HTTPS(加密网页)
21:FTP(文件传输)
53:DNS(域名解析)
2. 注册端口(1024~49151)
给自定义软件 / 数据库 / 中间件 用
自己部署服务首选区间
常用:
3306:MySQL
6379:Redis
8080:Web 备用端口
3389:Windows 远程桌面
3. 动态 / 临时端口(49152~65535)
客户端临时随机占用 ,用完释放
例如:浏览器访问网站时,本机随机用一个临时端口连接服务器 80 端口
(2)防火墙 防火墙默认拦截陌生端口
服务器部署必须放行端口 (如安全组、firewalld)
示例:云服务器需放行 80/443/3306 才能对外提供服务
5.网络通信协议 网络通信协议 :设备之间上网、传数据必须遵守的规则、格式、约定 。没有协议,电脑互相能连上,但听不懂对方发的内容 。一句话:协议就是网络的 “通用语言” 。 (1)网络分层模型 OSI 七层 / TCP/IP 五层(实用记五层)
应用层 浏览器、APP、所有业务协议
传输层 TCP、UDP(端口在这里)
网络层 IP 地址、路由
数据链路层 网卡、MAC 地址、交换机
物理层 网线、WiFi、信号电流
(2)核心协议分配
协议
端口
作用
HTTP
80
普通网页、接口请求
HTTPS
443
加密安全网页、接口
FTP
21
文件上传下载
SFTP
22
安全文件传输
SSH
22
远程登录服务器
DNS
53
域名转 IP
SMTP
25
发邮件
MySQL
3306
数据库连接
Redis
6379
缓存通信
(3)两大协议 TCP(可靠)
面向连接,先握手再通信
不丢包、不乱序、可靠传输
适用:网页、文件、数据库、远程连接
特点:三次握手、四次挥手
UDP(快速)
无连接,不用握手,直接发
速度快、开销小、可能丢包
适用:游戏、直播、视频通话、DNS
特点:快、不保证可靠
网络层协议
IP :给设备分配地址,负责路由转发
ICMP :ping 命令用的协议,测试网络通不通
数据链路层
MAC 地址 :网卡物理唯一地址
ARP:把 IP 解析成 MAC 地址
6. InetAddress类 静态方法
方法
作用
异常
InetAddress.getByName(String host)
根据域名 / IP / 主机名 获取对象
UnknownHostException
InetAddress.getLocalHost()
获取本机 地址
UnknownHostException
InetAddress.getByAddress(byte[] addr)
根据字节数组 IP 获取对象
UnknownHostException
InetAddress.getByAddress(String host, byte[] addr)
主机名 + IP 字节数组创建对象
UnknownHostException
InetAddress.getAllByName(String host)
获取一个域名对应的所有 IP (数组)
UnknownHostException
InetAddress.getLoopbackAddress()
获取回环地址 (127.0.0.1 或 ::1)
无
实例方法
方法
返回值
作用
getHostName()
String
获取主机名 / 域名
getCanonicalHostName()
String
获取规范主机名 (最完整域名)
getHostAddress()
String
获取IP 地址字符串 (最常用)
getAddress()
byte[]
获取IP 地址的字节数组
方法
返回
作用
isLoopbackAddress()
boolean
是否回环地址 (127.x.x.x)
isSiteLocalAddress()
boolean
是否私网 IP (内网 IP)
isAnyLocalAddress()
boolean
是否 0.0.0.0 任意地址
isLinkLocalAddress()
boolean
是否链路本地地址 (169.254.x.x)
isMulticastAddress()
boolean
是否组播地址 (D 类)
isReachable(int timeout)
boolean
能否 ping 通 (测试可达性)
1 2 3 4 5 InetAddress ip = InetAddress.getByName("www.baidu.com" );System.out.println(ip.getHostName()); System.out.println(ip.getHostAddress()); System.out.println(ip.isSiteLocalAddress());
7. Socket(套接字) 1.Socket开发网络应用程序被广泛采用。 2.通讯的两端都要有Socket,是两台机器间通讯的端点 3.网络通讯其实是Socket间的通信 4.Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO流传输 5.一般主动发起通讯的应用程序属于客户端,等待通讯请求的为服务端 (1)TCP编程 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 public class Server { public static void main (String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket (10002 ); System.out.println("等待客户端连接...." ); Socket accept = serverSocket.accept(); InputStream inputStream = accept.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader (inputStream); int b; while ((b = inputStreamReader.read()) != -1 ){ System.out.print((char )b); } } } public class Client { public static void main (String[] args) throws Exception { Socket socket = new Socket ("127.0.0.1" ,10002 ); OutputStream iS = socket.getOutputStream(); iS.write("你好,TCP" .getBytes(StandardCharsets.UTF_8)); socket.close(); iS.close(); } }
相关方法 ServerSocket(服务端)
方法
作用
ServerSocket(int port)
绑定指定端口,创建服务端
accept()
阻塞等待 客户端连接,返回 Socket
close()
关闭服务端
getLocalPort()
获取监听的端口
isClosed()
判断是否已关闭
Socket(客户端)
方法
作用
Socket(String host, int port)
连接指定服务端 IP + 端口
getInputStream()
获取输入流 ,读对方发的数据
getOutputStream()
获取输出流 ,给对方发数据
close()
关闭套接字,断开连接
getInetAddress()
获取对方 IP 地址
getPort()
获取对方端口
getLocalPort()
获取本地端口
setSoTimeout(int timeout)
设置读取超时时间 (毫秒)
isClosed()
判断是否断开连接
isConnected()
判断是否已连接
(2)UDP编程 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 public class SendMessageDemo { public static void main (String[] args) throws Exception { DatagramSocket datagramSocket = new DatagramSocket (6667 ); String str = "你好啊" ; byte [] bytes = str.getBytes(StandardCharsets.UTF_8); InetAddress byName = InetAddress.getByName("127.0.0.1" ); int port = 6666 ; DatagramPacket datagramPacket = new DatagramPacket (bytes,bytes.length,byName,port); datagramSocket.send(datagramPacket); datagramSocket.close(); } } public class ReceiveMessageDemo { public static void main (String[] args) throws Exception { DatagramSocket datagramSocket = new DatagramSocket (6666 ); byte [] bytes = new byte [1024 ]; DatagramPacket datagramPacket = new DatagramPacket (bytes,bytes.length); System.out.println("等待数据接收..." ); datagramSocket.receive(datagramPacket); System.out.println("接收成功!!!!1" ); byte [] data = datagramPacket.getData(); int length = datagramPacket.getLength(); InetAddress address = datagramPacket.getAddress(); int port = datagramPacket.getPort(); System.out.println(new String (data)); System.out.println(length); System.out.println(address); System.out.println(port); datagramSocket.close(); } }
相关方法
方法
作用
send(DatagramPacket p)
发送数据包
receive(DatagramPacket p)
阻塞接收 数据包
close()
关闭 UDP 套接字
getLocalPort()
获取本地绑定端口
setSoTimeout (int 毫秒)
设置接收超时
8.更多内容 三十二、JDBC数据库连接 JDBC为访问不同的数据库提供了统一的接口,Java程序员可以使用JDBC来对数据库的各种操作 JDBC API是一系列的接口,相关类和接口在java.sql和javx.sql包里面!!! 1.连接数据库 首先要下载mysql-connector-j-9.2.0.jar驱动,并配置好!!! 数据库代码: 1 2 3 4 5 6 7 8 9 10 CREATE TABLE actor ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR (50 ), sex VARCHAR (10 ), phone VARCHAR (20 ) );
连接数据库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class connect { public static void main (String[] args) { Class.forName("com.mysql.cj.jdbc.Driver" ); String url = "jdbc:mysql://localhost:3306/db01" ; String user = "用户名" ; String password = "密码" ; Connection connection = DriverManager.getConnection(url, user, password); System.out.println(connection); } }
2. DriverManager类 作用:驱动管理类,注册驱动、获取数据库连接 静态方法
方法签名
返回值
核心作用
getConnection(String url)
Connection
仅通过数据库 URL 获取连接
getConnection(String url, String user, String password)
Connection
通过 URL、用户名、密码获取连接最常用
getConnection(String url, Properties info)
Connection
通过 URL + Properties 配置(存账号密码)获取连接
registerDriver(Driver driver)
void
手动注册数据库驱动
deregisterDriver(Driver driver)
void
注销指定数据库驱动
getDriver(String url)
Driver
根据连接 URL 获取匹配的驱动实例
Enumeration<Driver> getDrivers()
Enumeration
获取当前已加载的所有数据库驱动
setLoginTimeout(int seconds)
void
设置数据库登录连接超时时间(秒)
getLoginTimeout()
int
获取当前设置的登录超时时间
setLogWriter(PrintWriter out)
void
设置 JDBC 日志输出流
getLogWriter()
PrintWriter
获取 JDBC 日志输出流
println(String message)
void
向 JDBC 全局日志打印信息
3. Connection接口 代表 Java 程序 和 数据库之间的桥梁 由 DriverManager.getConnection() 获取实例。
常用方法
返回值
作用
prepareStatement(String sql)
PreparedStatement
创建预编译对象,日常最常用
createStatement()
Statement
创建普通语句对象
setAutoCommit(boolean b)
void
设置是否自动提交事务
commit()
void
手动提交事务
rollback()
void
事务回滚
close()
void
关闭数据库连接
isClosed()
boolean
判断连接是否已关闭
isValid(int timeout)
boolean
检测连接是否有效
getMetaData()
DatabaseMetaData
获取数据库元数据(版本、表结构等)
setTransactionIsolation(int level)
void
设置事务隔离级别
4. Statement类(了解) JDBC 执行 SQL 的对象 Statement stmt = conn.createStatement();创建
方法
返回值
作用
executeUpdate(String sql)
int
执行增删改 ,返回受影响行数
executeQuery(String sql)
ResultSet
执行查询 ,返回结果集
execute(String sql)
boolean
通用执行,可执行任意 SQL
close()
void
关闭 Statement 资源
getUpdateCount()
int
获取最后一次增删改影响行数
getResultSet()
ResultSet
获取最后一次查询结果集
增删改查操作 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 public class homeWorko1 { public static void main (String[] args) throws Exception { Class.forName("com.mysql.cj.jdbc.Driver" ); String url = "jdbc:mysql://localhost:3306/cc_01" ; String name = "itchen" ; String password = "1234" ; Connection connection = DriverManager.getConnection(url, name, password); Statement statement = connection.createStatement(); String sql = "insert into actor values(null,'小陈','男','112223')" ; int i = statement.executeUpdate(sql); System.out.println(i > 0 ? "成功" :"失败" ); String sqlUpdate = "update actor set name='小丽',sex='女',phone='112224' where id = 2" ; boolean execute = statement.execute(sqlUpdate); System.out.println(execute); String sqlDelete = "delete from actor where id = 4" ; boolean execute2 = statement.execute(sqlDelete); System.out.println(execute2); String sqlSelect = "select * from actor" ; ResultSet resultSet = statement.executeQuery(sqlSelect); while (resultSet.next()){ int id = resultSet.getInt(1 ); String name1 = resultSet.getString(2 ); String sex = resultSet.getString(3 ); String string = resultSet.getString(4 ); System.out.println(id + "\t" + name1 + "\t" + sex + "\t" + string); } statement.close(); connection.close(); } }
5. sql注入问题 用户输入恶意内容,拼接进 SQL 语句,篡改原本逻辑,非法操作数据库 。根源:Statement 字符串拼接 SQL ,把用户输入直接当成 SQL 代码执行了。 经典案例: 1 2 3 4 select * from actor where name = '1' or ' and sex = ' or '1' = '1'
6. PreparedStatement(预处理) 不在使用+ 拼接sql语句,减少语法错误;解决注入问题; 减少编译次数,效率较高
方法
适用场景
返回值
executeUpdate()
增、删、改
int 受影响行数
executeQuery()
查询 select
ResultSet 结果集
execute()
通用任意 SQL
boolean 是否为查询
setInt (下标,值)
给占位符设整数
setString (下标,值)
给占位符设字符串
setDouble (下标,值)
给占位符设小数
setBoolean (下标,值)
给占位符设布尔值
setDate (下标,日期)
给占位符设日期
增删改查 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 public class CURL { public static void main (String[] args) throws Exception { Class<?> jdbc = Class.forName("com.mysql.cj.jdbc.Driver" ); String username = "itchen" ; String password = "1234" ; String url = "jdbc:mysql://localhost:3306/cc_01" ; Connection connection = DriverManager.getConnection(url, username, password); Scanner scanner = new Scanner (System.in); System.out.print("输入数字(1/增 2/改 3/删 4/查):" ); int i = scanner.nextInt(); switch (i){ case 1 -> System.out.println(add(connection)); case 2 -> System.out.println(update(connection)); case 3 -> System.out.println(delete(connection)); case 4 -> select(connection); } connection.close(); } public static boolean add (Connection connection) throws Exception { String name = "小美" ; String sex = "女" ; String tel = "111227" ; String sql = "insert into actor values (?,?,?,?)" ; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1 ,null ); preparedStatement.setString(2 ,name); preparedStatement.setString(3 ,sex); preparedStatement.setString(4 ,tel); return preparedStatement.execute(); } public static boolean update (Connection connection) throws Exception { String name = "小记" ; String sex = "男" ; String tel = "111228" ; String sql = "update actor set name=?,sex=?,phone=? where id = 6" ; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1 ,name); preparedStatement.setString(2 ,sex); preparedStatement.setString(3 ,tel); return preparedStatement.execute(); } public static boolean delete (Connection connection) throws Exception { int id = 6 ; String sql = "delete from actor where id = ?" ; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1 ,id); return preparedStatement.execute(); } public static void select (Connection connection) throws Exception { String sql = "select * from actor" ; PreparedStatement preparedStatement = connection.prepareStatement(sql); ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()){ int id = resultSet.getInt(1 ); String name = resultSet.getString(2 ); String sex = resultSet.getString(3 ); String tel = resultSet.getString(4 ); System.out.println(id + "\t" + name + "\t" + sex + "\t" + tel); } } }
7.事务 事务是一种操作的集合,它是一个不可分割的工作单位,事务会将所有的操作作为一个整体一起向系统提交或 撤销操作请求,即这些操作要么同时成功,要么同时失败 Connection相关方法
setAutoCommit(boolean b)
void
设置是否自动提交事务
commit()
void
手动提交事务
rollback()
void
事务回滚
rollback(保存点)
void
回滚到保存点
setSavepoint()
void
设置保存点
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 public class CURL { public static void main (String[] args) throws Exception { Class<?> jdbc = Class.forName("com.mysql.cj.jdbc.Driver" ); String username = "itchen" ; String password = "1234" ; String url = "jdbc:mysql://localhost:3306/cc_01" ; Connection connection = DriverManager.getConnection(url, username, password); connection.setAutoCommit(false ); try { String sql = "select * from actor" ; int i = 1 / 0 ; System.out.println("执行成功" ); connection.commit(); }catch (Exception e){ System.out.println("发生错误回滚" ); connection.rollback(); }finally { connection.close(); } } }
8.批处理 当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理,通常情况下比单独提交处理更有效率。 PerparedStatement相关方法
方法
作用
addBatch()
把当前参数加入批处理队列
executeBatch()
一次性执行所有批处理
clearBatch()
清空批处理队列
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 public class Batch { @Test public void batch () throws Exception{ Class.forName("com.mysql.cj.jdbc.Driver" ); String url = "jdbc:mysql://localhost:3306/cc_01?rewriterBatchedStatements=true" ; String name = "itchen" ; String password = "1234" ; Connection connection = DriverManager.getConnection(url, name, password); String sql = "insert into admin2 values(null,?,?)" ; PreparedStatement preparedStatement = connection.prepareStatement(sql); long start = System.currentTimeMillis(); for (int i = 0 ; i < 5000 ; i++){ preparedStatement.setString(1 ,"java" + i); preparedStatement.setString(2 ,"666" ); preparedStatement.addBatch(); if ((i + 1 ) % 1000 == 0 ){ preparedStatement.executeBatch(); preparedStatement.clearBatch(); } } long end = System.currentTimeMillis(); System.out.println("总时长:" +(end-start)+"ms" ); JDBCUtils.close(null ,preparedStatement,connection); } }
9.JDBC自制工具类 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 public class JDBCUtils { private static String user; private static String password; private static String url; private static String driver; static { Properties properties = new Properties (); try { properties.load(new FileInputStream ("src/mysql.properties" )); user = properties.getProperty("user" ); password = properties.getProperty("password" ); url = properties.getProperty("url" ); driver = properties.getProperty("driver" ); } catch (IOException e) { throw new RuntimeException (e); } } public static Connection getConnection () { try { return DriverManager.getConnection(url,user,password); } catch (SQLException e) { throw new RuntimeException (e); } } public static void close (ResultSet rs, Statement st, Connection c) { if (rs != null ){ try { rs.close(); } catch (SQLException e) { throw new RuntimeException (e); } } if (st != null ){ try { st.close(); } catch (SQLException e) { throw new RuntimeException (e); } } if (c != null ){ try { c.close(); } catch (SQLException e) { throw new RuntimeException (e); } } } }
10. URL后置参数 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 jdbc:mysql://localhost:3306/数据库名?useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&characterEncoding=utf-8 1. useSSL=false 作用:关闭 SSL 安全加密连接 本地开发没必要开启,设为 false 不写高版本 MySQL 会告警、甚至连不上 2. serverTimezone=UTC 最关键,MySQL8 必加 作用:指定数据库时区 不加直接报错:时区异常、时间匹配错误 常用:UTC 或 Asia/Shanghai 3. rewriteBatchedStatements=true 批处理必加 作用:开启 MySQL 真正批处理优化 不加:addBatch() 只是假批量,底层还是逐条执行,没提速 做 JDBC 批量插入 / 更新必须带这个 4. characterEncoding=utf-8 作用:指定连接编码为 utf-8 防止中文乱码、插入中文问号、乱码 5. zeroDateTimeBehavior=convertToNull 作用:处理数据库 0000-00-00 非法日期 自动转成 null,不抛异常 6. allowPublicKeyRetrieval=true 作用:解决本地连接报错 public key retrieval is not allowed 本地开发偶尔需要加
11.数据库连接池 原生 JDBC 问题 每次操作数据库:新建连接 → 用完关闭连接
创建连接耗时非常大
频繁创建销毁,性能低
连接资源无法复用,容易耗尽
连接池原理 提前初始化一批连接,放到池子中
1.优点 减少创建连接开销,速度快 连接复用,资源可控 可以设置最大连接数,防止数据库被压垮 统一管理、超时回收、自动补连接 2.常见连接池 HikariCP :SpringBoot 默认,性能最强Druid :阿里德鲁伊,带监控、防 SQL 注入,企业最常用C3P0、DBCP:老式,现在基本不用 3.Druid连接池 引入maven或者下载jar包druid-1.2.16.jar 1 2 3 4 5 <dependency > <groupId > com.alibaba</groupId > <artifactId > druid</artifactId > <version > 1.2.16</version > </dependency >
druid.properties文件 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 driverClassName =com.mysql.cj.jdbc.Driver url =jdbc:mysql://localhost:3306/cc_01?rewriteBatchedStatements=true username =itchen password =1234 initialSize =10 minIdle =5 maxActive =50 maxWait =5000
连接池 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 public class JDBCUtilsByDruid { private static DataSource ds; static { Properties properties = new Properties (); try { properties.load(new FileInputStream ("src/druid.properties" )); ds = DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { throw new RuntimeException (e); } } public static Connection getConnection () throws SQLException { return ds.getConnection(); } public static void close (ResultSet rs, Statement st, Connection conn) { if (rs != null ){ try { rs.close(); } catch (SQLException e) { throw new RuntimeException (e); } } if (st != null ){ try { st.close(); } catch (SQLException e) { throw new RuntimeException (e); } } if (conn != null ){ try { conn.close(); } catch (SQLException e) { throw new RuntimeException (e); } } } }
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 import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;public class TestDruid { public static void main (String[] args) { Connection conn = null ; PreparedStatement pstmt = null ; ResultSet rs = null ; try { conn = DruidJdbcUtil.getConnection(); String sql = "select * from actor where id=?" ; pstmt = conn.prepareStatement(sql); pstmt.setInt(1 , 2 ); rs = pstmt.executeQuery(); while (rs.next()) { System.out.println(rs.getString("name" )); } } catch (Exception e) { e.printStackTrace(); } finally { DruidJdbcUtil.close(conn, pstmt, rs); } } }