万物都是相同的,只要你把一个能力掌握好了,你会发现其他的东西都是万变不离其宗。
面向对象基础
模块
一、模块的核心概念
-
解决依赖问题
- 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 | 安全随机数(基于熵) | 系统安全熵 | 密码学、加密密钥生成 |