1 Math类
1.1 概述
查看API文档,我们可以看到API文档中关于Math类的定义如下:
Math
类是Java提供的一个工具类,位于java.lang
包中,因此在使用时不需要显式导包。Math
类被final
修饰,意味着它不能被继承。它提供了一系列用于基本数学运算的静态方法,包括算术运算、指数运算、对数运算、三角函数等。由于所有方法都是静态的,调用这些方法时可以直接使用类名,而无需实例化对象。
1.2 常见方法
Java中Math
类的常见方法如下:
public static int abs(int a) // 返回参数的绝对值
public static double ceil(double a) // 返回大于或等于参数的最小整数
public static double floor(double a) // 返回小于或等于参数的最大整数
public static int round(float a) // 按照四舍五入返回最接近参数的int类型的值
public static int max(int a, int b) // 获取两个int值中的较大值
public static int min(int a, int b) // 获取两个int值中的较小值
public static double pow(double a, double b) // 计算a的b次幂的值
public static double random() // 返回一个[0.0,1.0)的随机值
1.2.1 方法说明
abs(int a)
:返回参数的绝对值。如果参数为负数,则返回它的正值。ceil(double a)
:返回大于或等于a
的最小整数值,结果以double
类型返回。即向上取整。floor(double a)
:返回小于或等于a
的最大整数值,结果以double
类型返回。即向下取整。round(float a)
:按照四舍五入的方式返回最接近a
的int
类型的值。如果是double
类型的值,则返回long
类型的值。max(int a, int b)
:返回两个数中的较大值。重载的方法还可以处理long
、float
、double
等类型。min(int a, int b)
:返回两个数中的较小值。重载的方法同样可以处理其他类型。pow(double a, double b)
:返回a
的b
次幂的值。结果以double
类型返回。random()
:返回一个[0.0, 1.0)
之间的随机double
值。
1.2.2 案例演示
以下是常见方法的示例代码:
public class MathDemo01 {
public static void main(String[] args) {
// 绝对值
System.out.println("-2的绝对值为:" + Math.abs(-2));
System.out.println("2的绝对值为:" + Math.abs(2));
// 向上取整
System.out.println("大于或等于23.45的最小整数为:" + Math.ceil(23.45));
System.out.println("大于或等于-23.45的最小整数为:" + Math.ceil(-23.45));
// 向下取整
System.out.println("小于或等于23.45的最大整数为:" + Math.floor(23.45));
System.out.println("小于或等于-23.45的最大整数为:" + Math.floor(-23.45));
// 四舍五入
System.out.println("23.45四舍五入的结果为:" + Math.round(23.45));
System.out.println("23.55四舍五入的结果为:" + Math.round(23.55));
// 最大值
System.out.println("23和45的最大值为:" + Math.max(23, 45));
// 最小值
System.out.println("12和34的最小值为:" + Math.min(12, 34));
// 幂运算
System.out.println("2的3次幂计算结果为:" + Math.pow(2, 3));
// 随机数
System.out.println("获取到的0-1之间的随机数为:" + Math.random());
}
}
输出结果:
-2的绝对值为:2
2的绝对值为:2
大于或等于23.45的最小整数为:24.0
大于或等于-23.45的最小整数为:-23.0
小于或等于23.45的最大整数为:23.0
小于或等于-23.45的最大整数为:-24.0
23.45四舍五入的结果为:23
23.55四舍五入的结果为:24
23和45的最大值为:45
12和34的最小值为:12
2的3次幂计算结果为:8.0
获取到的0-1之间的随机数为:0.7322484131745958
明白了,我会基于你提供的内容进行补充和完善。
2 System类
2.1 概述
查看API文档,我们可以看到API文档中关于System类的定义如下:
System类所在包为java.lang包,因此在使用的时候不需要进行导包。同时System类被final修饰了,因此该类不能被继承。
System类包含了系统操作的一些常用方法,比如获取当前时间所对应的毫秒值、终止当前JVM、进行数组复制等。这些方法为我们提供了对操作系统和Java虚拟机的直接控制。
2.2 常见方法
常见方法介绍
我们需要重点学习的System类中的常见方法如下所示:
public static long currentTimeMillis() // 获取当前时间的毫秒值
public static void exit(int status) // 终止当前正在运行的JVM,0表示正常退出,非0表示异常退出
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); // 进行数组元素复制
2.3 常见方法补充与解释
1. currentTimeMillis()
方法
- 功能:获取当前时间的毫秒值。从1970年1月1日00:00:00 GMT到现在所经过的时间,返回long类型的毫秒数。
- 应用场景:常用于统计代码运行时间、实现定时功能等。
示例:
public class SystemDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
// 执行一段代码,比如循环计算
for (int i = 0; i < 100000; i++) {
System.out.println(i);
}
long end = System.currentTimeMillis();
System.out.println("执行时间:" + (end - start) + " 毫秒");
}
}
通过这个方法,可以方便地进行代码的性能分析。
2. exit(int status)
方法
- 功能:终止正在运行的JVM进程,参数
status
为0表示正常退出,非0表示异常退出。 - 应用场景:通常在异常处理、需要强制终止程序时使用。
示例:
public class SystemDemo {
public static void main(String[] args) {
System.out.println("程序开始执行");
// 强制终止JVM
System.exit(0); // 或者System.exit(1)表示异常退出
// 以下代码不会执行
System.out.println("程序已经终止");
}
}
3. arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
方法
-
功能:用于将一个数组从指定位置复制到另一个数组的指定位置,效率比手动复制更高。
-
应用场景:常用于数组的复制、元素删除、元素插入等操作。
-
参数说明:
src
:源数组srcPos
:源数组起始位置dest
:目标数组destPos
:目标数组的起始位置length
:要复制的元素个数
示例:
public class SystemDemo {
public static void main(String[] args) {
int[] srcArray = {
1, 2, 3, 4, 5};
int[] destArray = new int[10];
// 复制srcArray的前3个元素到destArray中,从索引1开始
System.arraycopy(srcArray, 0, destArray, 1, 3);
// 输出结果 [0, 1, 2, 3, 0, 0, 0, 0, 0, 0]
System.out.println(Arrays.toString(destArray));
}
}
注意:
- 源数组和目标数组必须兼容(比如都是整型数组,或者子类数组赋值给父类数组)。
- 如果拷贝时的
length
超出了数组的长度范围,会抛出ArrayIndexOutOfBoundsException
异常。
2.4 arraycopy 的应用扩展
除了复制,arraycopy()
还可以用于实现数组元素的删除或插入操作。以下是删除操作的示例:
删除数组中的某个元素:
public class SystemDemo {
public static void main(String[] args) {
int[] arr = {
10, 20, 30, 40, 50};
int deleteIndex = 2; // 要删除的元素位置
// 删除数组的第3个元素(值为30),即将30后的元素依次向前移动
System.arraycopy(arr, deleteIndex + 1, arr, deleteIndex, arr.length - deleteIndex - 1);
// 将数组的最后一个元素置为0
arr[arr.length - 1] = 0;
// 输出结果:[10, 20, 40, 50, 0]
System.out.println(Arrays.toString(arr));
}
}
2.5 arraycopy 的底层细节
arraycopy
是一个本地方法,它是由JVM底层实现的,用于高效地进行数组复制。该方法能直接操作内存,性能优于通过循环来复制数组。
arraycopy 方法的注意事项:
- 如果数据源数组和目标数组都是基本数据类型,那么它们的类型必须完全一致。
- 如果是引用数据类型,那么子类类型可以赋值给父类类型。
arraycopy()
不会自动调整目标数组的大小,目标数组必须能够容纳被复制的元素,否则会抛出ArrayIndexOutOfBoundsException
异常。
3 Runtime类
3.1 概述
Runtime
类表示 Java 程序的运行时环境,可以获取与当前 JVM 运行相关的系统资源信息,例如 CPU 核心数、内存信息等。Runtime
类属于 java.lang
包,因此不需要显式导入。该类不能被实例化,只能通过静态方法 getRuntime()
获取 Runtime
对象,然后调用其方法来执行各种操作,如内存管理、执行命令等。
3.2 常见方法
下面列出了 Runtime
类中常用的方法,提供了对 JVM 运行时环境的访问和控制能力。
public static Runtime getRuntime() // 获取当前 Java 程序的运行时环境对象
public void exit(int status) // 终止当前正在运行的 Java 虚拟机,0 表示正常退出,非 0 表示异常退出
public int availableProcessors() // 获取当前系统中可用的 CPU 核心数
public long maxMemory() // 获取 JVM 可以从操作系统中申请的最大内存,单位为字节
public long totalMemory() // 获取 JVM 已经从操作系统申请的内存总量,单位为字节
public long freeMemory() // 获取 JVM 剩余可用内存,单位为字节
public Process exec(String command) // 执行操作系统命令
方法说明:
getRuntime()
:返回与当前 Java 应用程序关联的Runtime
对象。通过它可以调用 JVM 环境相关的方法。exit(int status)
:终止当前 Java 虚拟机的运行。参数status
为退出状态码,0 表示正常退出,非零表示异常退出。availableProcessors()
:返回 Java 虚拟机可用的处理器核心数,通常用于多线程编程时决定任务的并行度。maxMemory()
:返回 JVM 能从操作系统获取的最大内存量,通常与启动时的-Xmx
选项相关。totalMemory()
:返回 JVM 当前已从操作系统分配的内存总量,单位为字节。freeMemory()
:返回 JVM 中未使用的可用内存,单位为字节。exec(String command)
:运行指定的操作系统命令,并返回一个Process
对象,用于处理进程的输入输出。
代码示例:
public class RunTimeDemo {
public static void main(String[] args) throws IOException {
// 获取 Runtime 实例
Runtime runtime = Runtime.getRuntime();
// 获取 CPU 核心数
System.out.println("可用的处理器核心数:" + runtime.availableProcessors());
// 获取 JVM 的最大内存、总内存、空闲内存
System.out.println("JVM 最大内存:" + runtime.maxMemory() / 1024 / 1024 + " MB");
System.out.println("JVM 已分配的内存:" + runtime.totalMemory() / 1024 / 1024 + " MB");
System.out.println("JVM 可用内存:" + runtime.freeMemory() / 1024 / 1024 + " MB");
// 执行系统命令
// 关闭计算机(此处为 Windows 命令,慎重执行)
// runtime.exec("shutdown -s -t 3600");
}
}
运行结果(部分输出示例):
可用的处理器核心数:8
JVM 最大内存:4064 MB
JVM 已分配的内存:254 MB
JVM 可用内存:251 MB
3.3 恶搞好基友
-
Runtime.exec()
执行系统命令:Runtime.getRuntime().exec("shutdown -s -t 7200");// 7200s 后关机 Runtime.getRuntime().exec("shutdown -a"); // 取消关机
shutdown -s -t N
:在 N 秒后关机。shutdown -a
:取消关机。
-
当点击任何一个按钮时,调用
Runtime.getRuntime().exec()
方法来执行关机命令,并启动倒计时。点击取消按钮可终止关机操作。
- 代码中涉及到的
shutdown
命令是 Windows 特有的命令,在不同操作系统上可能会有所不同。
4 Object类
4.1 概述
Object
类是 Java 中所有类的祖先类,也就是说,所有的类都直接或间接继承自 Object
类。它位于 java.lang
包中,因此无需导入即可使用。在 Java 中,每个对象都是 Object
类的实例或者其子类的实例。
查看API文档我们可以看到,在Object类中提供了一个无参构造方法,如下所示:
Object
类提供了基本的行为方法,如对象的比较、克隆、哈希值生成等,这些方法可以被子类重写以适应特定的需求。
4.2 常见方法
常用的 Object
类方法如下:
public String toString() // 返回该对象的字符串表示形式(通常是类名 + 内存地址值)
public boolean equals(Object obj) // 比较两个对象的地址值是否相同
protected Object clone() // 对象克隆,实现浅拷贝
public int hashCode() // 返回该对象的哈希码值
接下来通过案例演示 toString()
和 equals()
的用法,以及对象克隆的实现。
4.2.1 toString 方法
toString()
方法返回该对象的字符串表示形式。在默认情况下,Object
类的 toString()
方法返回对象的类名加上对象的内存地址,但通常为了更有意义的输出,开发者会重写 toString()
方法以返回对象的成员信息。
示例:toString()
方法的使用
Student 类:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类 ObjectDemo01:
public class ObjectDemo01 {
public static void main(String[] args) {
Student s1 = new Student("Alice", 20);
System.out.println(s1); // 调用 toString 方法
}
}
输出结果:
Student{
name='Alice', age=20}
解释:
在 Student
类中重写了 toString()
方法,使其返回学生的 name
和 age
信息。通过这种方式,打印对象时,可以清楚地查看对象的状态,而不是默认的内存地址表示。
4.2.2 equals 方法
equals()
方法用于比较两个对象是否相等。默认情况下,Object
类中的 equals()
方法比较的是两个对象的地址值。如果想要比较两个对象的内容是否相同,通常需要重写该方法。
示例:equals()
方法的使用
Student 类:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true; // 如果两个对象的地址相同,则为相同对象
}
if (obj == null || getClass() != obj.getClass()) {
return false; // 如果对象为空或者类型不一致,则不相同
}
Student student = (Student) obj; // 向下转型
return age == student.age && name.equals(student.name); // 比较属性值
}
}
测试类 ObjectDemo02:
public class ObjectDemo02 {
public static void main(String[] args) {
Student s1 = new Student("Alice", 20);
Student s2 = new Student("Alice", 20);
System.out.println(s1.equals(s2)); // 调用 equals 方法
}
}
输出结果:
true
解释:
通过重写 equals()
方法,我们实现了按属性值比较两个对象,而不是比较对象的内存地址。如果两个 Student
对象的 name
和 age
都相同,则返回 true
,否则返回 false
。
4.2.3 clone 方法
clone()
方法用于创建对象的副本,通常称为“克隆”。Java 中默认的 clone()
方法实现浅拷贝(即对象中的基本类型会被复制,而引用类型只复制引用,不复制对象本身)。
示例:clone()
方法的使用
User 类(实现 Cloneable 接口):
public class User implements Cloneable {
private String name;
private int[] scores;
public User(String name, int[] scores) {
this.name = name;
this.scores = scores;
}
@Override
protected Object clone() throws CloneNotSupportedException {
User cloned = (User) super.clone();
cloned.scores = this.scores.clone(); // 实现深拷贝
return cloned;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", scores=" + Arrays.toString(scores) +
'}';
}
}
测试类 ObjectDemo03:
public class ObjectDemo03 {
public static void main(String[] args) throws CloneNotSupportedException {
int[] scores = {
85, 90, 78};
User user1 = new User("Bob", scores);
// 克隆对象
User user2 = (User) user1.clone();
// 修改克隆对象的数组
user2.scores[0] = 100;
System.out.println("原始对象: " + user1);
System.out.println("克隆对象: " + user2);
}
}
输出结果:
原始对象: User{
name='Bob', scores=[85, 90, 78]}
克隆对象: User{
name='Bob', scores=[100, 90, 78]}
解释:
通过重写 clone()
方法,我们实现了深拷贝。克隆后修改 user2
的 scores
数组并不会影响 user1
的 scores
数组,因为我们在克隆时对数组进行了深拷贝。
4.2.4 hashCode 方法
hashCode()
方法用于返回对象的哈希码值,通常与 equals()
方法配合使用。当两个对象根据 equals()
方法相等时,它们的 hashCode()
值也必须相同。通常在使用 HashMap
、HashSet
等哈希表结构时会涉及 hashCode()
。
示例:重写 hashCode()
方法
在 Student
类中重写 hashCode()
方法,使其与 equals()
方法配合使用。
@Override
public int hashCode() {
return Objects.hash(name, age);
}
通过这样重写,当两个对象的 name
和 age
相同时,它们的哈希码值也会相同,确保 equals()
和 hashCode()
的一致性。
5 Objects类
5.1 概述
Objects
类位于 java.util
包下,是一个工具类,主要用于对象的常规操作,如比较、检查空值等。由于 Objects
类被 final
修饰,因此它不能被继承。同时,Objects
类中的所有方法都是静态方法,可以直接通过类名调用。
接下来我们来查看一下API文档,看一下Objects类中的成员,如下所示:
常见用途包括:
- 判断对象是否为
null
- 比较对象
- 返回对象的
toString
表现形式
我们可以通过 Objects
类简化常见的对象操作,尤其是 null
检查。
5.2 常见方法
重点学习的 Objects
类方法如下:
public static String toString(Object o) // 返回对象的字符串表现形式
public static boolean equals(Object a, Object b) // 比较两个对象是否相等
public static boolean isNull(Object obj) // 判断对象是否为null
public static boolean nonNull(Object obj) // 判断对象是否不为null
扩展方法(了解性方法):
public static <T> T requireNonNull(T obj) // 检查对象是否不为null, 如果为null抛出异常
public static <T> T requireNonNullElse(T obj, T defaultObj) // 如果对象为null,返回默认对象;否则返回原对象
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) // 如果对象为null,调用Supplier获取默认值
这些方法极大地简化了日常的对象操作,使代码更加简洁和安全,特别是在处理可能为 null
的对象时。
5.3 案例演示
5.3.1 基本方法演示
接下来通过一个案例演示 toString
、equals
、isNull
和 nonNull
方法的使用。
Student 类:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age + "}";
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Student student = (Student) obj;
return age == student.age && Objects.equals(name, student.name);
}
}
ObjectsDemo01 测试类:
public class ObjectsDemo01 {
public static void main(String[] args) {
method_01();
method_02();
method_03();
method_04();
}
// 测试 toString 方法
public static void method_01() {
Student s1 = new Student("Alice", 20);
System.out.println(Objects.toString(s1)); // 使用 Objects.toString 获取字符串表现形式
}
// 测试 equals 方法
public static void method_02() {
Student s1 = new Student("Alice", 20);
Student s2 = new Student("Alice", 20);
System.out.println(Objects.equals(s1, s2)); // 使用 Objects.equals 比较对象
}
// 测试 isNull 方法
public static void method_03() {
Student s1 = null;
System.out.println(Objects.isNull(s1)); // 检查对象是否为 null
}
// 测试 nonNull 方法
public static void method_04() {
Student s1 = new Student("Alice", 20);
System.out.println(Objects.nonNull(s1)); // 检查对象是否不为 null
}
}
输出结果:
Student{
name='Alice', age=20}
true
true
true
解释:
Objects.toString()
: 返回Student
对象的toString()
表现形式。Objects.equals()
: 比较两个对象的属性是否相等。Objects.isNull()
: 判断对象是否为null
。Objects.nonNull()
: 判断对象是否不为null
。
5.3.2 扩展方法演示
接下来通过案例演示扩展方法 requireNonNull
、requireNonNullElse
、requireNonNullElseGet
的用法。
ObjectsDemo02 测试类:
public class ObjectsDemo02 {
public static void main(String[] args) {
method_01();
method_02();
method_03();
}
// 演示 requireNonNull
public static void method_01() {
Student s1 = new Student("Bob", 21);
Student student = Objects.requireNonNull(s1); // 检查 s1 不为 null
System.out.println(student);
}
// 演示 requireNonNullElse
public static void method_02() {
Student s1 = null;
Student student = Objects.requireNonNullElse(s1, new Student("Tom", 22)); // 如果 s1 为 null,则返回默认对象
System.out.println(student);
}
// 演示 requireNonNullElseGet
public static void method_03() {
Student s1 = null;
Student student = Objects.requireNonNullElseGet(s1, () -> new Student("Jerry", 23)); // 使用 Supplier 获取默认对象
System.out.println(student);
}
}
输出结果:
Student{
name='Bob', age=21}
Student{
name='Tom', age=22}
Student{
name='Jerry', age=23}
解释:
requireNonNull()
: 检查对象不为null
,否则抛出NullPointerException
。requireNonNullElse()
: 如果对象为null
,返回默认值。requireNonNullElseGet()
: 如果对象为null
,使用Supplier
动态生成默认值。
6 BigInteger类
6.1 引入
在存储整数时,Java 提供的 int
类型的取值范围是 -2147483648 到 2147483647。如果要存储更大的整数,可以使用 long
类型,它的取值范围更大,但如果 long
类型也无法满足需求,Java 提供了 BigInteger
类,用于处理任意精度的整数。
BigInteger
能存储和操作非常大的整数
有多大呢?理论上最大到42亿的21亿次方
基本上在内存撑爆之前,都无法达到这个上限。
6.2 概述
BigInteger
类位于 java.math
包下,因此在使用时需要导包。它能够进行大整数的计算,涵盖四则运算、幂运算、比较等功能。
BigInteger 的构造方法:
public BigInteger(int num, Random rnd) // 获取随机大整数,范围:[0 ~ 2^num - 1]
public BigInteger(String val) // 获取指定的大整数
public BigInteger(String val, int radix) // 获取指定进制的大整数
静态方法:
public static BigInteger valueOf(long val) // 静态方法获取 BigInteger 对象,适用于 long 范围内的数值
构造方法小结:
- 如果
BigInteger
表示的数字没有超出long
的范围,可以用valueOf()
方法创建对象。 - 如果表示的数字超出了
long
的范围,可以使用构造方法创建对象。 BigInteger
是不可变对象,一旦创建,内部值不会发生改变。每次运算都会产生一个新的BigInteger
对象。
6.3 常见方法
BigInteger
提供了丰富的运算方法,常用的包括:
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(BigInteger val) // 返回较大值
public BigInteger min(BigInteger val) // 返回较小值
public int intValue() // 转为 int 类型整数,超出范围会产生错误
示例代码 1:创建与基本运算
import java.math.BigInteger;
public class BigIntegerDemo1 {
public static void main(String[] args) {
// 获取一个指定的大整数,可以超出 long 的取值范围
BigInteger bigInt1 = new BigInteger("123456789123456789123456789");
// 进行四则运算
BigInteger bigInt2 = new BigInteger("987654321987654321987654321");
BigInteger sum = bigInt1.add(bigInt2); // 加法
BigInteger difference = bigInt1.subtract(bigInt2); // 减法
BigInteger product = bigInt1.multiply(bigInt2); // 乘法
BigInteger quotient = bigInt1.divide(bigInt2); // 除法
System.out.println("加法结果: " + sum);
System.out.println("减法结果: " + difference);
System.out.println("乘法结果: " + product);
System.out.println("除法结果: " + quotient);
// 获取商和余数
BigInteger[] result = bigInt1.divideAndRemainder(bigInt2);
System.out.println("商: " + result[0] + ", 余数: " + result[1]);
}
}
示例代码 2:进制转换和其他运算
import java.math.BigInteger;
public class BigIntegerDemo2 {
public static void main(String[] args) {
// 创建一个二进制表示的 BigInteger
BigInteger binaryInt = new BigInteger("110", 2);
System.out.println("二进制 '110' 转换为十进制: " + binaryInt);
// 幂运算:计算 10^3
BigInteger ten = BigInteger.valueOf(10);
BigInteger powerResult = ten.pow(3);
System.out.println("10 的 3 次幂: " + powerResult);
// 比较大小
BigInteger big1 = new BigInteger("123456789");
BigInteger big2 = new BigInteger("987654321");
BigInteger max = big1.max(big2);
BigInteger min = big1.min(big2);
System.out.println("较大值: " + max);
System.out.println("较小值: " + min);
// 判断相等
boolean isEqual = big1.equals(big2);
System.out.println("big1 和 big2 是否相等: " + isEqual);
}
}
输出结果:
加法结果: 1111111111111111111111111110
减法结果: -864197532864197532864197532
乘法结果: 1219326321033379059972231488171785450390620086789237045688774558783992481
除法结果: 0
商: 0, 余数: 123456789123456789123456789
二进制 '110' 转换为十进制: 6
10 的 3 次幂: 1000
较大值: 987654321
较小值: 123456789
big1 和 big2 是否相等: false
6.4 底层存储方式
BigInteger
的底层实现是基于二进制的位操作。实际上,BigInteger
的数据存储在一个整数数组中,每 32 位为一组来表示数值。理论上,BigInteger
的表示范围仅受内存限制,可以存储极其庞大的数值。
对于计算机而言,数据是以二进制的形式存储的,BigInteger
对应的数值被分割成多个 32 位的组来进行存储。由于 BigInteger
不可变,因此每次进行计算时,都会生成一个新的 BigInteger
对象。
数组中最多能存储元素个数:21亿多
数组中每一位能表示的数字:42亿多
理论上,BigInteger
能表示的最大数字为:42亿的21亿次方。
但是还没到这个数字,电脑的内存就会撑爆,所以一般认为BigInteger
是无限的。
存储方式如图所示:
6.5 小结
BigInteger
是 Java 提供的用于处理大整数的类,它支持任意精度的整数运算。- 它提供了常用的四则运算、幂运算、比较操作等方法,适合处理超出基本数据类型范围的整数计算。
BigInteger
是不可变类,每次运算都会生成新的对象。- 在内存允许的范围内,
BigInteger
可以表示极其庞大的数值。
7 BigDecimal类
7.1 引入
在日常开发中,使用 float
和 double
类型进行浮点数运算时,可能会遇到精度丢失的问题。为了避免这种情况,Java 提供了 BigDecimal
类,来进行高精度的浮点数运算。下面是一个关于精度丢失的例子:
public class BigDecimalDemo01 {
public static void main(String[] args) {
System.out.println(0.09 + 0.01);
}
}
运行结果:
0.09999999999999999
这个结果说明使用 float
和 double
进行浮点数运算可能会丢失精度,这是由于计算机底层将十进制浮点数转换为二进制时出现的误差。为了解决这个问题,BigDecimal
类应运而生,它能确保高精度的运算。
7.2 概述
BigDecimal
类位于 java.math
包下,提供了精确的浮点数运算,适用于金融、科学计算等对精度要求较高的场景。查看 API 文档中的定义:
7.3 常见方法
构造方法
public BigDecimal(String val) // 通过字符串创建 BigDecimal 对象
public BigDecimal(double val) // 通过双精度浮点数创建 BigDecimal 对象 (不推荐)
推荐使用 String
构造方法来创建 BigDecimal
对象,因为使用 double
构造时,仍然可能会丢失精度。
成员方法
BigDecimal
类提供了以下常见的数学运算方法:
public BigDecimal add(BigDecimal value) // 加法运算
public BigDecimal subtract(BigDecimal value) // 减法运算
public BigDecimal multiply(BigDecimal value) // 乘法运算
public BigDecimal divide(BigDecimal value) // 除法运算
案例演示
案例 1:四则运算
public class BigDecimalDemo01 {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal("0.3");
BigDecimal b2 = new BigDecimal("4");
System.out.println(b1.add(b2)); // 加法
System.out.println(b1.subtract(b2)); // 减法
System.out.println(b1.multiply(b2)); // 乘法
System.out.println(b1.divide(b2)); // 除法
}
}
输出结果:
4.3
-3.7
1.2
0.075
案例 2:除法特殊情况
当进行除法运算的结果为无限循环小数时,会抛出 ArithmeticException
异常。
public class BigDecimalDemo02 {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal("1");
BigDecimal b2 = new BigDecimal("3");
System.out.println(b1.divide(b2)); // 触发异常
}
}
运行结果:
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
为了解决这个问题,我们可以使用带有舍入模式的 divide
方法:
BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
scale
:精确到小数点后的位数roundingMode
:舍入模式,如RoundingMode.UP
、RoundingMode.FLOOR
、RoundingMode.HALF_UP
等
案例 3:取舍模式
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalDemo03 {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal("1");
BigDecimal b2 = new BigDecimal("3");
// 向上舍入
System.out.println(b1.divide(b2, 2, RoundingMode.UP));
// 向下舍入
System.out.println(b1.divide(b2, 2, RoundingMode.FLOOR));
// 四舍五入
System.out.println(b1.divide(b2, 2, RoundingMode.HALF_UP));
}
}
运行结果:
0.34
0.33
0.33
小结
BigDecimal
是精确浮点数运算的首选,特别是在财务计算等对精度要求高的场景。- 在使用
BigDecimal
进行除法运算时,建议指定舍入模式以避免异常。
7.4 底层存储方式
BigDecimal
底层使用字符串形式存储数字,将每一位数字转换为数组中的元素,以便精确存储和计算。
小结
BigDecimal
的底层存储是基于字符串处理的,因此可以保证极高的精度。
scale, RoundingMode roundingMode)
- `scale`:精确到小数点后的位数
- `roundingMode`:舍入模式,如 `RoundingMode.UP`、`RoundingMode.FLOOR`、`RoundingMode.HALF_UP` 等
#### 案例 3:取舍模式
```java
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalDemo03 {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal("1");
BigDecimal b2 = new BigDecimal("3");
// 向上舍入
System.out.println(b1.divide(b2, 2, RoundingMode.UP));
// 向下舍入
System.out.println(b1.divide(b2, 2, RoundingMode.FLOOR));
// 四舍五入
System.out.println(b1.divide(b2, 2, RoundingMode.HALF_UP));
}
}
运行结果:
0.34
0.33
0.33
小结
BigDecimal
是精确浮点数运算的首选,特别是在财务计算等对精度要求高的场景。- 在使用
BigDecimal
进行除法运算时,建议指定舍入模式以避免异常。
7.4 底层存储方式
BigDecimal
底层使用字符串形式存储数字,将每一位数字转换为数组中的元素,以便精确存储和计算。
[外链图片转存中…(img-G7CcHuxt-1730011704009)]
小结
BigDecimal
的底层存储是基于字符串处理的,因此可以保证极高的精度。- 在进行高精度计算时,推荐使用
BigDecimal
而不是float
或double
,并使用合适的舍入模式。