博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java中大整型BigInteger及setBit和testBit方法
阅读量:4156 次
发布时间:2019-05-25

本文共 3826 字,大约阅读时间需要 12 分钟。

 

最近在修改公司之前的项目,在项目中遇到了权限校验的问题,代码中出现了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

BigIntegerIntegerLong一样,也是不可变类,并且也继承自Number类。因为Number定义了转换为基本类型的几个方法:

因此,通过上述方法,可以把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必须为正整数了。。)

 

    • 转换为bytebyteValue()

    • 转换为shortshortValue()

    • 转换为intintValue()

    • 转换为longlongValue()

    • 转换为floatfloatValue()

    • 转换为doubledoubleValue()

转载地址:http://dmwxi.baihongyu.com/

你可能感兴趣的文章
C 语言 学习---回调、时间定时更新程序
查看>>
第十一章 - 直接内存
查看>>
一篇搞懂Java反射机制
查看>>
Single Number II --出现一次的数(重)
查看>>
对话周鸿袆:从程序员创业谈起
查看>>
Mysql中下划线问题
查看>>
Xcode 11 报错,提示libstdc++.6 缺失,解决方案
查看>>
Windows mysql 安装
查看>>
python循环语句与C语言的区别
查看>>
vue项目打包后无法运行报错空白页面
查看>>
Vue 解决部署到服务器后或者build之后Element UI图标不显示问题(404错误)
查看>>
element-ui全局自定义主题
查看>>
facebook库runtime.js
查看>>
js报错显示subString/subStr is not a function
查看>>
高德地图js API实现鼠标悬浮于点标记时弹出信息窗体显示详情,点击点标记放大地图操作
查看>>
初始化VUE项目报错
查看>>
vue项目使用安装sass
查看>>
在osg场景中使用GLSL语言——一个例子
查看>>
laravel 修改api返回默认的异常处理
查看>>
laravel事务
查看>>