Java千问:Java位运算经典应用(一)

很多人认为位运算在实际开发过程中并没什么用,学习位运算也只是为了应付面试。这种想法是错误的,接下来我们就通过几篇连载文章介绍一下位运算在实际开发过程中的几个经典应用实例。如果对位运算规则掌握还不是很熟练,可以先阅读《Java千问:Java语言位运算符详解》。这篇文章不仅详细讲解了Java位运算的基本规则和一些常用的运算定律,同时还在文中提到了一些常用的位运算实际应用,比如可以用位运算操作的方式快速把某个变量所在的内存单元清零,或者位运算的方式实现某个变量快速倍增等等。但文中所这提到的这几个实际应用比较简单,本次连载文章将为大家讲述的是更加复杂和实际的应用经典案例。此外,为获得更好的阅读效果,请各位读者在读本文之前先熟练掌握”补码”的计算规则。

一、判断整数的奇偶性

按照传统的思路,判断一个整数的奇偶性是通过用这个数与2求模,看运算结果是否为0。学了位运算符以后,我们可以换一种思路来考虑问题。我们知道:Java语言中,所有数字存储在内存中,都要先转换成补码的形式。任何一个偶数用补码表示出来后,它的最后一个二进制位都是0,而奇数补码的最后一个二进制位都是1。所以,我们可以通过判断这个整数的补码的最后一位二进制数是0还是1,来判断这个数是偶数还是奇数。判断的方法就是用这个数与1进行按位与的操作,如果结果为0,那么这个数就是偶数,否则就是奇数。如果大家不理解这个算法的原理,请看下图:


为了方便表述,我们把要判断奇偶性的数字称为a。图中,以横线为界,分别展示了a为偶数和奇数的情况下,与数字1进行按位与操作的结果。其中,上面的二进制串是a的补码,下面二进制串是数字1的补码。可以看到,数字1被转换成补码之后,总共有32位,其中前31位都是0,最后1位的值是1。这就导致a补码的前31位无论是0还是1,与数字1的补码进行按位与运算,运算结果的前31位都只能是0,决定最终运算结果的就只有a补码最右边的那个二进制位。如果最右边那一位是0,那么a就是偶数,a与1按位与运算的最终结果是数字0。反过来,如果最右边那一位是1,那么a就是奇数,a与1按位与运算的最终结果是数字1。因此我们只要看一下a与数字1进行按位与运算的结果就知道a的奇偶性了。具体的程序实现如下:

二、求绝对值

常规算法求绝对值的思路是:首先判断一个数a是否>=0,如果a>=0,则返回a本身,否则返回a的相反数。这个过程包含判断和选择两个步骤。如果使用位运算符来实现求绝对值,可以省略掉判断的步骤,直接返回运算结果。下面来讲解一下使用位运算符求绝对值的基本原理。我们知道:任何一个二进制位上的数,与0进行异或运算,运算的结果都与这个二进制位上的数相同。把这个结论扩展一下,从原来某个数的单独的一个二进制位扩展到这个数字本身,可以得出另外两个结论,第一个结论:任何一个整数与0进行异或运算后依然保持不变。如果小伙伴不理解的话,请看下图,我们以数字5作为例子分析讲解:

另一个结论:任何一个整数与-1进行异或运算后再加上1,得到的结果就是这个数的相反数。如果不理解的话,还是看下图,仍然是以数字5分析讲解:

以上两个结论中,第一个结论比较容易理解。我们简单的解释一下第二个结论的原理。第二个结论能够成立的关键就在于,数字-1用补码的形式表示出来,恰好是一个32位全为1的二进制串。这个二进制串与任何一个其他二进制串进行按位异或运算,都可以达到”取反”的效果,而按照补码的计算规则,一个正数按位取反后再加1,得到的就是它相反数。比如图中的数字5,按位取反之后,再加1得到的就是-5。
至此,我们已经知道怎样通过位运算的方式获得一个数的相反数了。在《Java千问:Java语言位运算符详解》一文中还讲过:int类型的正数经过带符号右移31位之后,得到的必然是0,而负数经过带符号右移31位得到的是-1。我们就可以通过右移所得到的这个0或者-1,判断出这个数是正数还是负数。知道数字的正负属性,然后再用位运算的方式得到这个数本身或者是它的相反数,就能求出这个数的绝对值。按照这个思路,我们就可以来编写求绝对值的程序了,程序如下:

示例程序中的变量a是int型,如果改为long型,对a带符号右移63位也可有相同的运算效果。

(未完待续...)
如想系统学习Java编程,欢迎观看我在本站的视频课程。

原文地址:https://blog.51cto.com/2266836/2471460

时间: 2024-08-25 09:36:44

Java千问:Java位运算经典应用(一)的相关文章

Java千问:Java位运算经典应用(二)

接上篇 三.不借助中间变量交换两个变量的值 通常情况下,我们要交换两个变量的值都按如下步骤操作: 这种操作方式不难理解,实现交换变量值的关键点就在于中间变量c.而现在的题目要求是不借助中间变量来交换a和b的值.如果不使用位运算的方式,同样可以做到不借助中间变量交换两个变量的值,其实现过程如下. 为了讲解方便,我们把最初a与b的值称之为原始a和原始b,3行代码就是3步操作:第1步:把原始a与原始b相加的和存储到变量a中,变量b的值暂时没有发生变化.第2步:用这个和减去原始b,再赋值到变量b中,经过

Java千问:Java语言中最大的整数再加1等于多少?

已知Java语言中int类型所能表示的最大整数为2147483647,请问以下代码执行结果是什么?一部分人都会认为这段程序压根就无法通过编译,也有人认为,这段程序能够通过编译,但在运行时会抛出异常,但更多的人面对这道题目根本就无从下手.那么正确答案是什么呢?首先告诉大家,这段程序能够顺利通过编译,并且在运行时也不会出现异常,运行的结果是在控制台上输出了数字-2147483648!而-2147483648正好是Java语言中int类型所能表示的最小整数.这个运行结果可能会让很多人感到大跌眼镜,运行

Java千问:关于Java语言复合赋值运算符的两个问题,快来瞧瞧!

我们知道,在Java以及很多高级编程语言当中,都有一种运算符叫做复合赋值运算符.复合赋值运算符由两个符号组成,它所能完成的运算操作也分为两步:第一步是运算,第二步是赋值.比如说:上面的这两条语句相当于但是,如果碰到下面这样的情况,a的值该应该是多少呢?有人认为应该按以下方式来计算,因为我们都知道,在四则运算规则中,遵循"先乘除,后加减"的原则按照这样的方式来计算,得到a的值应该是7,但实际运行程序所得到的结果是8.这是为什么呢?就是因为复合赋值运算符在完成运算的时候,遵循一个规则:把&

Java基本数据类型与位运算

Java基本数据类型与位运算 >>赋值运算符 赋值使用操作符“=”.它的意思是“取右边的值(即右值),把它复制给左边(即左值)”.右值可以是任何 常数.变量或者表达式 (只要它能 生成 一个值就行).但左值必须是一个明确的,已命名的变量.也就是说,必须有一个物理空间可以存储等号右边的值.分类 基本数据类型 与 类数据类型 的不同1. 对基本数据类型的赋值是很简单的.基本数据存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方.2. 但是在为

java加密解密算法位运算

一.实例说明 本实例通过位运算的异或运算符 “ ^ ” 把字符串与一个指定的值进行异或运算,从而改变每个字符串中字符的值,这样就可以得到一个加密后的字符串.当把加密后的字符串作为程序输入内容,异或运算会把加密后的字符串还原为原有字符串的值.效果图如下: 二.实现过程 1 package com.itxxz; 2 3 import java.util.Scanner; 4 5 /** 6 * java加密解密算法 7 * 8 * @author 螃蟹 9 * 网站:IT学习者 10 * 网址:ht

《Java千问》系列短文写作计划

大家好,我在51CTO开博客啦!我本人从事软件开发和教学多年,在我从事教学过程中,回答过很多学生的问题,但非常遗憾,我只是当场回答了这些问题,但事后并没有把这些问题的解答写成博客.我打算弥补一下这个缺憾,因此产生了写文章解答问题的想法.经过几天酝酿,我打算把这些文章写成系列短文,名字就叫<Java千问系列>.取这个名字并不是说真的有一千个问题,"千"只是表示多的意思.只要我有把握回答的,都发表出来.关于<Java千问系列>的文章,在这里我想做几点说明:一.<

Java位运算经典实例

一 源码.反码.补码 正数的源码.反码.补码相同,例如5:            5的源码:101            5的反码:101            5的补码:101 负数的源码.反码.补码不同,例如-5:            -5的源码:10000101            -5的反码:111111010 (取反操作)            -5的补码:111111011 (补码加1操作) 计算机所有数据都以补码存储和运算. 二 位操作       位操作包含&,|,!分别表示

Java千问:Java语言位运算符详解

很多编程语言都有位运算符,Java语言也不例外.在Java语言中,提供了7种位运算符,分别是按位与(&).按位或(|).按位异或(^).取反(~).左移(<<).带符号右移(>>)和无符号右移(>>>).这些运算符当中,仅有~是单目运算符,其他运算符均为双目运算符.在讲解这些运算符的使用之前,必须了解一个常识,那就是:位运算符是对long.int.short.byte和char这5种类型的数据进行运算的,我们不能对double.float和boolean进

Java笔记1(位运算)

1.位运算:| 操作符使用public class WeiHuoTest{       public static void main(String[] args){               int number1 = 10;              int number2 = 8;  /*    number1: 10    0000 0000 0000 0000 0000 0000 0000 1010    number2: 8    0000 0000 0000 0000 0000