万物都是相同的,只要你把一个能力掌握好了,你会发现其他的东西都是万变不离其宗。
面向对象基础
模块
一、模块的核心概念
-
解决依赖问题
- Java 9 前:
jar
包仅作为 class 文件的容器,不管理依赖,需手动通过-cp
指定依赖,易引发ClassNotFoundException
。 - Java 9 后:模块是自带依赖关系的 class 容器 ,通过
module-info.class
声明依赖,确保编译和运行时自动定位依赖模块。
- Java 9 前:
-
JDK 标准库模块化
- 原
rt.jar
被拆分为数十个.jmod
模块(如java.base.jmod
),位于$JAVA_HOME/jmods
,所有模块直接或间接依赖根模块java.base
。 - 模块支持多版本和 JNI 二进制扩展,比 jar 包功能更强大。
- 原
二、编写模块
-
模块描述文件
module-info.java
- 声明模块名(如
module hello.world
)和依赖(requires java.xml
),默认依赖java.base
可省略。 - 可通过
exports 包名
导出包,供其他模块访问(模块内权限控制增强,未导出的包对外不可见)。
- 声明模块名(如
-
编译与打包
- 编译:
javac -d bin src/module-info.java src/...
,生成module-info.class
。 - 打包为可运行 jar:
jar --create --file hello.jar --main-class 主类 -C bin .
。 - 转为模块文件(.jmod):
jmod create --class-path hello.jar hello.jmod
(主要用于打包 JRE)。
- 编译:
三、运行模块与打包 JRE
-
运行模块
-
使用
--module-path
指定模块路径,--module
指定模块名:bash
arduinojava --module-path hello.jar --module hello.world
-
.jmod
文件不能直接运行,需通过jlink
工具处理。
-
-
精简 JRE 打包(jlink)
-
按需提取所需模块(包括自定义模块),生成轻量 JRE,减少分发体积:
bash
cssjlink --module-path hello.jmod --add-modules java.base,java.xml,hello.world --output jre/
-
分发时只需包含该
jre
目录,无需完整 JDK。
-
四、模块的访问权限
- 模块内权限:继承 Java 原有的 public/protected/private/ 包访问权限,但仅在模块内有效。
- 模块间访问 :需通过
exports 包名
显式导出包,否则其他模块无法访问该包内的类(如java.xml
模块导出java.xml
包后,外部才能使用其中的类)。
五、核心优势与小结
- 依赖管理:模块显式声明依赖,避免手动配置 classpath 的繁琐和错误。
- JRE 瘦身 :通过
jlink
按需打包,大幅减小运行时环境体积,方便部署。 - 代码隔离:导出机制增强了模块间的封装性,提升系统安全性和可维护性。
java核心类
字符串和编码
一、String 基础特性与不可变性
-
本质与创建
String
是引用类型,底层通过char[]
(早期 JDK)或优化的byte[]
(新版本,存储 ASCII 字符时节省空间)存储,支持字面量"..."
和构造函数new String(char[])
创建。- 不可变性 :内部字段
private final
修饰,所有修改操作(如toUpperCase()
)均返回新字符串,原字符串不变。
二、字符串比较规则
-
内容 vs 引用
equals()
:比较字符串内容是否相同(需忽略大小写时用equalsIgnoreCase()
)。==
:仅比较引用是否指向同一对象(常量池优化可能导致==
为true
,但属特例,不可依赖)。- 示例 :
new String("a") == "a"
为false
,因前者在堆中,后者在常量池。
三、常用操作方法详解
-
子串与搜索
- 包含:
contains(CharSequence)
;索引:indexOf()
/lastIndexOf()
;首尾匹配:startsWith()
/endsWith()
。 - 提取:
substring(start, end)
(左闭右开,索引从 0 开始)。
- 包含:
-
空白处理
trim()
:移除首尾空格、\t、\r、\n
;strip()
:额外处理全角空格\u3000
;isEmpty()
(长度为 0)与isBlank()
(全空白)。
-
替换与分割
- 普通替换:
replace(char/CharSequence)
;正则替换:replaceAll(String regex, String replacement)
(如replaceAll("[\,\;\s]+", ",")
)。 - 分割:
split(String regex)
(传入正则,如split("\,")
按逗号分割,注意正则元字符需转义,如.
需写为\.
)。
- 普通替换:
-
拼接与格式化
- 拼接:
String.join(separator, array)
(高效,避免+
操作的性能损耗)。 - 格式化:
formatted()
或String.format()
,占位符%s
(字符串)、%d
(整数)、%.2f
(两位小数浮点数)等。
- 拼接:
-
类型转换
- 转字符串:
String.valueOf()
(自动适配类型);转基本类型:Integer.parseInt()
/Boolean.parseBoolean()
(注意getInteger()
获取系统变量)。
- 转字符串:
四、字符编码原理与 Java 实现
-
编码基础
- ASCII:1 字节(0-127),仅英文字符。
- Unicode :统一编码(2 字节或更多),解决多语言冲突(如中文
'中'
的 Unicode 为0x4E2D
)。 - UTF-8:变长编码(1-4 字节),英文兼容 ASCII(1 字节),中文 3 字节,传输容错性强(推荐使用)。
-
Java 编码转换
String
/char
内存中为 Unicode,转字节数组:getBytes("UTF-8")
(避免默认编码,推荐用StandardCharsets.UTF_8
)。- 字节数组转字符串:
new String(byte[], charset)
(指定编码如GBK
/UTF-8
,确保一致性)。
五、最佳实践与注意事项
-
不可变性设计
- 构造方法中避免直接引用外部可变数组,需复制(如
this.scores = Arrays.copyOf(scores, scores.length)
),防止外部修改影响内部状态。
- 构造方法中避免直接引用外部可变数组,需复制(如
-
性能优化
- 频繁拼接用
StringBuilder
/StringJoiner
,减少临时对象创建;split()
和replaceAll()
谨慎使用正则,避免不必要的转义。
- 频繁拼接用
-
编码规范
- 始终明确指定编码(如 UTF-8),确保跨平台兼容性;处理用户输入时,注意编码转换可能导致的乱码问题。
六、核心总结
- 不可变性:String 操作返回新对象,安全且线程友好,但需注意性能开销。
- 比较规则 :内容比较用
equals()
,引用比较用==
,常量池优化是特例而非通用规则。 - 编码转换 :内存中为 Unicode,通过
getBytes()
和构造函数与字节数组交互,UTF-8 是首选编码。 - 工具方法 :熟练掌握
trim()
、substring()
、format()
等,结合正则提升灵活性,同时避免常见陷阱(如错误转义)。
一、StringBuilder 核心作用
-
高效字符串拼接
- 解决
String
不可变导致的性能问题:String
拼接时每次生成新对象,循环中大量创建临时对象浪费内存、影响 GC 效率。 StringBuilder
是可变对象,可预分配缓冲区,通过append()
等方法直接修改内部字符数组,避免临时对象创建。
- 解决
-
适用场景:循环内高频字符串拼接(如日志生成、SQL 语句构造等)。
二、核心特性与用法
-
链式操作
- 方法(如
append()
、insert()
)返回this
,支持连续调用,代码更简洁。 - 示例:
java
gonew StringBuilder() .append("Hello, ") .append("Bob") .insert(0, "Mr "); // 结果:Mr Hello, Bob
- 方法(如
-
源码原理 :通过返回当前实例(
return this
)实现链式调用,用户可模仿设计自定义链式操作类(如计数器Adder
)。
三、与 StringBuffer 的对比
特性 | StringBuilder | StringBuffer |
---|---|---|
线程安全 | 非线程安全(无同步) | 线程安全(方法加synchronized ) |
性能 | 更高(无同步开销) | 较低(同步导致性能损耗) |
推荐场景 | 单线程或非并发场景 | 早期多线程场景(现完全被StringBuilder 替代,无需使用) |
四、实践与注意事项
-
编译器优化 :普通
String
拼接(非循环中)会被编译器优化为StringConcatFactory
操作,无需手动改写为StringBuilder
。 -
练习示例 :构造
INSERT
语句时,通过循环拼接字段和占位符?
,避免硬编码,提高通用性。- 正确实现思路:
java
scssstatic String buildInsertSql(String table, String[] fields) { StringBuilder sb = new StringBuilder(); sb.append("INSERT INTO ").append(table).append(" ("); for (int i = 0; i < fields.length; i++) { sb.append(fields[i]); if (i < fields.length - 1) sb.append(", "); // 非最后一个字段添加逗号 } sb.append(") VALUES ("); for (int i = 0; i < fields.length; i++) { sb.append("?"); if (i < fields.length - 1) sb.append(", "); // 生成占位符 } sb.append(")"); return sb.toString(); }
练习
java
public class Main {
public static void main(String[] args) {
String[] fields = { "name", "position", "salary" };
String table = "employee";
String insert = buildInsertSql(table, fields);
System.out.println(insert);
String s = "INSERT INTO employee (name, position, salary) VALUES (?, ?, ?)";
System.out.println(s.equals(insert) ? "测试成功" : "测试失败");
}
static String buildInsertSql(String table, String[] fields) {
StringBuilder sb = new StringBuilder(1024);
sb.append("INSERT INTO ")
.append(table);
sb.append(" (");
for (int i = 0; i < fields.length; i++) {
sb.append(fields[i]+ (i < fields.length - 1 ? ", " : ")"));
}
sb.append(" VALUES (");
for (int i = 0; i < fields.length; i++) {
sb.append("?"+ (i < fields.length - 1 ? ", " : ")"));
}
return sb.toString();
}
}
StringJoiner
的教程,主要介绍StringJoiner
的用法、与相关方法的对比及练习,具体内容如下:
-
核心功能:用于高效拼接带分隔符的字符串,可附加固定的开头和结尾字符串,简化字符串拼接逻辑,避免手动处理分隔符和首尾字符。
-
基本用法
- 构造函数 :
StringJoiner(分隔符)
:创建仅包含分隔符的 Joiner,如new StringJoiner(", ")
。StringJoiner(分隔符, 开头, 结尾)
:创建包含分隔符、开头和结尾的 Joiner,如new StringJoiner(", ", "Hello ", "!")
。 - 核心方法 :
add(String element)
:向 Joiner 中添加元素,自动用分隔符连接。toString()
:返回最终拼接的字符串。
- 构造函数 :
-
与
String.join()
对比String.join(分隔符, 数组)
:静态方法,内部使用StringJoiner
,适用于简单的分隔符拼接(无需开头 / 结尾),代码更简洁。StringJoiner
:支持自定义开头和结尾,灵活性更高,适合复杂拼接场景(如 SQL 语句构造)。
-
示例代码
- 基础拼接 :通过
StringJoiner
循环添加元素,自动处理分隔符。 - 带首尾字符串:在构造函数中指定开头(如 "SELECT")和结尾(如 "FROM table"),直接生成完整语句。
- 基础拼接 :通过
包装类型
转换为包装类型的目的是说,可以调用包装类型的静态方法。
Java 包装类型详解
一、基本概念
-
数据类型分类
- 基本类型 (8 种):
byte
、short
、int
、long
、boolean
、float
、double
、char
,不能赋值为null
。 - 引用类型 :所有
class
和interface
,可赋值为null
。
- 基本类型 (8 种):
-
包装类型定义
- 为基本类型提供对应的引用类型(
java.lang
包下),如Integer
对应int
,Boolean
对应boolean
等,便于将基本类型视为对象操作。
- 为基本类型提供对应的引用类型(
二、自动装箱与拆箱(JDK 1.5+)
-
核心机制
- 自动装箱 :编译期自动将基本类型转为包装类型(如
Integer n = 100;
等价于Integer.valueOf(100)
)。 - 自动拆箱 :编译期自动将包装类型转为基本类型(如
int x = n;
等价于n.intValue()
)。
- 自动装箱 :编译期自动将基本类型转为包装类型(如
-
注意事项
- 效率影响 :装箱拆箱发生在编译期,但运行时仍需执行对应方法(如
valueOf()
、intValue()
),频繁操作会影响性能。 - 空指针风险 :拆箱时若包装类型为
null
,会抛出NullPointerException
(如Integer n = null; int x = n;
)。
- 效率影响 :装箱拆箱发生在编译期,但运行时仍需执行对应方法(如
三、不变类特性
-
不可变性
- 所有包装类型均为不变类 (如
Integer
的value
字段为final
),实例创建后值不可修改。
- 所有包装类型均为不变类 (如
-
对象比较
- 禁止使用
==
:包装类型是引用类型,==
比较引用地址而非值。 - 必须使用
equals()
:即使值相同,不同实例的==
可能为true
(如小整数缓存优化),但需统一用equals()
保证语义正确。 - 缓存优化 :
Integer.valueOf()
对-128~127
的整数返回缓存实例,超出范围则创建新实例,但代码逻辑不应依赖此优化。
- 禁止使用
四、常用方法与功能
-
创建实例
- 推荐静态工厂方法 :
Integer.valueOf(int)
或Integer.valueOf(String)
,而非new Integer()
(后者在 Java 9 + 被弃用,且无法利用缓存)。
- 推荐静态工厂方法 :
-
进制转换
- 解析字符串 :
Integer.parseInt("100")
(十进制)、Integer.parseInt("100", 16)
(十六进制)。 - 格式化为字符串 :
Integer.toString(n, 36)
(36 进制)、toHexString
(十六进制)、toBinaryString
(二进制)等。
- 解析字符串 :
-
静态变量与工具方法
- 极值:
Integer.MAX_VALUE
、Integer.MIN_VALUE
。 - 类型信息:
Long.SIZE
(位数)、Long.BYTES
(字节数)。 - 无符号转换:
Byte.toUnsignedInt(-1)
将byte
的-1
转为无符号255
(适用于byte
/short
/int
转更高位无符号类型)。
- 极值:
-
继承体系
- 整数和浮点数包装类型继承自
Number
,可转换为多种基本类型(如Number num = new Integer(999); int n = num.intValue();
)。
- 整数和浮点数包装类型继承自
五、最佳实践
- 对象创建 :优先使用静态工厂方法(如
valueOf()
),而非new
操作符,以便库实现优化(如缓存)。 - 对象比较 :始终用
equals()
比较包装类型值,避免依赖==
的缓存优化特性。 - 数据处理:利用包装类提供的工具方法(进制转换、无符号运算等),分离数据存储与显示逻辑。
javaBean
可以理解为只是一种协议规定。
一、JavaBean 定义与规范
-
基本定义
-
符合特定命名规范的 Java 类,通常包含:
private
修饰的实例字段public
修饰的字段读写方法(Getter/Setter)
-
示例:
typescriptpublic class Person { private String name; private int age; // Getter 和 Setter 方法 public String getName() { return name; } public void setName(String name) { this.name = name; } }
-
-
命名规范
-
普通字段:
- 读方法(Getter):
getXyz()
(首字母大写,前缀get
) - 写方法(Setter):
setXyz(Type value)
(前缀set
)
- 读方法(Getter):
-
布尔字段:
- 读方法通常为
isXyz()
(如isChild()
)
- 读方法通常为
-
属性类型:
- 读写属性:同时有 Getter 和 Setter
- 只读属性 :仅有 Getter(如
getAge()
) - 只写属性:仅有 Setter(不常见)
-
特殊说明 :属性可通过方法逻辑计算(不一定对应实际字段),例如
isChild()
可根据age
计算返回值。
-
二、JavaBean 的作用
-
核心用途
- 数据封装与传输:将相关数据组合为一个对象,便于在组件间传递(如 Web 开发中的参数传递)。
- IDE 工具支持:通过 IDE(如 Eclipse、IntelliJ IDEA)自动生成 Getter/Setter,提升开发效率。
-
工具使用示例
- 在 Eclipse 中,右键点击类文件,通过
Source -> Generate Getters and Setters
快速生成方法。
- 在 Eclipse 中,右键点击类文件,通过
三、枚举 JavaBean 属性(反射 API)
通过 Java 核心库的 Introspector
类可动态获取 JavaBean 的属性信息:
-
关键类与方法
BeanInfo info = Introspector.getBeanInfo(Class<?> clazz)
:获取类的元信息。PropertyDescriptor
:封装属性名称、Getter 和 Setter 方法。
-
示例代码
javaimport java.beans.*; public class Main { public static void main(String[] args) throws Exception { BeanInfo info = Introspector.getBeanInfo(Person.class); for (PropertyDescriptor pd : info.getPropertyDescriptors()) { System.out.println("属性名: " + pd.getName()); System.out.println("读方法: " + pd.getReadMethod()); System.out.println("写方法: " + pd.getWriteMethod()); } } }
-
注意事项
- 会包含从
Object
继承的getClass()
方法对应的class
属性,需按需过滤。
- 会包含从
四、核心要点总结
-
本质 :通过 Getter/Setter 命名规范定义属性的 Java 类,非 Java 语法强制,而是编程约定。
-
核心优势:
- 数据封装性强,符合面向对象设计原则。
- 兼容反射机制,便于框架(如 Spring)或工具动态操作属性。
-
最佳实践:
- 使用 IDE 自动生成 Getter/Setter,避免手动编写冗余代码。
- 通过
Introspector
实现框架级属性解析(如序列化、配置绑定)。
BigInteger
一、概述
- 用途 :处理超过 Java 原生
long
类型(64 位)范围的大整数运算,支持任意精度的整数。 - 实现 :通过
java.math.BigInteger
类实现,内部使用int[]
数组模拟大整数。
二、核心特性
- 不可变类 :与
Integer
、Long
类似,实例一旦创建不可修改。 - 继承自
Number
类 :支持转换为基本数值类型(如byte
、short
、int
、long
、float
、double
)。 - 无范围限制 :突破
long
类型的数值范围限制,但运算速度较原生类型慢(因需软件模拟)。
三、基本用法与运算
-
创建实例:
iniBigInteger bi = new BigInteger("1234567890"); // 直接通过字符串初始化
-
算术运算:
-
加法:
add(BigInteger val)
-
乘法:
multiply(BigInteger val)
-
幂运算:
pow(int exponent)
-
示例:
csharpBigInteger sum = i1.add(i2); // 加法运算 System.out.println(bi.pow(5)); // 计算5次幂
-
-
与原生类型对比:
long
运算速度快但范围有限(±9e18),BigInteger
范围无限但速度慢。
四、类型转换
-
普通转换方法(可能丢失精度或溢出):
byteValue()
、shortValue()
、intValue()
、longValue()
、floatValue()
、doubleValue()
。- 例:
longValue()
将BigInteger
转为long
,超出范围时截断高位。
-
精确转换方法(超出范围时抛异常):
intValueExact()
、longValueExact()
等,若结果超出目标类型范围,抛出ArithmeticException
。
-
特殊场景:
- 当
BigInteger
值超过float
最大范围(3.4×10³⁸)时,floatValue()
返回Infinity
。
- 当
BigDecimal
一、BigDecimal 核心特性
-
精确表示小数
- 用于任意精度的浮点运算,避免
float
/double
的精度丢失问题,常见于财务计算。 - 内部通过
BigInteger
(整数部分)和scale
(小数位数)表示。
- 用于任意精度的浮点运算,避免
-
不可变对象 :所有运算(如加减乘除)均返回新的
BigDecimal
实例,原对象不变。
二、创建与初始化
-
推荐使用字符串构造器:
javaBigDecimal bd = new BigDecimal("123.4567"); // 精确初始化,避免浮点精度误差
❗ 避免使用
new BigDecimal(double)
,因double
本身存在二进制精度丢失(如new BigDecimal(0.1)
实际存储值为0.10000000149
)。
三、小数位数与格式处理
-
获取小数位数(scale)
scale()
方法返回小数位数:
javanew BigDecimal("123.45").scale(); // 2 new BigDecimal("1234500").scale(); // 0(整数无小数位)
-
去除末尾零(stripTrailingZeros)
- 移除小数末尾的零,可能改变
scale
,若结果为整数且末尾有零,scale
为负数(如1234500.stripTrailingZeros().scale() = -2
,表示末尾有 2 个零)。
- 移除小数末尾的零,可能改变
四、算术运算
-
基础运算(加、减、乘)
- 直接调用对应方法,精度不丢失:
javaBigDecimal result = d1.add(d2); // 加法 result = d1.multiply(d2); // 乘法
-
除法(divide)
- 必须指定精度和舍入模式 ,否则除不尽时抛出
ArithmeticException
:
java// 保留10位小数,四舍五入 BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP);
- 常用舍入模式:
RoundingMode.HALF_UP
(四舍五入)、RoundingMode.DOWN
(直接截断)。
- 必须指定精度和舍入模式 ,否则除不尽时抛出
-
除法与余数(divideAndRemainder)
- 返回数组
[商, 余数]
,商为整数(小数部分为 0),余数绝对值小于除数:
iniBigDecimal[] dr = n.divideAndRemainder(m); if (dr[1].signum() == 0) { // 余数为0,n是m的整数倍 }
- 返回数组
五、精度调整(setScale)
- 设置指定小数位数,支持舍入或截断:
java
BigDecimal d1 = new BigDecimal("123.456789");
d1.setScale(4, RoundingMode.HALF_UP); // 123.4568(四舍五入)
d1.setScale(4, RoundingMode.DOWN); // 123.4567(直接截断)
六、比较操作
- 值比较(忽略 scale 差异) :使用
compareTo()
,返回 - 1(小于)、0(等于)、1(大于):
java
BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("123.45600");
d1.compareTo(d2); // 0(值相等,忽略末尾零)
- 严格相等(值和 scale 均相同) :使用
equals()
,但实际开发中很少用,因业务场景更关注值是否相等:
java
d1.equals(d2); // false(scale不同,d1.scale=3,d2.scale=5)
Java 常用工具类
一、核心工具类概述
Java 核心库提供了多个常用工具类,用于数学计算、进制转换、随机数生成等场景,显著提升开发效率。以下是重点介绍的工具类:
二、工具类详解
1. Math 类
-
功能:提供数学运算的静态方法和常量。
-
常用方法:
- 基础运算 :
abs()
(绝对值)、max()
/min()
(最值)、pow(x, y)
(x 的 y 次方)、sqrt()
(平方根)。 - 指数与对数 :
exp(x)
(e 的 x 次方)、log()
(自然对数)、log10()
(以 10 为底的对数)。 - 三角函数 :
sin()
、cos()
、tan()
等。 - 随机数 :
random()
生成[0, 1)
的随机数,可通过公式扩展到指定区间。
- 基础运算 :
-
常量 :
Math.PI
(圆周率)、Math.E
(自然对数底数)。 -
注意 :与
StrictMath
的区别在于Math
针对平台优化性能,而StrictMath
保证跨平台计算结果一致。
2. HexFormat 类(Java 17+)
-
功能 :简化
byte[]
数组与十六进制字符串的转换,支持格式定制。 -
常用方法:
- 编码 :
formatHex(byte[] data)
将字节数组转为十六进制字符串,可通过ofDelimiter()
、withPrefix()
、withUpperCase()
定制格式(如添加分隔符、前缀、大写字母)。 - 解码 :
parseHex(String hex)
将十六进制字符串转为字节数组。
- 编码 :
-
示例 :
HexFormat.of().formatHex("Hello".getBytes())
→48656c6c6f
。
3. Random 类
-
功能:生成伪随机数,序列由初始种子决定。
-
特点:
- 若不指定种子,默认使用系统时间戳,每次运行结果不同。
- 指定种子(如
new Random(12345)
)时,生成固定序列的伪随机数。
-
常用方法:
nextInt()
/nextLong()
/nextFloat()
/nextDouble()
,支持指定范围(如nextInt(10)
生成[0, 10)
的整数)。
-
注意 :
Math.random()
内部调用Random
,但无法指定种子。
4. SecureRandom 类
-
功能:生成安全的随机数,用于密码学等对随机性要求高的场景。
-
特点:
- 种子由系统提供的安全熵(如 CPU 热噪声、磁盘 I/O 事件)生成,不可预测。
- 提供高强度实现(
getInstanceStrong()
)和普通实现(new SecureRandom()
),前者可能因熵不足阻塞线程。
-
常用方法:
nextInt()
生成安全随机整数,nextBytes(byte[] buffer)
填充安全随机字节。
-
注意 :必须用于安全场景 ,绝不能用
Random
替代(后者种子可预测,存在安全风险)。
三、核心区别对比
工具类 | 随机性类型 | 种子来源 | 应用场景 |
---|---|---|---|
Math | 伪随机数(通过 Random) | 系统时间戳(默认) | 普通数学计算、非安全随机 |
Random | 伪随机数 | 自定义或系统时间 | 非安全场景(如游戏随机) |
SecureRandom | 安全随机数(基于熵) | 系统安全熵 | 密码学、加密密钥生成 |