在Java中,负数的绝对值竟然不一定是正数!!!
绝对值是指一个数在数轴上所对应点到原点的距离,所以,在数学领域,正数的绝对值是这个数本身,负数的绝对值应该是他的相反数。
这几乎是每个人都知道的。
在Java中,想要获得有个数字的绝对值,可以使用java.lang.Math
中的abs
方法,这个类共有4个重载的abs方法,分别是:
public static int abs(int a) {
return (a < 0) ? -a : a;
}
public static long abs(long a) {
return (a < 0) ? -a : a;
}
public static float abs(float a) {
return (a <= 0.0F) ? 0.0F - a : a;
}
public static double abs(double a) {
return (a <= 0.0D) ? 0.0D - a : a;
}
以上4个方法分别返回int、long、float、double类型的绝对值,方法里面的逻辑也简单,无非就是整数直接返回,负数取相反数返回。
所以,基于以上所有的知识,我们经常会直接使用Math.abs
来对一个数字取绝对值。
在我们的代码中,也有很多这样的例子。
比如,我们需要用订单号做分库分表,但是订单号是字符串类型,所以,我们就需要取得这个字符换的hashCode,因为hashCode可能是负数,所以然后再对hashCode取绝对值,再用这个值去对分表数取模:
Math.abs(orderId.hashCode()) % 1024;
但是,上面这个逻辑是有问题的!!!
因为在极特殊情况下,上面的代码会得到一个负数的值。
这个极特殊情况下就是当hashCode是Integer.MIN_VALUE,即整数能表达的最小值的时候,可以代码验证下:
public static void main(String[] args) {
System.out.println(Math.abs(Integer.MIN_VALUE));
}
执行以上代码,得到的结果是:
-2147483648
很明显,这是个负数!!!
为什么会这样呢?
这要从Integer的取值范围说起,int的取值范围是-2^31 —— (2^31) - 1,即-2147483648 至 2147483647
那么,当我们使用abs取绝对值时候,想要取得-2147483648的绝对值,那应该是2147483648。
但是,2147483648大于了2147483647,即超过了int的取值范围。这时候就会发生越界。
2147483647用二进制的补码表示是:
01111111 11111111 11111111 11111111
这个数 +1 得到:
10000000 00000000 00000000 00000000
这个二进制就是-2147483648的补码。
虽然,这种情况发生的概率很低,只有当要取绝对值的数字是-2147483648的时候,得到的数字还是个负数。
那么,如何解决这个问题呢?
既然是以为越界了导致最终结果变成负数,那就解决越界的问题就行了,那就是在取绝对值之前,把这个int类型转成long类型,这样就不会出现越界了。
如,前面我们的分表逻辑修改为
Math.abs((long)orderId.hashCode()) % 1024;
就万无一失了。
大家可以执行下以下代码:
public static void main(String[] args) {
System.out.println(Math.abs((long)Integer.MIN_VALUE));
}
得到的结果就是:
2147483648
以上,就是今天要介绍的知识点了。
但是,一定要记得,对long类型取绝对值其实也可能存在这个情况哦!只不过发生的概率就更低了,但是只要他存在,就有可能发生哦!
关注公众号【Hollis】,后台回复"成神导图"可以咯领取Java工程师进阶思维导图。
在Java中,负数的绝对值竟然不一定是正数!!!的更多相关文章
- java中负数的补码转换为十进制
一个数如果为正,则它的原码.反码.补码相同:一个正数的补码,将其转化为十进制,可以直接转换. 已知一个负数的补码,将其转换为十进制数,步骤: 1.先对各位取反: 2.将其转换为十进制数: 3.加上负号 ...
- Java中正数与负数操作>>、>>>的区别
以下为个人理解,有不对的地方请提出 Java中,>>.>>>都是在数字的二进制的补码中进行的 正数的补码为本身 如33的二进制表示为 00000000 00000000 ...
- (转) Java中的负数及基本类型的转型详解
(转) https://my.oschina.net/joymufeng/blog/139952 面这行代码的输出是什么? 下面两行代码的输出相同吗? 请尝试在Eclipse中运行上面的两个代码片段, ...
- Java中正负数的存储方式-正码 反码和补码
Java中正负数的存储方式-正码 反码和补码 正码 我们以int 为例,一个int占用4个byte,32bits 0 存在内存上为 00000000 00000000 00000000 0000000 ...
- JAVA中计算两个日期时间的差值竟然也有这么多门道
上半年春招的时候,作为面试官,对于面试表现的不错的同学会要求其写一小段代码看看.题目很简单: 给定一个日期,然后计算下距离今天相差的天数. 本以为这么个问题就是用来活跃面试氛围的,但是结果却让人大跌眼 ...
- 我说精通字符串,面试官竟然问我 Java 中的 String 有没有长度限制?
String 是 Java 中很重要的一个数据类型,除了基本数据类型以外,String 是被使用的最广泛的了,但是,关于 String,其实还是有很多东西容易被忽略的. 就如本文我们要讨论的问题:Ja ...
- Java中的数是用补码表示的检验
一.基本介绍(关于下列五个定义来自http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html#!comments,谢原 ...
- JAVA中分为基本数据类型及引用数据类型
一.基本数据类型: byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0 short:短整型,在内存中占16位,即2个字节,取值范围-32768 ...
- java中的二进制
(1)按位与运算 & 1 & 1 = 1, 0 & 1 = 0 51 & 5 即 0011 0011 & 0000 0101 =0000 0001 = 1 ...
随机推荐
- C++标准模板库(STL)——set常见用法详解
set的定义 set<typename> name; typename可以是任何基本类型,如int.double.char.结构体等,也可以是STL标准容器,如vector.set.que ...
- 工作流Activiti框架中的LDAP组件使用详解!实现对工作流目录信息的分布式访问及访问控制
Activiti集成LDAP简介 企业在LDAP系统中保存了用户和群组信息,Activiti提供了一种解决方案,通过简单的配置就可以让activit连接LDAP 用法 要想在项目中集成LDAP,需要在 ...
- 权限管理(基本权限、附加权限、ACL权限)
基本权限 •访问方式(权限) 读取:允许查看内容-read r 写入:允许修改内容-write w 可执行:允许运行和切换-execute x 对于文本文件 r: cat head ...
- Webflux(史上最全)
文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...
- WPF中ListView控件怎么添加新的tiem时滚动条一直在最下面
listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1])
- 《手把手教你》系列基础篇之(三)-java+ selenium自动化测试- 启动三大浏览器(上)(详细教程)
1.简介 前边宏哥已经将环境搭建好了,今天就在Java项目搭建环境中简单地实践一下: 启动三大浏览器.按市场份额来说,全球前三大浏览器是:IE.Firefox.Chrome.因此宏哥这里主要介绍一下如 ...
- Vue.js的基础学习
Vue.js的基础网上很多,这里不记录 开始正式页面的开发 1.页面加载时请求数据 methods: { post() { //发送post请求 this.$http.post('../../ashx ...
- 『无为则无心』Python基础 — 16、Python序列之字符串的下标和切片
目录 1.序列的概念 2.字符串的下标说明 3.字符串的切片说明 1.序列的概念 序列sequence是Python中最基本的数据结构.指的是一块可存放多个值的连续内存空间,这些值按一定顺序排列,可通 ...
- 使用远程Docker进行集成测试
目录 需求背景 使用docker进行环境搭建 以中心化的docker server改进集成测试 Docker Server远程链接配置 Testcontainers 框架 Testcontainers ...
- Unity触发碰撞
原文链接:Unity触发碰撞介绍 3D触发器与碰撞器 触发信息检测: 1.MonoBehaviour.OnTriggerEnter(Collider collider)当进入触发器 2.MonoBeh ...