java中大整型BigInteger及setBit和testBit方法
最近在修改公司之前的项目,在项目中遇到了权限校验的问题,代码中出现了BigInteger的setBit()testBit()方法,之前未接触过,所以了解了下BigInteger。
在Java中,由CPU原生提供的整型最大范围是64位long
型整数。使用long
型整数可以直接通过CPU指令进行计算,速度非常快。
如果我们使用的整数范围超过了long
型怎么办?这个时候,就只能用软件来模拟一个大整数。java.math.BigInteger
就是用来表示任意大小的整数。BigInteger
内部用一个int[]
数组来模拟一个非常大的整数:
BigInteger bi = new BigInteger("1234567890");
System.out.println(bi.pow(5)); // 2867971860299718107233761438093672048294900000
对BigInteger
做运算的时候,只能使用实例方法,例如,加法运算:
BigInteger i1 = new BigInteger("1234567890");
BigInteger i2 = new BigInteger("12345678901234567890");
BigInteger sum = i1.add(i2); // 12345678902469135780
和long
型整数运算比,BigInteger
不会有范围限制,但缺点是速度比较慢。
也可以把BigInteger
转换成long
型:
BigInteger i = new BigInteger("123456789000");
System.out.println(i.longValue()); // 123456789000System.out.println(i.multiply(i).longValueExact()); // java.lang.ArithmeticException: BigInteger out of long range
使用longValueExact()
方法时,如果超出了long
型的范围,会抛出ArithmeticException
。
BigInteger
和Integer
、Long
一样,也是不可变类,并且也继承自Number
类。因为Number
定义了转换为基本类型的几个方法:
转换为
byte
:byteValue()
转换为
short
:shortValue()
转换为
int
:intValue()
转换为
long
:longValue()
转换为
float
:floatValue()
转换为
double
:doubleValue()
因此,通过上述方法,可以把BigInteger
转换成基本类型。如果BigInteger
表示的范围超过了基本类型的范围,转换时将丢失高位信息,即结果不一定是准确的。如果需要准确地转换成基本类型,可以使用intValueExact()
、longValueExact()
等方法,在转换时如果超出范围,将直接抛出ArithmeticException
异常。
知道了BigInteger的概念,运算也和之前的BigDecimal很像,第一次看到BigInteger,还是学的不够多啊 这样的知识居然现在才发现。
再说说setBit()和testBit()方法
在项目中是使用BigInteger的这两个方法来进行权限效验的,利用菜单id生成对应权限效验码,把具体的权限设置为一个正整数值,如果一个用户有多个权限的话,比如1,2权限,那么我们设置值的时候就是num.setBit(1),num.setBit(2),然后把返回的num值保存在session中,要验证是否有权限的话,只要从session中取得保存的num,然后执行下num.test(权限值),如果返回true就是有权限的,否则无权限。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
/** * 利用BigInteger对权限进行2的权的和计算 * * @param rights String型权限编码数组 * @return 2的权的和 */ public static BigInteger sumRights(String[] rights) { BigInteger num = new BigInteger( "0" ); for ( int i = 0 ; i < rights.length; i++) { num = num.setBit(Integer.parseInt(rights[i])); } return num; } /** * 测试是否具有指定编码的权限 * * @param sum * @param targetRights * @return */ public static boolean testRights(String sum, int targetRights) { if (Tools.isEmpty(sum)) return false ; return testRights( new BigInteger(sum), targetRights); } public static void main(String[] args) { System.out.println(testRights( new BigInteger( "8148143905337944345073782753637512644205873574663745002544561797417525199053346824733589504" ), 302 )); BigInteger num = new BigInteger( "0" ); num = num.setBit( 302 ); System.out.println(num); } |
testBit方法代码
1
2
3
4
5
6
|
public boolean testBit( int n) { if (n < 0 ) throw new ArithmeticException( "Negative bit address" ); return (getInt(n >>> 5 ) & ( 1 << (n & 31 ))) != 0 ; } |
意思就是将1左移n位,与this做&运算,其实就是判断当前数(要写成二进制)第n+1位上的数是不是为1,是的话返回true
setBit方法代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public BigInteger setBit( int n) { if (n < 0 ) throw new ArithmeticException( "Negative bit address" ); int intNum = n >>> 5 ; int [] result = new int [Math.max(intLength(), intNum+ 2 )]; for ( int i= 0 ; i < result.length; i++) result[result.length-i- 1 ] = getInt(i); result[result.length-intNum- 1 ] |= ( 1 << (n & 31 )); return valueOf(result); } |
意思就是将1左移n位,与this对象做|运算,这样的话,就会将this的二进制格式的第n+1位的数变为1.这样很明显就和上一个方法形成一对,
n可以作为某个功能编号,而角色可以使用setBit的方法设置编号,然后使用testBit来测试是不是含有n编号的功能。
如果每次有添加多个新的功能,那么就用这些功能编号依次给原来的角色编号执行setBit得到新的角色编号。
利用这两个方法进行权限效验解析:
假设我的数据库总共有4个菜单 4个账户
id 菜单名称 id 菜单权限值 转换为二进制
1 菜单1 1 6 1 1 0
2 菜单2 2 12 1 1 0 0
3 菜单3 3 26 1 1 0 1 0
4 菜单4 4 30 1 1 1 1 0
假如账户A 有菜单1 菜单2 的权限, 权限值=2^1+2^2=6
账户B 有菜单2 菜单3 的权限, 权限值=2^2+2^3=12
账户C 有菜单1 菜单3 菜单4 的权限, 权限值=2^1+2^3+2^4=26
账户D 有菜单1 菜单2 菜单3 菜单4 的权限, 权限值=2^1+2^2+2^3+2^4=30
大家可以观察一下这些权限值转换为二进制数后的规律(假如把这些二进制数从右往左转换成一个bolean数组,1 代表 false 2 代表true),看上图的转换后的二进制,我们来看这个数组
0 1 2 3 4
账户A F T T F F
账户B F F T T F
账户C F T F T T
账户D F T T T T
把上面的 1 2 3 4 看成是菜单ID,T 和 F看成表示是否有该菜单权限,你们应该能发现其中的奥妙!(现在应该也可以说明为什么菜单ID必须为正整数了。。)
java中大整型BigInteger及setBit和testBit方法的更多相关文章
- JAVA 长整型转换为IP地址的方法
JAVA 长整型转换为IP地址的方法 代码例如以下: /** * 整型解析为IP地址 * @param num * @return */ public static String int2iP(Lon ...
- (转)JAVA的整型与字符串相互转换
JAVA的整型与字符串相互转换1如何将字串 String 转换成整数 int? A. 有两个方法: 1). int i = Integer.parseInt([String]); 或 ...
- 深入理解Java的整型类型:如何实现2+2=5?
先看下这段神奇的Java代码: public static void main(String[] args) throws Exception { doSomethingMagic(); System ...
- 为什么阿里巴巴Java开发手册中强制要求整型包装类对象值用 equals 方法比较?
在阅读<阿里巴巴Java开发手册>时,发现有一条关于整型包装类对象之间值比较的规约,具体内容如下: 这条建议非常值得大家关注, 而且该问题在 Java 面试中十分常见. 还需要思考以下几个 ...
- JAVA的整型与字符串相互转换
1如何将字串 String 转换成整数 int? A. 有两个方法: 1). int i = Integer.parseInt([String]); 或 i = Integer.parseInt([S ...
- Java关于整型类缓存[-128,127]之间的数字
我们在学习Java的包装类Integer.Long的时候可能会遇到这个问题: ①Integer a = 500;// Integer a = Integer.valueOf(500); 等价于上面的 ...
- JAVA中整型的存储和左右移位运算
byte,1个字节8位, -128 ~ 127之间,首位表示正负,0为正,1为负,0111,1111表示127,-127为127取反1000,0000,再加1,即1000,0001为-127,-127 ...
- java中整型、浮点型、char型扩展
怎么区分是什么进制? 二进制:0b开头,eg: int i = 0b10; 八进制:0开头,eg: int k = 010; 十进制: 十六进制:0x开头,eg: int j = 0x10; 浮点数类 ...
- 一个封存Id与状态对应键值的神器,BigInteger的setBit和testBit用法实例
1,首先描述一下应用场景 比如,我们要对菜单做权限,控制不同角色菜单显示与不显示,角色为经理时,我们需要菜单id为 4,7,13,24的菜单显示,别的菜单不显示. 就是说,这时候我们要把4,7,13, ...
随机推荐
- Mysql数据库(九)备份与恢复
一.数据备份 1.使用mysqldmp命令备份 (1)备份一个数据库 mysqldump -u root -p dbname table1 table2 ... > D:\BackName.sq ...
- vue cli3.3 以上版本配置vue.config.js 及反向代理操作解决跨域操作
const webpack = require('webpack') module.exports = { configureWebpack: { plugins: [ new webpack.Pro ...
- Mysql常用数据类型归纳总结1
一直在用Mysql数据库,Mysql的数据类型也最常打交道的.但关于Mysql的一些常用数据类型了解程度仅限于一知半解,仅仅能满足满足于平时一些最简单的操作.而Mysql常用数据类型的定义以及规范理解 ...
- 学习笔记52_mongodb增删改查
使用use db1作为当前数据库 如果没有db1,会自动创建 使用switch db2,当前数据库切换为db2 使用show dbs,显示当前所有数据库 使用show collection ,显示当前 ...
- Go 程序的性能监控与分析 pprof
你有没有考虑过,你的goroutines是如何被go的runtime系统调度的?是否尝试理解过为什么在程序中增加了并发,但并没有给它带来更好的性能?go执行跟踪程序可以帮助回答这些疑问,还有其他和其有 ...
- 原生JS实现call,apply,bind函数
1. 前言 使用原生JS实现call和apply函数,充分了解其内部原理.call和apply都是为了解决改变this的指向.作用都相同,只是传参的方式不同.除了第一个参数外,call可以接受一个参数 ...
- Markdown基本语法小结
目录 Typore Markdown基本语法 1.标题 一级标题 二级标题 三级标题 2.字体加粗 3.斜体 4.文本高亮 5.上标 6.下标 7.引用代码 1 8.代码引用2 9.代码引用3 10. ...
- php编辑器notepad++ 推荐一款非常好看主题和字体
php编辑器notepad++ 推荐一款非常好看主题和字体1.主题名称:Obsidian 2.字体字号:Courier New 10 3.设置方法:设置---语言格式设置---选择主题,同时勾选“使用 ...
- html5自动横屏的方法
html5自动横屏的方法<pre>var evt = "onorientationchange" in window ? "orientationchange ...
- js常用的array方法
1. splice() splice()方法向/从数组中添加/删除项目,然后返回被删除的项目.(注释:该方法会改变原始数组.) arrayObject.splice(index,howmany,i ...