Kotlin基础学习之位运算

什么是位运算?

程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算。举个例子,6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理):

110
AND 1011
———-
0010 –> 2

由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。当然有人会说,这个快了有什么用,计算6 and 11没有什么实际意义啊。这一系列的文章就将告诉你,位运算到底可以干什么,有些什么经典应用,以及如何用位运算优化你的程序。

引言

这个还真是基础中的基础,如果你跟我一样之前没有好好学习过Java基础语法,这块对你来说应该是一个懵逼点吧。不谈底层什么的,单单从android编程来看,我们在加密算法还有网络包处理等业务上使用位运算的频率还是很高的,更别提Intent中的那些种类繁多的Flag了,因此学好这方面的基础知识还是很重要的

本系列的例子使用的是Kotlin的语法,跟Java相比还是有所区别,请对照参考

无符号和有符号

在计算机中,可以区分正负的类型称为有符号类型,没有正负类型的称为无符号类型。

一个字节为8位,从0开始算,那它的最高位就是第7位。同样2个字节最高位为第15位,4个字节最高位为第31位。不同长度的类型,最高位不同,但是都是最左边的那个。

无符号数中,所有的位都用于直接表示该值的大小;有符号数中最高位用于表示正负,0表示正数,1表示负数。因此同样一个字节,无符号数最大值为255,有符号数最大值为127。有符号数最大值计算完全跟无符号数一样,但是在负数范围内就不能用刚才那种计算方式了,在计算机中,负数除了最高位为1以外,还采用补码的形式,所以在计算中要对补码进行还原

值得注意:的是JAVA的原始类型里没有无符号整型,如果需要转成无符号类型,可以用ushr

原码、补码、反码

这个是高中就教过的知识,这里就不再做介绍

提醒一下,负数都是用补码参与运算的,得到的也是补码,需要减1取反获得原码。

位运算符

位运算主要在直接操控二进制数时进行使用,可以达到节约内存,使你的程序运行速度更快

Java定义了位运算符,可应用在整形(int)、长整型(long)、短整型(short)以及字符型(byte)等类型上。位运算符作用在所有的位上,并按位进行运算。Kotlin与之略有不同,它并没有提供特殊的操作符,只提供了中缀形式的表示方法,并且Kotlin只可用在Int和Long类型上,这点千万要记住

咱们来看一个例子

 val a1 = 60
 val b1 = 13
 var c1 = -5
 // 与
 println(a1 and b1)
 // 或
 println(a1 or b1)
 // 异或
 println(a1 xor b1)
 // 按位取反
 println(a1.inv())
 // 左移
 println(a1.shl(1))
 // 右移
 println(a1.shr(1))
 // 无符号右移
 println(a1.ushr(1))

先看看结果,然后我们再一个个的分析

12
61
49
-61
120
30
30

我们知道,Java中的Int是4个字节32位的,那么a1与b1、c1转换成二进制就应该是

val a1 = 60 // 0000 0000 0000 0000 0000 0000 0011 1100
val b1 = 13 // 0000 0000 0000 0000 0000 0000 0000 1101
var c1 = -5 // 1111 1111 1111 1111 1111 1111 1111 1011

随后就是7种中缀表达式的计算规则

and 如果对应位都是1,则结果为1,否则为0

or 如果对应位都是0,则结果为0,否则为1

xor 如果对应位值相同,则结果为0,否则为1

inv 按位翻转操作数的每一位,即0变成1,1变成0

shl 按位左移指定的位数,相当于乘以2的N次方。移掉的省略,右边缺失的位,用0补齐

shr 按位右移指定的位数,相当于除以2的N次方,移掉的省略,左边缺失的位,如果是正数则补0,若为负数,可能补0或补1,这取决于所用的计算机系统

ushr 按位右移指定的位数,移掉的省略,左边缺失的位,用0补齐

所以我们来看看按位计算的结果(省略掉高位重复的0或者1,只看低八位)

通过上述规则,我们就能明白计算结果是怎样得到的

“与”的结果就是00001100,即为12
“或”的结果就是00111101,即为61
“异或”的结果就是00110001,即为49
“非a1”的结果就是11000011,即为-61
“左移a1 1位”的结果就是01111000,即为120
“右移a1 1位”的结果就是00011110,即为30
“无符号右移a1 1位”的结果就是00011110,即为30

有一个很有趣的现象,对于一个Int类型的数值,无论你执行左移还是右移还是无符号右移,只要移动32位,效果跟没有移动一致。这是因为在JAVA进行移位运算中因为Int是占32位,进行移位的数就是32的模,所以当数值移动32位的时候就等于数值移动0位,也相当于没有进行移位。同理Long类型的移位,Long占8字节也就是64位,所以移位的数是64的模

应用举例

有一个位运算口诀大家可以记一下:

清零取反要用与,某位置一可用或

若要取反和交换,轻轻松松用异或

判断Int型变量a是奇数还是偶数

a1 and 1 = 0 // 偶数
a1 and 1 = 0 // 奇数

获取Int型变量的第K位(注:K从0开始依次由右往左,以下揭同)

a1 shr k and 1

将Int型变量的第K位清0

a1 and ((1 shl k).inv())

将Int型变量的第K位置1

a1 or (1 shl k)

平均值

(a1 and b1)+((a1 xor b1) shr 1)

不用temp交换两个整数

a1 = a1 xor b1
b1 = b1 xor a1
a1 = a1 xor b1

获取绝对值

val temp = c1 shr 31
(c1 + temp) xor temp
(c1 xor temp) - temp

获取相反数

c1.inv()+1

Int转byte数组

val bytes = ByteArray(4)
bytes[0] = (a1 and 0xFF).toByte()
bytes[1] = (a1 shr 8 and 0xFF).toByte()
bytes[2] = (a1 shr 16 and 0xFF).toByte()
bytes[3] = (a1 shr 24 and 0xFF).toByte()

补零扩展和补符号位扩展

在看这个问题之前,我们先做一个小游戏

val byte1: Byte = -127
println(byte1)
println(byte1.toInt())
println(byte1.toInt() and 0xff)

看官请猜猜看呢

还是我来公布答案吧

-127
-127
129

能解释一下为什么-127变成129吗?这个就牵扯到补零扩展和补符号位扩展了

之前我们知道,Java是没有无符号类型的,byte是8个字节而int是32个字节。在byte转int的时候,肯定要将8位补到32位。Java中的扩展方式是补符号位扩展,所以-127通过补符号位扩展之后还是-127,即11111111 11111111 11111111 10000001。如果采用补零扩展,相当于11111111 11111111 11111111 10000001 and 11111111,这个值就是00000000 00000000 00000000 10000001,也就是129了

为了加深记忆,我再留一道题给大家思考

println(0x100000000L + 0xcafebabe.toInt())
println(0x100000000L + 0xcafebabeL)

这两个表达式打印出来也不一样,现在你应该能明白为什么不一样了吧

总结一下

Java中只有有符号数。当byte扩展到short,int时,因为符号位是0,所以正数都一样,无论如何都是补零扩展;但负数补零扩展和按符号位扩展结果完全不同。

补符号位扩展,原数值不变。补零扩展,相当于把有符号数看成无符号数。

对于有符号数,默认采用符号位扩展。由小扩展到大时,需要用and 0xff这样方式来确保是按补零扩展的;而从大向小时,符号位自动无效,所以不用处理。如果是char类型,那么不管它将要被扩展成什么类型,都执行补零扩展

参考文章

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

您可能感兴趣的文章:

  • kotlin 官方学习教程之基础语法详解
  • Android Kotlin的使用及简单实例
  • Kotlin 基础教程之数组容器
  • Kotlin 开发环境详解及简单实例
  • Kotlin 的注解类详解及实例
  • 详解Kotlin中的变量和方法
  • 使用Kotlin开发Android应用教程
(0)

相关推荐

  • 使用Kotlin开发Android应用教程

    使用Kotlin开发Android应用 1.Kotlin介绍 [Kotlin](https://kotlinlang.org/) Kotlin是一门基于JVM的编程语言,它正成长为Android开发中用于替代Java语言的继承者.Java是世界上使用最多的编程语言之一,当其他编程语言为更加便于开发者使用而不断进化时,Java并没有像预期那样及时跟进. Java缺失的很多特性在最新的修订版中逐渐覆盖到了,但Android开发者暂时还没能够使用它们.这就使得类似Kotlin这样的语言有了用武之地了:

  • Android Kotlin的使用及简单实例

    Android Kotlin的使用及简单实例 写在前面的话,作为一个不熬夜的人,一觉醒来发现Kotlin成为了Android的官方语言,可谓是大喜过望.为了趁热打铁,我决定提前三天放出原定本周日Release的文章.希望能及时让大家了解一下Kotlin. 相信很多开发人员,尤其是Android开发者都会或多或少听说过Kotlin,当然如果没有听过或者不熟悉也没有关系.因为本篇文章以及博客后期的内容会涉及到很多关于Kotlin的知识分享. 在写这篇文章前的一个多月,Flipboard中国的Andr

  • kotlin 官方学习教程之基础语法详解

    kotlin 官方学习教程之基础语法详解 Google 在今天的举行了 I/O 大会,大会主要主要展示内有容 Android O(Android 8.0)系统.Google Assistant 语音助手.Google 智能音箱.人工智能.机器学习.虚拟现实等.作为一个 Android 开发者,我关心的当然是 Android O(Android 8.0)系统了,那么关于 Android O 系统的一个重要消息是全面支持 Kotlin 编程语言,使得 Kotlin 成为了 Android 开发的官方

  • Kotlin 的注解类详解及实例

    Kotlin 的注解类详解及实例 注解声明 注解是将元数据附加到代码的方法.要声明注解,请将 annotation 修饰符放在类的前面: annotation class Fancy 注解的附加属性可以通过用元注解标注注解类来指定: @Target 指定可以用 该注解标注的元素的可能的类型(类.函数.属性.表达式等): @Retention 指定该注解是否 存储在编译后的 class 文件中,以及它在运行时能否通过反射可见 (默认都是 true): @Repeatable 允许 在单个元素上多次

  • Kotlin 开发环境详解及简单实例

    Hello Kotlin 在前段时间举办的Google I/O 2017上,Google宣布Kotlin成为Android官方的开发语言,这个最初发布于2011年的语言在短短的时间内就吸引了大量的开发者,而Google使得它进入了更多人的视线. Kotlin是一种开源的基于JVM的变成语言,由JetBeans公司开发(大概除了使用VS的.net开发者意外,都会或多或少听说或使用过IDEA吧),名字取自圣彼得堡附近的一个小岛(Koltin island). Kotlin是一种简单的语言,其主要目标

  • Kotlin 基础教程之数组容器

    Kotlin 基础教程之数组容器 Arrays Kotlin 标准库提供了arrayOf()创建数组, **ArrayOf创建特定类型数组 val array = arrayOf(1, 2, 3) val countries = arrayOf("UK", "Germany", "Italy") val numbers = intArrayOf(10, 20, 30) val array1 = Array(10, { k -> k * k

  • 详解Kotlin中的变量和方法

    详解Kotlin中的变量和方法 变量 Kotlin 有两个关键字定义变量:var 和 val, 变量的类型在后面. var 定义的是可变变量,变量可以被重复赋值.val 定义的是只读变量,相当于java的final变量. 变量的类型,如果可以根据赋值推测,可以省略. var name: String = "jason" name = "jame" val max = 10 常量 Java 定义常量用关键字 static final, Kotlin 没有static,

  • Kotlin基础学习之位运算

    什么是位运算? 程序中的所有数在计算机内存中都是以二进制的形式储存的.位运算说穿了,就是直接对整数在内存中的二进制位进行操作.比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算.举个例子,6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理): 110 AND 1011 ---- 0010 –> 2 由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度

  • 深入学习java位运算的基础知识

    相信大家和我一样,接触java这门语言的时候就听过java位运算的鼎鼎大名,当然也仅限于听说过.日常开发过程中使用过么?使用位运算的好处是什么? 想要真正理解java位运算,首先要搞清楚,这个"位"代表的含义. 一切的起源:二进制 位:二进制位,简称"位".是二进制记数系统中表示小于2的整数的符号,一般用1或 0表示,是具有相等概率的两种状态中的一种.二进制位的位数可表示一个机器字的字长,一个二进制位包含的信息量称为一比特(bit). 举个栗子: int占4个字节(

  • Kotlin基础学习之循环和异常

    前言 Kotlin并没有想象中的那么牛逼哄哄,也并不难,我更喜欢把他看做一枚语法糖,所谓的语法糖就是:能够让代码变得更加简单易读的辅助工具.而工具这种东西,看看说明书,实操几遍基本就能掌握,都是记忆性的东西,熟能生巧.如果你的Java基础扎实,看看Kotlin的开发文档,写写Demo,分分钟就上手了. 说到这个Kotlin提升写代码效率,还是谈谈几个最直观简单的例子吧: 1.不用再去 findViewById 或者 @BindView,拿到控件id直接用 2.不用再为 Bean 写一堆 gett

  • Kotlin基础学习之Deprecated与Suppress注解使用

    前言 在 Java 中通常对一些方法进行一些注解操作,但是很多注解在 Java 代码上没有问题,如果切换到 Kotlin 上时,如果继续使用这些注解就会存在一些问题,本篇主要对比一些常用 Java 注解和 Kotlin 注解使用转换. Deprecated 在 Java 方法中,如果需要废弃一个方法,只需要在方法钱加上 @Deprecated 即可,例如这样: @Deprecated public void test(){ } 但是如果在 Kotlin 代码中直接使用这个注释,就存在问题了: D

  • Kotlin基础学习之lambda中return语句详解

    前言 当我们爱上lambda并且大范围使用它的时候,我想大家都会被lambda中的return语句狠狠地调戏过,所以今天我们需要一起来揭开lambda中return的神秘面纱. 首先来看一个例子: fun demo() { val indexes = arrayOf(1, 2, 3, 4, 5, 6, 7) indexes.forEach { if (it > 5) { return } println(it) } println("End") } 按照我们的预期,调用demo后

  • 图文详解C语言位运算基础知识

    C语言位运算基础知识分享给大家,希望对大家有帮助. 1.   程序中的所有数在计算机内存中都是以二进制的形式储存的.位运算说穿了,就是直接对整数在内存中的二进制位进行操作. 2.  与运算:只有前后两个运算数都是 1 的时候结果才是1. 3.  或运算:有1位为1,结果便为1. 4.  异或:不相同则为1. 5.  取反运算:将1变为0,将0变为1. 6.  移位运算:左移则乘2,右移则除2.如果超出边界,则舍弃. 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们.

  • Java基础之位运算知识总结

    一.位运算的分类与展现效果 java位运算可以分为左移和右移,其中右移还有无符号右移.   java只对整型位移,可以分为int体系和long体系.int体系包括(byte, short, int, char),long体系只包含long.int体系中进行位运算时,除int类型外都会先转换为int再进行运算.. 无符号右移指的是,向右移动时,左边补位的是0. 一般来说,右移左移常用作乘2n 或者除以2n.(右移除以2n,左移乘以2n) int i1 = 4; int r1 = i1 >> 2;

  • 基础的十进制按位运算总结与在Python中的计算示例

    与运算 & 举例: 3&5                        解法:3的二进制补码是 11,  5的是101, 3&5也就是011&101,先看百位(其实不是百位,这样做只是便于理解) 一个0一个1,根据(1&1=1,1&0=0,0&0=0,0&1=0)可知百位应该是1,同样十位上的数字1&0=0,个位上的数字1&1=1,因此最后的结果是1.(这之后本来应该还有一步,因为我们现在得到的数值只是所求答案的补码,但是因

  • Python基础学习之基本数据结构详解【数字、字符串、列表、元组、集合、字典】

    本文实例讲述了Python基础学习之基本数据结构.分享给大家供大家参考,具体如下: 前言 相比于PHP,Python同样也是脚本解析语言,所以在使用Python的时候,变量和数据结构相对于编译语言来说都会简单许多,但是Python相比于PHP来说,变量类型的定义会比较严格:string->int的转换没有PHP那么方便.但这也让程序稳定性有所提升,例如和客户端交互的时候,数据库取出来的数字int和缓存取出来的数字(默认是string)需要手动进行转换(否则会有报错提示),而PHP不需要手动转换的

随机推荐