JavaAPI常用类型(包装类、BigDecimal类)
包装类
java语言是面向对象的语言,但是其中的八大基本数据类型不符合面向对象的特征。
因此java为了弥补这样的缺点,为这八种基本数据类型专门设计了八种符合面向对象特征的的类型,这八种具有面向对象特征的类型,统称为包装类,英文单词:wrapper class。
包装类,就是在类的内部,维护了一个基本数据类型的成员变量,以及其他方法,常量等。比如int对应的包装类Integer的部分源码如下:
public final class Integer extends Number implements Comparable<Integer> {
public static final int MIN_VALUE = 0x80000000;
public static final int MAX_VALUE = 0x7fffffff;
private final int value;
public Integer(int value) {this.value = value;}
public Integer(String s) throws NumberFormatException {this.value = parseInt(s, 10);}public static String toHexString(int i) {}
public static String toOctalString(int i) {}
public static String toBinaryString(int i) {}public static int parseInt(String s) throws NumberFormatException {}
public static Integer valueOf(String s) throws NumberFormatException {}
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
public int compareTo(Integer anotherInteger) {}
public static int max(int a, int b) {
return Math.max(a, b);
}
public static int min(int a, int b) {
return Math.min(a, b);
}
//.....
}
所有的基本数据类型和包装类型的对比,参考如下:
| 基本数据类型 | 包装类型 |
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| boolean | Boolean |
| char | Character |
装箱和拆箱
在使用包装类型时,涉及到两个概念:
1. 装箱操作: 基本数据类型 变成其对应的包装类型对象
--第一种方式: 调用包装类的构造器
--第二种方式: 调用工具方法valueOf(....)
2. 拆箱操作: 包装类对象转成其对应的基本数据类型的值
--对象调用xxxValue(),返回对应的基本数据类型的值
装箱操作:
int age = 10;
Integer a1 = new Integer(age); // 装箱操作
Integer a2 = new Integer(11); // 装箱操作
Integer a3 = Integer.valueOf(100); // 装箱操作
// 比较a1和a3
boolean r = a1.equals(a3);
System.out.println("比较结果:"+r); //比较结果:false
Integer a4 =Integer.valueOf("1001"); // int value
System.out.println(a4); //1001拆箱操作:
int i1 = a1.intValue(); // 拆箱操作, 由对象转成值。
int i2 = a2.intValue();
int i3 = a3.intValue();
int i4 = a4.intValue();
System.out.println(i1+","+i2+","+i3+","+i4); //10,11,100,1001
自动装箱和拆箱
为了方便获取包装类对象,从jdk1.5以后,提供了一个自动装箱的操作,也提供了一个包装类到基本数据类的自动拆箱操作。
自动装箱 : 直接使用一个基本数据类型的变量或字面值给一个包装类型的引用进行赋值即可
自动的装箱 : 省略掉的是 valueOf 方法
eg:
Integer age = 10; // 实际上,底层帮助我们调用了工具方法valueOf(....)
double scores = 100;
Double d1 = scores; // 自动装箱。
自动拆箱 : 直接使用一个包装类型的引用给一个基本数据类型的变量进行赋值即可
自动的拆箱 : 省略掉的是 xxValue 方法
eg:
Byte b1 = new Byte("88");
byte r1 = b1; // 实际上,底层帮助我们调用了byteValue()方法,来拆箱
int num1 = new Integer(100); // 发生了自动拆箱操作,对象调用了intValue()方法
包装类的常量池
为什么有常量池:为了减少内存的开销,以及提高个别对象的使用率。
对于装箱操作后的包装类的对象,jvm在堆中,维护了一个常量池。
该常量池适用于调用了valueOf()方法产生的包装类对象,以及自动装箱的包装类对象。
不适用于new关键字创建的包装类对象。
Byte, Short, Integer, Long :默认创建了数值 [-128, 127] 的相应类型的缓存数据,
Character :创建了数值在 [0, 127] 范围的缓存数据,
Boolean : 直接返回 true 或 false。Float, Double :没有实现常量池技术。
Integer i1 = 100; //自动装箱了, 先去常量池中查找是否有和100这个值相同的对象,没有,因此就在常量池创建该对象,返回地址。
Integer i2 = Integer.valueOf("100"); //先去常量池中查找是否有和100这个值相同的对象,有,因此返回的是常量池中对象的地址
System.out.println(i1 == i2); //true
//验证范围
Integer i3 = 128; //128装箱后,并没有进入常量池,而是在堆中。
Integer i4 = 128; //128自动装箱后,也是在堆中。
System.out.println(i3 == i4); //两个地址不相同
//验证new出来的对象
Integer i5 = new Integer(100);
System.out.println(i1 == i5); //因为是false,所以证明了new出来的对象不在常量池中,在堆中。
//验证Character 和 Boolean
Character c1 = 97;
Character c2 = 97;
System.out.println(c1 == c2); //true, 所以在常量池中
Boolean f = true;
Boolean g = true;
System.out.println(f == g); //true , 所以在常量池中
//验证Float和Double
System.out.println(4-3.9); //0.10000000000000009精度不准
Float f1 = 4f-3.9f;
Float f2 = 0.1f;
System.out.println(f1 == f2); //false 验证了没有常量池
System.out.println(f1.equals(f2)); // false 两个浮点型比较,也包含了精确度。
包装类其他常用方法
成员方法: xxxValue() ,用来拆箱,但是现在用的少,一般都是自动拆箱
工具方法:
static WrapperClassName valueOf(xxx value)
static WrapperClassName valueOf(String value)
static xxx parseXXX(String value)
static String toBinaryString(); 转成二进制
static String toHexString(); 转成16进制
static String toOctalString() 转成8进制
eg:
//手动装箱方法,使用的也少,目的就是装箱成包装类对象
Double v = Double.valueOf("3002.15"); //手动装箱
//从控制台上扫描一个纯数字的字符串
String line = "1201";
int i = Integer.parseInt(line);
System.out.println(i+1);
line = "1000.123";
double d1 = Double.parseDouble(line);
System.out.println(d1);//获取int的最大值和最小值。
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);//转成其他进制
int num = 1001;
System.out.println(Integer.toBinaryString(num)); //1111101001
System.out.println(Integer.toOctalString(num)); // 1751
System.out.println(Integer.toHexString(num)); // 3e9
BigDecimal类
前面提到浮点数运算时容易精度不准确,因此java提供了BigDecimal这个类来完善这类运算,运算可以非常精确,精确到小数点后无数位。
BigDecimal 通常支持任意位数的小数部分,用来对超过16位有效位的数进行精确的运算,(float可以精确到7左右,double是15位左右)
BigInteger: 表示大整数。一般用来处理非常大的数字,大到long也表示不了的数字。
常用构造器
BigDecimal(int val) 创建一个具有参数所指定整数值的对象。
BigDecimal(double val) 创建一个具有参数所指定双精度值的对象。不推荐使用,因为存在精度丢失问题
BigDecimal(long val) 创建一个具有参数所指定长整数值的对象。
BigDecimal(String val) 创建一个具有参数所指定以字符串表示的数值的对象 推荐使用
常用方法
BigDecimal add(BigDecimal other); BigDecimal对象中的值相加,返回BigDecimal对象
BigDecimal subtract(BigDecimal other);BigDecimal对象中的值相减,返回BigDecimal对象
BigDecimal multiply(BigDecimal other);BigDecimal对象中的值相乘,返回BigDecimal对象
BigDecimal divide(BigDecimal other): 做除法时要注意,除数不能是0, 不能出现除不尽的情况,不然都会报异常。
xxx xxxValue() : 将BigDecimal对象中的值转换成相应的基本数据类型
String toString(): 有必要时使用科学计数法。
//想要计算10和20的和
BigDecimal b1 = new BigDecimal("10");
BigDecimal b2 = new BigDecimal("20");
BigDecimal v = b1.add(b2);
System.out.println(v); // 调用了重写的toString,返回字符串样子。
//或者调用xxxValue方法
System.out.println(v.intValue()+1); //
//减法操作
BigDecimal subtract = b1.subtract(b2);
System.out.println(subtract);
//乘法操作
BigDecimal multiply = b1.multiply(b2);
System.out.println(multiply);
//除法操作
BigDecimal b3 = new BigDecimal("10");
BigDecimal b4 = new BigDecimal("200");
BigDecimal divide = b3.divide(b4,1,BigDecimal.ROUND_HALF_DOWN);
System.out.println(divide);
常用的舍入模式
BigDecimal.setScale() 方法用于格式化小数点
setScale(1) 表示保留一位小数,默认用四舍五入方式setScale(1,BigDecimal.ROUND_DOWN) 直接删除多余的小数位,如2.35会变成2.3
setScale(1,BigDecimal.ROUND_UP) 进位处理,2.32变成2.4
setScale(1,BigDecimal.ROUND_HALF_UP) 四舍五入,2.35变成2.4
setScaler(1,BigDecimal.ROUND_HALF_DOWN) 五舍六入,2.35变成2.3,如果是5则向下舍
setScaler(1,BigDecimal.ROUND_CEILING) 接近正无穷大的舍入
setScaler(1,BigDecimal.ROUND_FLOOR) 接近负无穷大的舍入,数字>0和ROUND_UP作用一样,数字<0和ROUND_DOWN作用一样
setScaler(1,BigDecimal.ROUND_HALF_EVEN) 向最接近的数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。setScaler(1,BigDecimal.ROUND_UNNECESSARY)计算结果是精确的,不需要舍入模式。如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。
常见问题:
创建 BigDecimal精度丢失的坑
在BigDecimal 中提供了多种创建方式,可以通过new 直接创建,也可以通过 BigDecimal.valueOf 创建。这两种方式使用不当,也会导致精度问题。如下:
public static void main(String[] args) throws Exception {
BigDecimal b1= new BigDecimal(0.1);
System.out.println(b1);
BigDecimal b2= BigDecimal.valueOf(0.1);
System.out.println(b2);
BigDecimal b3= BigDecimal.valueOf(0.111111111111111111111111111234);
System.out.println(b3);
}
执行结果:
0.1000000000000000055511151231257827021181583404541015625
0.1
0.1111111111111111
上面示例中两个方法都传入了double类型的参数0.1
但是 b1 还是出现了精度的问题。造成这种问题的原因是 0.1 这个数字计算机是无法精确表示的,送给 BigDecimal 的时候就已经丢精度了。
而 BigDecimal.valueOf 的实现却完全不同,如下源码所示,BigDecimal.valueOf 中是把浮点数转换成了字符串来构造的BigDecimal,因此避免了问题。
public static BigDecimal valueOf(double val) {
return new BigDecimal(Double.toString(val));
}
第一,在使用BigDecimal构造函数时,尽量传递字符串而非浮点类型;
第二,如果无法满足第一条,则可采用BigDecimal.valueOf方法来构造初始化值。
但是valueOf受double类型精度影响,当传入参数小数点后的位数超过double允许的16位精度还是可能会出现问题的。
等值比较的坑
一般在比较两个值是否相等时,都是用equals 方法,
但是,在BigDecimal 中使用equals可能会导致结果错误,
BigDecimal 中提供了 compareTo 方法,在很多时候需要使用compareTo 比较两个值。
如下所示:
public static void main(String[] args){
BigDecimal b1 = new BigDecimal("1.0");
BigDecimal b2 = new BigDecimal("1.00");
System.out.println(b1.equals(b2));
System.out.println(b1.compareTo(b2));
}
执行结果
false
0
出现此种结果的原因是,equals不仅比较了值是否相等,还比较了精度是否相同。
示例中,由于两个值的精度不同,所有结果也就不相同。
而 compareTo 是只比较值的大小。
返回的值为-1(小于),0(等于),1(大于)。
无限精度的坑
BigDecimal 并不代表无限精度,当在两个数除不尽的时候,就会出现无限精度的坑
如下所示:
public static void main(String[] args){
BigDecimal b1 = new BigDecimal("1.0");
BigDecimal b2 = new BigDecimal("3.0");
b1.divide(b2);
}Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1693)
at com.demo.controller.Test.main(Test.java:29)
如果在除法(divide)运算过程中,如果商是一个无限小数(如 0.333…),而操作的结果预期是一个精确的数字,那么将会抛出ArithmeticException异常。
此种情况,只需要在使用 divide方法时指定结果的精度即可:
public static void main(String[] args){
BigDecimal b1 = new BigDecimal("1.0");
BigDecimal b2 = new BigDecimal("3.0");
System.out.println(b1.divide(b2,2, RoundingMode.HALF_UP));//0.33
}
在使用BigDecimal进行(所有)运算时,尽量指定精度和舍入模式。
相关文章:
JavaAPI常用类型(包装类、BigDecimal类)
包装类 java语言是面向对象的语言,但是其中的八大基本数据类型不符合面向对象的特征。 因此java为了弥补这样的缺点,为这八种基本数据类型专门设计了八种符合面向对象特征的的类型,这八种具有面向对象特征的类型,统称为包装类&a…...
项目中一些不理解的问题
1.Mybatis是干啥的 他是用来帮我们操作数据库的,相当于是我们的一个助手: 我们想要得到数据库中的什么数据,就可以告诉mybatis,他会给我们想要的结果,同时,我们想要对数据库做出什么操作,也可…...
数字化转型4化:标准化奠基-信息化加速-数字化赋能-智能化引领
随着经济增速的放缓,大国体系所催生的生产力逐渐释放,后续业务的发展愈发需要精耕细作,精益理念也必须深入企业的骨髓。与此同时,在全球经济一体化的大背景下,企业面临着来自国内外同行,甚至是跨行业的激…...
Lineageos 22.1(Android 15) 开机向导制作
一、前言 开机向导原理其实就是将特定的category的Activity加入ComponentResolver,如下 <category android:name"android.intent.category.SETUP_WIZARD"/>然后我们开机启动的时候,FallbackHome结束,然后启动Launcher的时候…...
“让App玩捉迷藏:Android教育平板的‘隐身术’开发实录”
1. 前言:一场App的“消失魔术” 在定制教育平板时,客户要求:“朕要某些App在桌面上消失,只能在系统设置里当个‘幽灵’,而朕一声令下,它们又得原地复活!”于是,程序员们翻开了Androi…...
简单易懂,解析Go语言中的Channel管道
Channel 管道 1 初始化 可用var声明nil管道;用make初始化管道; len(): 缓冲区中元素个数, cap(): 缓冲区大小 //变量声明 var a chan int //使用make初始化 b : make(chan int) //不带缓冲区 c : make(chan stri…...
C++基础知识学习记录—模版和泛型编程
1、模板 概念: 模板可以让类或者函数支持一种通用类型,在编写时不指定固定的类型,在运行时才决定是什么类型,理论上讲可以支持任何类型,提高了代码的重用性。 模板可以让程序员专注于内部算法而忽略具体类型&#x…...
已解决IDEA无法输入中文问题(亲测有效)
前言 在使用IDEA的时候,比如我们想写个注释,可能不经意间,输入法就无法输入中文了,但是在其他地方打字,输入法仍然能够正常工作。这是什么原因呢,这篇文章带你解决这个问题! 快捷键 如果你的I…...
人工智能之目标追踪DeepSort源码解读(yolov5目标检测,代价矩阵,余弦相似度,马氏距离,匹配与预测更新)
要想做好目标追踪,须做好目标检测,所以这里就是基于yolov5检测基础上进行DeepSort,叫它为Yolov5_DeepSort。整体思路是先检测再追踪,基于检测结果进行预测与匹配。 一.参数与演示 这里用到的是coco预训练人的数据集: 二.针对检测结果初始化track 对每一帧数据都输出…...
Copilot基于企业PPT模板生成演示文稿
关于copilot创建PPT,咱们写过较多文章了: Copilot for PowerPoint通过文件创建PPT Copilot如何将word文稿一键转为PPT Copilot一键将PDF转为PPT,治好了我的精神内耗 测评Copilot和ChatGPT-4o从PDF创建PPT功能 Copilot for PPT全新功能&a…...
使用GDI+、文件和目录和打印API,批量将图片按文件名分组打包成PDF
代码写了两个小时,速度太慢(包括学习文档的时间) #include <stdio.h> #include <Windows.h> #include <gdiplus.h> #include <string.h> using namespace Gdiplus; #pragma comment(lib, "Gdiplus.lib") …...
【Linux】【网络】Libevent基础
【Linux】【网络】Libevent基础 libevent 是轻量级 c语言实现的 网络io库 能够跨平台 且线程安全 是单线程的 libevent 的使用过程通常包括几个主要步骤: 1.创建Libevent实例2.注册事件、添加事件、设置处理事件回调函数3.启动事件循环4.清理资源 1. 创建Libeven…...
MySQL 主从复制原理及其工作过程
一、MySQL主从复制原理 MySQL 主从复制是一种将数据从一个 MySQL 数据库服务器(主服务器,Master)复制到一个或多个 MySQL 数据库服务器(从服务器,Slave)的技术。以下简述其原理,主要包含三个核…...
nginx负载均衡, 解决iphash不均衡的问题之consistent
原因分析 客户端IP分布不均:部分IP段请求集中,导致哈希到同一后端。 服务器数量变动:增删节点时,传统ip_hash未使用一致性哈希,导致分布重置。 哈希键范围过小:例如仅使用IPv4前24位,不同IP可…...
MySQL远程连接配置
一、配置TCP服务地址绑定 配置文件路径 /etc/mysql/mysql.cnf /etc/mysql/mysql.conf.d/mysqld.cnf具体文件可以通过 mysql --help查看 配置项 # 只接受本地连接 bind-address 127.0.0.1 mysqlx-bind-address 127.0.0.1改为 # 接受任意IP地址连接 bind-address …...
Langchain vs. LlamaIndex:哪个在集成MongoDB并分析资产负债表时效果更好?
Langchain vs. LlamaIndex:哪个在集成MongoDB并分析资产负债表时效果更好? 随着大语言模型(LLM)在实际应用中的普及,许多开发者开始寻求能够帮助他们更高效地开发基于语言模型的应用框架。在众多框架中,La…...
iOS开发书籍推荐 - 《高性能 iOS应用开发》(附带链接)
引言 在 iOS 开发的过程中,随着应用功能的增加和用户需求的提升,性能优化成为了不可忽视的一环。尤其是面对复杂的界面、庞大的数据处理以及不断增加的后台操作,如何确保应用的流畅性和响应速度,成为开发者的一大挑战。《高性能 …...
Excel核心函数VLOOKUP全解析:从入门到精通
一、函数概述 VLOOKUP是Excel中最重要且使用频率最高的查找函数之一,全称为Vertical Lookup(垂直查找)。该函数主要用于在数据表的首列查找特定值,并返回该行中指定列的对应值。根据微软官方统计,超过80%的Excel用户在…...
leetcode1047-删除字符串中的所有相邻重复项
leetcode 1047 思路 因为要删除字符串中的所有相邻重复项,那么在删除完成后,最后返回的元素中是不应该存在任何相邻重复项的,如果是普通的遍历,假设str ‘abbaca’,遍历出来只发现中间的bb是相邻重复的删除了以后a…...
解决DeepSeek服务器繁忙问题的实用指南
目录 简述 1. 关于服务器繁忙 1.1 服务器负载与资源限制 1.2 会话管理与连接机制 1.3 客户端配置与网络问题 2. 关于DeepSeek服务的备用选项 2.1 纳米AI搜索 2.2 硅基流动 2.3 秘塔AI搜索 2.4 字节跳动火山引擎 2.5 百度云千帆 2.6 英伟达NIM 2.7 Groq 2.8 Firew…...
软件工程之软件需求SWE.1
物有本末,事有终始。知所先后,则近道矣。对软件开发而言,软件需求乃重中之重。必先之事重千钧,不可或缺如日辰。 汽车行业由于有方法论和各种标准约束,对软件开发有严苛的要求。ASPICE指导如何审核软件开发࿰…...
【面试题】redis大key问题怎么解决?(key访问的次数比较多,key存的数据比较大)
针对 Redis 中大 Key(数据量大且访问频繁)的问题,需从 数据拆分、访问优化、架构设计 等多维度综合解决。以下是具体方案及实施步骤: 一、大 Key 的定义与危害 定义: Value 过大:如 String 类型 Value >…...
web入侵实战分析-常见web攻击类应急处置实验1
场景说明: 某天运维人员发现在/opt/tomcat8/webapps/test/目录下,多出了一个index_bak.jsp这个文件, 并告诉你如下信息 操作系统:ubuntu-16.04业务:测试站点中间件:tomcat开放端口:22&#x…...
【Kubernetes】k8s 部署指南
1. k8s 入门 1.1 k8s 简介 需要最需要明确的就是:kubernetes(简称 k8s ) 是一个 容器编排平台 ,换句话说就是用来管理容器的,相信学过 Docker 的小伙伴对于容器这个概念并不陌生,打个比方:容器…...
深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作
一、问题背景(传统爬虫的痛点) 数据采集是现代网络爬虫技术的核心任务之一。然而,传统爬虫面临多重挑战,主要包括: 反爬机制:许多网站通过检测请求头、IP地址、Cookie等信息识别爬虫,进而限制…...
iOS事件传递和响应
背景 对于身处中小公司且业务不怎么复杂的程序员来说,很多技术不常用,你可能看过很多遍也都大致了解,但是实际让你讲,不一定讲的清楚。你可能说,我以独当一面,应对自如了,但是技术的知识甚多&a…...
JDK最详细安装教程,零基础入门到精通,收藏这篇就够了
目录 一、下载与安装二、配置环境三、验证是否配置成功 一、下载与安装 1、下载地址 http://www.oracle.com/technetwork/java/javase/downloads/index.html 2、选择自己想要的版本下载,并且选择自己电脑对应的版本下载 3、下载完成之后,双击打开然后…...
深研究:与Dify建立研究自动化应用
许多个人和团队面临筛选各种网页或内部文档的挑战,以全面概述一个主题。那么在这里我推荐大家使用Dify,它是一个用于LLM应用程序开发的低代码,开源平台,它通过自动化工作流程的多步搜索和有效汇总来解决此问题,仅需要最小的编码。 在本文中,我们将创建“ Deepresearch”…...
新手向:SpringBoot后端查询到数据,前端404?(附联调时各传参方式注解总结-带你一文搞定联调参数)
前言: 在 Spring Boot 项目开发中,后端小伙伴可能经常遇到这样诡异的场景: 后台日志显示查询到了数据,但前端却一脸懵逼地告诉你 404 Not Found?接口明明写好了,Postman 直接访问却提示找不到?…...
Mysql各操作系统安装全详情
" 至高无上的命运啊~ " MySQL是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的RDBMS (Relational Database Mana…...
