Math类
基本特性
- 所在包:
java.lang
包(使用时无需手动导包) - 类结构:
final class Math
(final
修饰,禁止继承) - 核心功能:提供执行基础数学运算的静态方法
- 对象创建限制:API文档中无公开构造方法,禁止通过
new Math()
实例化对象
调用方式
无需实例化,所有字段和方法均为 static
,直接通过 Math.字段名
或 Math.方法名(参数列表)
调用。
示例:
java
double pi = Math.PI; // 获取圆周率
int max = Math.max(10, 20); // 返回 20
double root = Math.sqrt(4); // 返回 2.0
字段摘要
修饰符和类型 | 字段 | 描述 |
---|---|---|
static final double |
E | 自然对数的底数(约等于 2.718) |
static final double |
PI | 圆周率(约等于 3.14159) |
方法摘要(常用)
修饰符和类型 | 方法签名 | 描述 |
---|---|---|
static double |
abs(double a) | 返回 double 值的绝对值 |
static float |
abs(float a) | 返回 float 值的绝对值 |
static int |
abs(int a) | 返回 int 值的绝对值 |
static long |
abs(long a) | 返回 long 值的绝对值 |
static double |
ceil(double a) | 向上取整(返回 ≥a 的最小整数) |
static double |
floor(double a) | 向下取整(返回 ≤a 的最大整数) |
static int |
round(float a) | 四舍五入(返回最接近的 int) |
static long |
round(double a) | 四舍五入(返回最接近的 long) |
static double |
max(double a, double b) | 返回两个 double 值的较大值 |
static float |
max(float a, float b) | 返回两个 float 值的较大值 |
static int |
max(int a, int b) | 返回两个 int 值的较大值 |
static long |
max(long a, long b) | 返回两个 long 值的较大值 |
static double |
min(double a, double b) | 返回两个 double 值的较小值 |
static int |
min(int a, int b) | 返回两个 int 值的较小值 |
static double |
pow(double a, double b) | 返回 a 的 b 次幂(a^b) |
static double |
sqrt(double a) | 返回 double 值的平方根 |
static double |
cbrt(double a) | 返回 double 值的立方根 |
static double |
random() | 返回 [0.0, 1.0) 的随机小数 |
static double |
sin(double a) | 返回角度的正弦值(弧度制) |
static double |
cos(double a) | 返回角度的余弦值(弧度制) |
static double |
tan(double a) | 返回角度的正切值(弧度制) |
static double |
toRadians(double angdeg) | 将角度转换为弧度 |
static double |
toDegrees(double angrad) | 将弧度转换为角度 |
static double |
log(double a) | 返回自然对数(底数为 e) |
static double |
log10(double a) | 返回底数为 10 的对数 |
static double |
exp(double a) | 返回 e 的 a 次幂(e^a) |
System类
基本特性
- 所在包:
java.lang
包(使用时无需手动导包) - 类结构:
final class System
(final
修饰,禁止继承) - 核心功能:提供与系统交互的实用方法和标准I/O流
- 对象创建限制:API文档中无公开构造方法,禁止通过
new System()
实例化对象
调用方式
无需实例化,所有字段和方法均为 static
,直接通过 System.字段名
或 System.方法名(参数列表)
调用。
示例:
java
long timestamp = System.currentTimeMillis(); // 获取当前时间戳
System.out.println("Error Message"); // 标准输出流打印
String os = System.getProperty("os.name"); // 获取操作系统名称
字段摘要
修饰符和类型 | 字段 | 描述 |
---|---|---|
static final InputStream |
in | 标准输入流(通常对应键盘输入) |
static final PrintStream |
out | 标准输出流(控制台输出) |
static final PrintStream |
err | 标准错误输出流(红色错误输出) |
方法摘要(常用)
修饰符和类型 | 方法签名 | 描述 |
---|---|---|
static long |
currentTimeMillis() | 返回当前时间戳(毫秒,1970-01-01至今) |
static void |
arraycopy(Object src, int srcPos, Object dest, int destPos, int length) | 数组复制(高效) |
static void |
exit(int status) | 终止JVM(0正常退出,非0异常退出) |
static void |
gc() | 请求JVM执行垃圾回收(不保证立即执行) |
static String |
getProperty(String key) | 获取系统属性(os.name/user.dir/file.separator等) |
static String |
getenv(String name) | 获取环境变量值(PATH/HOME等) |
static void |
setIn(InputStream in) | 重定向标准输入流 |
static void |
setOut(PrintStream out) | 重定向标准输出流 |
static void |
setErr(PrintStream err) | 重定向标准错误流 |
static String |
lineSeparator() | 获取系统换行符(Windows:"\r\n", Linux:"\n") |
📌 注意事项:
arraycopy()
需确保目标数组有足够空间(否则抛出IndexOutOfBoundsException
)exit()
会立即终止JVM(后续代码不执行)gc()
仅为建议,JVM不保证立即执行回收
arraycopy方法 详解:
java
// 复制数据源数组中从[数据源数组起始索引]开始的[拷贝个数]个元素,粘贴到 [目的地数组]中的从[目的地数组起始索引]开始的位置
public static void arraycopy(数据源数组,数据源数组起始索引,目的地数组,目的地数组起始索引,拷贝个数)
int[] srcArray = {23 , 45 , 67 , 89 , 14 , 56 } ;
// 进行数组元素的copy:复制srcArray数组中从0索引开始的3个元素,粘贴到 desArray数组中的从1索引开始的位置
System.arraycopy(srcArray , 0 , desArray , 1 , 3);
// 进行数组元素的删除:删除数组中第3个元素(67),只需将 67 后面的其他元素依次向前进行移动即可
System.arraycopy(srcArray , 3 , srcArray , 2 , 3);
底层细节:
-
如果数据源数组和目的地数组都是基本数据类型,那么两者的类型必须保持一致,否则会报错
-
在拷贝的时候需要考虑数组的长度,如果超出范围也会报错
-
如果数据源数组和目的地数组都是引用数据类型,那么子类类型可以赋值给父类类型
代码示例:javaclass Person {} // 父类 class Student extends Person { // 子类 //...... } public class Main { public static void main(String[] args) { // 创建学生对象和数组 Student s1 = new Student("zhangsan", 23); Student s2 = new Student("lisi", 24); Student s3 = new Student("wangwu", 25); Student[] arr1 = {s1, s2, s3}; // 创建Person数组并复制引用 Person[] arr2 = new Person[3]; System.arraycopy(arr1, 0, arr2, 0, 3); // 输出结果 System.out.println("arr2内容: "); for(Person p : arr2) { System.out.println(p); } // 修改共享对象 s1.name = "张三"; System.out.println("\n修改后arr2[0]: " + arr2[0]); } }
Runtime
基本特性
- 所在包:
java.lang
包(使用时无需手动导包) - 类结构:
final class Runtime
(final
修饰,禁止继承) - 核心功能:提供程序运行时环境的管理能力(内存监控、进程执行、JVM终止等)
- 对象创建限制:
- 禁止通过
new Runtime()
实例化对象 - 只能通过静态方法
Runtime.getRuntime()
获取唯一实例(每个Java应用有且只有一个Runtime
实例)
- 禁止通过
调用方式
-
获取实例:通过静态方法获取Runtime对象
javaRuntime runtime = Runtime.getRuntime();
-
方法调用:通过Runtime实例调用非静态方法:
[Runtime对象].方法名(参数列表)
示例:javalong freeMem = runtime.freeMemory(); // 获取空闲内存 runtime.exec("notepad.exe"); // 启动记事本 int cores = runtime.availableProcessors(); // 获取处理器核心数
方法摘要(常用)
方法签名 | 描述 |
---|---|
static Runtime getRuntime() |
返回当前应用的Runtime对象 |
void exit(int status) |
终止当前JVM(0正常退出,非0异常退出) |
long totalMemory() |
返回JVM当前管理的总内存量(字节) |
long freeMemory() |
返回JVM空闲内存量(字节) |
long maxMemory() |
返回JVM可申请的最大内存量(字节) |
Process exec(String command) |
执行cmd命令,返回Process 对象(需处理IOException ) |
void gc() |
建议JVM执行垃圾回收(不保证立即执行) |
int availableProcessors() |
返回JVM可用处理器核心数 |
void addShutdownHook(Thread hook) |
注册JVM关闭时的钩子线程(安全释放资源) |
void load(String filename) |
加载指定文件名的本地库 |
void loadLibrary(String libname) |
加载系统库路径下的指定名称本地库 |
注意事项
exec()
方法执行系统命令存在安全风险,需谨慎使用- 调用
exit()
会立即终止JVM,后续代码不会执行- 内存监控数据单位为字节,需手动转换(1MB = 1024*1024字节)
- 本地库加载(
load()
/loadLibrary()
)需确保库文件存在且兼容当前系统
Object类
基本特性
- 所在包:
java.lang
包(自动导入,无需手动导包) - 类层次地位:Java类层次结构的根超类(所有类都直接或间接继承Object)
- 核心功能:提供对象基础操作(对象比较、字符串表示、线程同步等)
- 对象创建限制:
- 可通过
new Object()
创建实例 - 但实际开发中很少直接创建Object对象
- 可通过
继承特性说明
- 类继承:所有Java类默认继承Object类;自定义类未显式extends时,编译器自动添加
extends Object
:class Person {} 等价于 class Person extends Object {}
- 方法继承:父类(Object类)定义的方法会被所有子类继承;子类可重写其中关键方法(如
toString()
、equals()
)总结起来就是:由于类继承,所以在所有创建的Java类中都可以重写Object类定义的方法。
调用方式
通过任意Java对象调用继承自Object的方法: [任意对象].方法名(参数列表)
示例:
java
Person p = new Person("Alice", 30);
// 调用toString()方法
String info = p.toString(); // 返回对象字符串表示
// 调用equals()方法
boolean same = p.equals(new Person("Alice", 30)); // 比较对象内容
// 调用getClass()方法
Class<?> cls = p.getClass(); // 获取对象运行时类
方法摘要(常用)
toString()核心作用:
- 默认返回对象内存地址的字符串表示(类名@十六进制哈希值)
- 重写后可返回对象的属性信息,便于调试和日志输出
- 直接打印对象时自动隐式调用:
System.out.println(obj)
实际上执行的是System.out.println(obj.toString())
equals()核心作用:
- 默认比较对象地址是否相同(与
==
行为一致) - 重写后可实现自定义对象内容比较(如比较属性值)
clone()核心作用:
- 创建对象的副本(需实现
Cloneable
接口) - 注意深浅拷贝问题
- 必须满足以下两个条件才能成功调用
- 实现 Cloneable 接口:类必须声明实现该接口
- 重写 clone() 方法:访问权限改为
public
常见方法演示
演示toString方法
为了得到更有意义的输出(即对象的成员变量信息),我们需要在类中重写toString()方法。通过idea开发工具进行实现,具体步骤如下所示:
-
在空白处使用快捷键:alt + insert。此时会弹出如下的对话框\
-
选择toString,此时会弹出如下的对话框\
-
同时选择name和age属性,点击OK。此时IDEA自动生成toString方法的重写,代码如下所示:
javapublic class Student { private String name; // 姓名 private String age; // 年龄 // 构造方法 public Student(String name, String age) { this.name = name; this.age = age; } // 使用IDEA自动生成toString() @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age='" + age + '\'' + '}'; } }
-
测试验证
javapublic class ObjectDemo01 { public static void main(String[] args) { // 创建学生对象 Student s1 = new Student("itheima", "14"); // 直接输出对象(自动调用toString()) System.out.println(s1); } }
运行程序进行测试,控制台输出结果如下所示:
javaStudent{name='itheima', age='14'}
输出结果与IDEA自动生成toString方法的重写的输出结果一致。证明直接输出一个对象,那么会默认调用对象的toString方法。
演示equals方法
为了得到更有意义的输出(即比较对象的属性),我们需要在类中重写equals方法。通过idea开发工具进行实现,具体步骤如下所示:
-
在空白处使用快捷键:alt + insert。此时会弹出如下的对话框\
-
选择equals() and hashCode()方法,弹出如下的对话框
点击next,弹出如下对话框:\
选择neme和age属性点击next,弹出如下对话框:\
取消勾选name和age属性(因为此时窗口选择的是在生成hashCode方法时所涉及到的属性,关于hashCode方法后期再做重点介绍),点击Finish完成生成操作。此时IDEA自动生成equals方法和hashCode方法的重写,代码如下所示:
java@Override public boolean equals(Object o) { // 1. 自反性检查:如果是同一个对象(内存地址相同) if (this == o) return true; // 2. 安全性检查:排除null和非同类对象 if (o == null || getClass() != o.getClass()) return false; // 3. 类型转换:将Object转为具体类型 Student student = (Student) o; // 4. 关键属性比较:使用null安全的Objects.equals() return Objects.equals(name, student.name) && Objects.equals(age, student.age); } @Override public int hashCode() { // hashCode方法暂时使用不到,可以将hashCode方法删除 return 0; }
-
测试验证
javapublic class ObjectDemo02 { public static void main(String[] args) { // 创建两个学生对象 Student s1 = new Student("itheima" , "14") ; Student s2 = new Student("itheima" , "14") ; // 比较两个对象是否相等 System.out.println(s1.equals(s2)); }
重写完毕以后运行程序进行测试,控制台输出结果如下所示:
javatrue
此时equals方法比较的是对象的成员变量值,而s1和s2两个对象的成员变量值都是相同的。因此比较完毕以后的结果就是true。
演示clone方法
把A对象的属性值完全拷贝给B对象,也叫对象拷贝,对象复制
- 对象克隆的分类: 深克隆和浅克隆
- Object类默认的是浅克隆
浅克隆:
- 对 对象内部的基本数据类型与引用数据类型的属性都进行拷贝
- 基本数据类型拷贝过来的是具体的数据,引用数据类型拷贝过来的是地址值

深克隆: 拷贝基本数据类型;字符串复用;对引用数据类型进行重新创建
图示说明:
对象深克隆实现代码
创建对象u1
的一个副本(克隆),并将这个副本赋值给变量u2
:
User u2 = (User) u1.clone();
(User)
:clone() 返回的是 Object 类型(所有类的基类),但实际需要返回 User 类型的对象,需要进行显式类型转换
测试类 ObjectDemo4.java
java
package com.itheima.a04objectdemo;
public class ObjectDemo4 {
public static void main(String[] args) throws CloneNotSupportedException {
// 1. 创建原始对象
int[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
User u1 = new User(1, "zhangsan", "1234qwer", "girl11", data);
// 2. 克隆对象
User u2 = (User) u1.clone();
// 3. 验证克隆效果
// 修改原始对象的数组数据
u1.getData()[0] = 100;
// 打印两个对象
System.out.println("原始对象: " + u1);
System.out.println("克隆对象: " + u2);
}
}
用户类 User.java
java
package com.itheima.a04objectdemo;
import java.util.StringJoiner;
// 实现Cloneable标记接口(无方法,仅表示可克隆)
public class User implements Cloneable {
private int id;
private String username;
private String password;
private String path;
private int[] data;
// 构造方法
public User(int id, String username, String password, String path, int[] data) {
this.id = id;
this.username = username;
this.password = password;
this.path = path;
this.data = data;
}
// getter/setter方法
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getPath() { return path; }
public void setPath(String path) { this.path = path; }
public int[] getData() { return data; }
public void setData(int[] data) { this.data = data; }
// toString方法
@Override
public String toString() {
return "User{id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", path='" + path + '\'' +
", data=" + arrToString() + '}';
}
// 数组转字符串辅助方法
private String arrToString() {
StringJoiner sj = new StringJoiner(", ", "[", "]");
for (int value : data) {
sj.add(String.valueOf(value));
}
return sj.toString();
}
// 重写clone方法实现深克隆
@Override
protected Object clone() throws CloneNotSupportedException {
// 1. 调用父类浅克隆方法,父类:在这里就是 `Object` 类。
User clonedUser = (User) super.clone();
// 2. 深克隆处理:复制数组内容
//2.1 获取当前被克隆对象的数组引用 保存到 临时变量 originalData 中
int[] originalData = this.data; //data是前面定义的数组变量
//2.2 创建一个与原数组的长度相同的新数组对象,作为受粘贴对象
int[] newData = new int[originalData.length]; //originalData.length:原数组的长度
//2.3 将原数组的每个元素值复制到新数组
System.arraycopy(originalData, 0, newData, 0, originalData.length);
// 3. 替换受粘贴对象的数组引用,将受粘贴对象的data引用指向新创建的数组clonedUser
clonedUser.data = newData;
return clonedUser;
}
}
执行结果:
ini
原始对象: User{id=1, username='zhangsan', password='1234qwer', path='girl11', data=[100, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]}
克隆对象: User{id=1, username='zhangsan', password='1234qwer', path='girl11', data=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]}
克隆关键点说明
完整深克隆实现要素
类别 | 要素 | 说明 |
---|---|---|
基础要素 | 1. 实现 Cloneable 接口 |
标记可克隆 |
2. 重写 clone() 方法 |
提供访问入口 | |
3. 调用 super.clone() |
创建基础副本 | |
深克隆扩展 | 4. 识别可变引用字段 | 如数组/集合/自定义对象 |
5. 创建字段新实例 | new 或 clone() |
|
6. 复制字段内容 | 值复制/递归克隆 | |
7. 更新克隆对象引用 | 指向新实例 |
浅克隆只需基础三要素
在上述代码中的具体体现
java
// === 基础三要素 ===
public class User implements Cloneable { // 要素1: 实现接口
@Override // 要素2: 重写方法
protected Object clone() {
User cloned = (User) super.clone(); // 要素3: 调用super.clone()
// === 深克隆扩展 ===
// 要素4: 识别可变字段 (data数组)
// 要素5: 创建新实例
int[] newData = new int[this.data.length];
// 要素6: 复制内容
System.arraycopy(this.data, 0, newData, 0, this.data.length);
// 要素7: 更新引用
cloned.data = newData;
return cloned;
}
}
特殊引用类型处理差异:
引用类型 | 处理方式 |
---|---|
String | 无需处理(不可变) |
基本类型数组 | System.arraycopy() 或Arrays.copyOf() |
对象数组 | 循环 + 递归克隆 |
集合类 | 创建新集合并复制元素 |
关键结论 :
Java原生克隆机制(
clone()
方法)默认是浅克隆,要实现真正的对象隔离必须通过重写clone()
方法实现深克隆。深克隆的核心在于为每个引用类型属性创建独立副本,尤其当对象包含嵌套结构时需递归处理。实际开发中推荐使用序列化或JSON工具库实现深克隆。
Objects类
基本特性
- 所在包:
java.util
包(使用时需要手动导包) - 类结构:
final class Objects
(final
修饰,禁止继承) - 核心功能:提供对象操作的工具方法(如判空、判等、哈希值计算等)
- 对象创建限制:API文档中无公开构造方法,禁止通过
new Objects()
实例化对象
调用方式
无需实例化,所有方法均为 static
,直接通过 Objects.方法名(参数列表)
调用。
示例:
java
boolean equal = Objects.equals(obj1, obj2); // 安全比较对象相等
boolean isNull = Objects.isNull(obj); // 判断对象是否为null
int hash = Objects.hash(name, age, id); // 生成对象哈希值
常见方法
基本对象操作
-
public static String toString(Object obj):安全获取对象的字符串表示形式
- 当对象不为
null
时,返回o.toString()
的结果 - 当对象为
null
时,返回字符串"null"
优势 :避免直接调用
toString()
可能引发的NullPointerException
- 当对象不为
-
public static boolean equals(Object a, Object b):安全比较两个对象是否相等
- 如果两个对象都为
null
,返回true
- 如果只有一个对象为
null
,返回false
- 如果两个对象都不为
null
,返回a.equals(b)
的结果 优势 :安全处理null
值比较,避免NullPointerException
- 如果两个对象都为
-
public static boolean isNull(Object obj) :判断对象是否为
null
(等价于obj == null
) -
public static boolean nonNull(Object obj) :判断对象是否不为
null
(等价于obj != null
)
非空校验与默认值
-
public static <T> T requireNonNull(Object obj):强制校验对象非空
- 当对象不为
null
时,返回对象本身 - 当对象为
null
时,抛出NullPointerException
- 当对象不为
-
public static <T> T requireNonNull(Object obj, String message):带自定义错误信息的非空校验
- 对象不为
null
时返回对象本身 - 对象为
null
时抛出带指定消息的NullPointerException
- 对象不为
-
public static <T> T requireNonNullElse(Object obj, Object defaultObj):非空校验并提供默认值
- 对象不为
null
时返回对象本身 - 对象为
null
时返回指定的默认对象
- 对象不为
- 约束 :默认对象不能为
null
(否则抛出NullPointerException
)
- public static <T> T requireNonNullElseGet(Object obj, Supplier supplier) :非空校验并通过Supplier提供默认值
- 对象不为
null
时返回对象本身 - 对象为
null
时调用Supplier生成默认值
- 对象不为
- Supplier 是一个函数式接口 ,它代表一个无参数但有返回值的操作。通常通过 Lambda 表达式编写 Supplier
- 约束 :Supplier不能为
null
(否则抛出NullPointerException
)
方法特性总结
说明:
- 泛型说明:方法签名中的
<T>
表示泛型类型,可接受任意非基本类型(引用类型)。在调用时,编译器会自动推断类型。requireNonNull
系列方法常用于参数校验,确保传入的对象不为null
。requireNonNullElse
和requireNonNullElseGet
提供安全的默认值机制,避免空指针。
案例演示
接下来我们就来通过一些案例演示一下Objects类中的这些方法特点。
案例1:演示重点学习方法
实现步骤:
- 创建一个学生类,提供两个成员变量(name , age);并且提供对应的无参构造方法和有参构造方法以及get/set方法,并且重写toString方法和equals方法
- 创建一个测试类(ObjectsDemo01), 在该类中编写测试代码
如下所示:
Student类
java
public class Student {
private String name ; // 姓名
private String age ; // 年龄
// 其他代码略
...
}
ObjectsDemo01测试类
java
public class ObjectsDemo01 {
public static void main(String[] args) {
// 调用方法
method_04() ;
}
// 测试nonNull方法
public static void method_04() {
// 创建一个学生对象
Student s1 = new Student("itheima" , "14") ;
// 调用Objects类中的nonNull方法
boolean result = Objects.nonNull(s1);
// 输出结果
System.out.println(result); // 输出: true (因为s1不是null)
}
// 测试isNull方法
public static void method_03() {
// 创建一个学生对象
Student s1 = new Student("itheima" , "14") ;
// 调用Objects类中的isNull方法
boolean result = Objects.isNull(s1);
// 输出结果
System.out.println(result); // 输出: false (因为s1不是null)
}
// 测试equals方法
public static void method_02() {
// 创建两个学生对象
Student s1 = new Student("itheima" , "14") ;
Student s2 = new Student("itheima" , "14") ;
// 调用Objects类中的equals方法,比较两个对象是否相等
boolean result = Objects.equals(s1, s2); // 如果Student没有重写Object类中的equals方法,此处比较的还是对象的地址值
// 输出结果
System.out.println(result); // 输出: false (除非Student类重写了equals方法,否则比较的是内存地址)
}
// 测试toString方法
public static void method_01() {
// 创建一个学生对象
Student s1 = new Student("itheima" , "14") ;
// 调用Objects中的toString方法,获取s1对象的字符串表现形式
String result = Objects.toString(s1); // 如果Student没有重写Object类中的toString方法,此处还是返回的对象的地址值
// 输出结果
System.out.println(result); // 输出: Student类的toString()结果或默认的对象哈希表示(如Student@1b6d3586)
}
}
案例2:演示需要了解的方法
java
public class ObjectsDemo02 {
public static void main(String[] args) {
// 调用方法
method_03();
}
// 演示requireNonNullElseGet
public static void method_03() {
// 创建一个学生对象
Student s1 = new Student("itheima" , "14") ;
// 调用Objects对象的requireNonNullElseGet方法,该方法的第二个参数是Supplier类型的,查看源码我们发现Supplier是一个函数式接口,
// 那么我们就可以为其传递一个Lambda表达式,而在Supplier接口中所定义的方法是无参有返回值的方法,因此具体调用所传入的Lambda表达式如下所示
Student student = Objects.requireNonNullElseGet(s1, () -> {
return new Student("itcast", "14");
});
// 输出
System.out.println(student); // 输出: Student{name='itheima', age='14'} (因为s1不为null,直接返回s1)
}
// 演示requireNonNullElse
public static void method_02() {
// 创建一个学生对象
Student s1 = new Student("itheima" , "14") ;
// 调用Objects对象的requireNonNullElse方法
Student student = Objects.requireNonNullElse(s1, new Student("itcast", "14"));
// 输出
System.out.println(student); // 输出: Student{name='itheima', age='14'} (因为s1不为null,直接返回s1)
}
// 演示requireNonNull
public static void method_01() {
// 创建一个学生对象
Student s1 = new Student("itheima" , "14") ;
// 调用Objects对象的requireNonNull方法
Student student = Objects.requireNonNull(s1);
// 输出
System.out.println(student); // 输出: Student{name='itheima', age='14'} (因为s1不为null,直接返回s1)
}
}
BigInteger类
基本特性
- 所在包:java.math包(使用时需要手动导包)
- 类结构:public class BigInteger extends Number implements Comparable<BigInteger>
- 核心功能:表示不可变的任意精度的整数,提供所有Java的基本整数操作符的对应物,并提供java.lang.Math的所有相关方法
- 数值范围:理论上可表示无限大的整数(仅受JVM内存限制)
调用方式
通过创建BigInteger对象实例来调用其方法。
示例:
java
import java.math.BigInteger;
BigInteger bigInt = new BigInteger("123456789012345678901234567890");
BigInteger result = bigInt.add(anotherBigInt); // 加法运算
int comparison = bigInt.compareTo(anotherBigInt); // 比较大小
常见方法
构造方法
java
public BigInteger(int num, Random rnd) // 生成随机大整数,范围:[0 ~ 2^num - 1]
public BigInteger(String val) // 通过字符串创建指定的大整数
public BigInteger(String val, int radix) // 创建指定进制的大整数
静态工厂方法
java
public static BigInteger valueOf(long val) // 静态方法获取BigInteger对象(内部有优化)
成员方法
java
// 算术运算方法
public BigInteger add(BigInteger val) // 加法运算
public BigInteger subtract(BigInteger val) // 减法运算
public BigInteger multiply(BigInteger val) // 乘法运算
public BigInteger divide(BigInteger val) // 除法运算
public BigInteger[] divideAndRemainder(BigInteger val) // 除法运算,返回商和余数数组
public BigInteger pow(int exponent) // 幂运算(次方)
// 比较方法
public boolean equals(Object x) // 相等比较
public BigInteger max(BigInteger val) // 返回较大值
public BigInteger min(BigInteger val) // 返回较小值
// 类型转换方法
public int intValue() // 转换为int类型(可能丢失精度)
方法使用说明
- 对象创建 :
- 如果数字未超出long类型范围,推荐使用静态方法
valueOf()
获取对象(性能更优) - 如果数字超出long类型范围,必须使用构造方法创建对象
- BigInteger对象一旦创建,其内部值不可改变(不可变性)
- 如果数字未超出long类型范围,推荐使用静态方法
- 运算特性 :
- 所有算术运算都会产生新的BigInteger对象,原对象保持不变
- 进行除法运算时,如果除数为0会抛出ArithmeticException
- 注意事项 :
- 使用
intValue()
方法转换时,如果值超出int范围,结果可能不正确(数据截断) - 比较两个BigInteger对象时,应使用
equals()
方法而非==
运算符
- 使用
案例演示
演示1:BigInteger对象创建与方法演示
java
import java.math.BigInteger;
import java.util.Random;
public class BigIntegerDemo1 {
public static void main(String[] args) {
// 1. 获取随机大整数 (范围: 0 ~ 2^4-1 = 0~15)
Random r = new Random();
for (int i = 0; i < 5; i++) {
BigInteger bd1 = new BigInteger(4, r);
System.out.println("随机数 " + (i+1) + ": " + bd1);
}
// 2. 获取指定的大整数
// 注意: 字符串中必须是整数,否则会报错
BigInteger bd2 = new BigInteger("12345678901234567890");
System.out.println("指定大整数: " + bd2);
// 3. 获取指定进制的大整数
// 注意:
// 1. 字符串中的数字必须是整数
// 2. 字符串中的数字必须要跟进制吻合
BigInteger bd3 = new BigInteger("1010", 2); // 二进制表示的10
System.out.println("二进制1010转换为十进制: " + bd3);
// 4. 静态方法获取BigInteger对象
// 注意:
// 1. 能表示范围比较小,只能在long的取值范围之内
// 2. 在内部对常用数字(-16~16)进行了优化
BigInteger bd4 = BigInteger.valueOf(16);
BigInteger bd5 = BigInteger.valueOf(16);
System.out.println("值相同的对象是否相同: " + (bd4 == bd5)); // true (优化范围内)
BigInteger bd6 = BigInteger.valueOf(17);
BigInteger bd7 = BigInteger.valueOf(17);
System.out.println("值相同的对象是否相同: " + (bd6 == bd7)); // false (超出优化范围)
// 5. 对象不可变性演示
BigInteger bd8 = BigInteger.valueOf(1);
BigInteger bd9 = BigInteger.valueOf(2);
// 不会修改原对象,而是产生新对象
BigInteger result = bd8.add(bd9);
System.out.println("加法结果: " + result);
System.out.println("原对象bd8的值: " + bd8); // 保持不变
System.out.println("原对象bd9的值: " + bd9); // 保持不变
}
}
演示2:BigInteger常用运算方法演示
java
import java.math.BigInteger;
public class BigIntegerDemo2 {
public static void main(String[] args) {
/*
public BigInteger add(BigInteger val) 加法
public BigInteger subtract(BigInteger val) 减法
public BigInteger multiply(BigInteger val) 乘法
public BigInteger divide(BigInteger val) 除法,获取商
public BigInteger[] divideAndRemainder(BigInteger val) 除法,获取商和余数
public boolean equals(Object x) 比较是否相同
public BigInteger pow(int exponent) 次幂
public BigInteger max/min(BigInteger val) 返回较大值/较小值
public int intValue() 转为int类型整数,超出范围数据有误
*/
// 创建两个BigInteger对象
BigInteger bd1 = BigInteger.valueOf(20);
BigInteger bd2 = BigInteger.valueOf(6);
// 加法
BigInteger sum = bd1.add(bd2);
System.out.println("加法结果: " + sum);
// 减法
BigInteger difference = bd1.subtract(bd2);
System.out.println("减法结果: " + difference);
// 乘法
BigInteger product = bd1.multiply(bd2);
System.out.println("乘法结果: " + product);
// 除法(获取商)
BigInteger quotient = bd1.divide(bd2);
System.out.println("除法商: " + quotient);
// 除法(获取商和余数)
BigInteger[] divResult = bd1.divideAndRemainder(bd2);
System.out.println("商: " + divResult[0] + ", 余数: " + divResult[1]);
// 相等比较
boolean isEqual = bd1.equals(bd2);
System.out.println("是否相等: " + isEqual);
// 次幂
BigInteger power = bd1.pow(3);
System.out.println("20的3次方: " + power);
// 最大值/最小值
BigInteger max = bd1.max(bd2);
BigInteger min = bd1.min(bd2);
System.out.println("最大值: " + max + ", 最小值: " + min);
// 转换为int类型(注意可能的数据丢失)
BigInteger bigValue = BigInteger.valueOf(2147483647); // int最大值
int intValue = bigValue.intValue();
System.out.println("转换为int: " + intValue);
// 转换为double类型
double doubleValue = bigValue.doubleValue();
System.out.println("转换为double: " + doubleValue);
}
}
底层存储方式
BigInteger类的底层实现基于以下原理:
存储机制
- 计算机底层存储的都是二进制数据(010101...),数据类型是编程语言层面的抽象概念
- BigInteger将大整数转换为二进制后,每32个bit(4字节)为一组,存储在int类型的数组中
容量限制
- 数组最大长度:理论上数组最多能存储约21亿个元素(受限于Java数组的最大长度,约为Integer.MAX_VALUE)
- 每个元素的取值范围:数组中每个int元素可以表示0到2³²-1(约42亿多)的数值
- 理论最大数值:基于上述限制,BigInteger能表示的最大数字理论上可达(2³²)^(2³¹) ≈ 42亿的21亿次方
- 实际限制:在实际应用中,尚未达到理论最大值之前,计算机的内存就会先被耗尽。所以通常认为BigInteger可以表示"无限大"的整数(实际上受可用内存限制)
存储方式如图所示:
BigDecimal类
引入 浮点数(float/double)在进行数学运算时可能存在精度丢失问题。计算机底层使用二进制运算,十进制浮点数转换为二进制时可能产生无限循环二进制值,导致运算结果不精确。BigDecimal通过基于十进制的存储和运算机制,从根本上解决精度问题。
基本特性
- 所在包:java.math包(使用时需手动导包)
- 类结构:public class BigDecimal(非final修饰,可继承)
- 核心功能:提供高精度的十进制运算,解决浮点数运算中的精度丢失问题
- 对象创建:通过构造方法或静态方法实例化,支持从字符串、整数、双精度等类型创建对象
调用方式
需通过实例化对象调用其方法,提供多种算术运算和精度控制功能。
示例:
java
BigDecimal num1 = new BigDecimal("0.1"); // 通过字符串构造
BigDecimal num2 = BigDecimal.valueOf(0.2); // 静态工厂方法
BigDecimal result = num1.add(num2); // 加法运算
System.out.println(result); // 输出: 0.3
常见方法
构造方法
BigDecimal类提供多种构造方法创建对象,其中最常用的构造方法包括:
java
BigDecimal(String val) // 通过字符串创建BigDecimal对象
BigDecimal(double val) // 通过双精度浮点数创建BigDecimal对象
BigDecimal(int val) // 通过整型数据创建BigDecimal对象
常用成员方法
BigDecimal类提供精确的算术运算方法,主要包括:
java
public BigDecimal add(BigDecimal value) // 加法运算
public BigDecimal subtract(BigDecimal value) // 减法运算
public BigDecimal multiply(BigDecimal value) // 乘法运算
public BigDecimal divide(BigDecimal value) // 除法运算
案例演示
案例1:基本四则运算演示
通过BigDecimal类进行精确的数学运算,避免浮点数精度丢失问题:
java
// 创建两个BigDecimal对象
BigDecimal b1 = new BigDecimal("0.3");
BigDecimal b2 = new BigDecimal("4");
// 进行四则运算并输出结果
System.out.println(b1.add(b2)); // 加法运算:4.3
System.out.println(b1.subtract(b2)); // 减法运算:-3.7
System.out.println(b1.multiply(b2)); // 乘法运算:1.2
System.out.println(b1.divide(b2)); // 除法运算:0.075
使用BigDecimal进行浮点数计算可完全避免精度损失问题,确保计算结果的准确性。
案例2:除法运算的特殊情况处理
当除法运算结果为无限循环小数时,直接调用divide方法会抛出ArithmeticException异常:
java
BigDecimal b1 = new BigDecimal("1");
BigDecimal b2 = new BigDecimal("3");
System.out.println(b1.divide(b2)); // 抛出ArithmeticException
解决方案是使用重载的divide方法指定精度和舍入模式:
java
BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
参数说明:
- divisor:除数对应的BigDecimal对象
- scale:精确位数(保留小数位数)
- roundingMode:舍入模式,常用模式包括:
- UP:直接进1
- FLOOR:直接删除
- HALF_UP:四舍五入
应用示例:
java
// UP模式(直接进1)
BigDecimal b1 = new BigDecimal("1");
BigDecimal b2 = new BigDecimal("3");
System.out.println(b1.divide(b2, 2, RoundingMode.UP)); // 输出: 0.34
// FLOOR模式(直接删除)
System.out.println(b1.divide(b2, 2, RoundingMode.FLOOR)); // 输出: 0.33
// HALF_UP模式(四舍五入)
BigDecimal b3 = new BigDecimal("0.3");
BigDecimal b4 = new BigDecimal("4");
System.out.println(b3.divide(b4, 2, RoundingMode.HALF_UP)); // 输出: 0.08
实际开发中推荐使用可指定精度和舍入模式的divide方法进行除法运算,以确保程序的稳定性和准确性。
底层存储方式
把数据看成字符串,遍历得到里面的每一个字符,把这些字符在ASCII码表上的值,都存储到数组中。