无论Java还是C++,都分为以下几种运算符:算术运算符,关系运算符,逻辑运算符,位运算符等。接下来我就对Java中的这些运算符进行简单的讲解。
我们常用的算数运算符有以下几个:
操作符 | 描述 |
---|---|
+ | 加法运算 |
- | 减法运算 |
* | 乘法运算 |
/ | 除法运算 |
% | 取余运算:左操作数除以右操作数的余数 |
++ | 自增1运算 |
– | 自减1运算 |
这里+、-、* 与我们的数学运算规则完全相同,我就不做讲解了。
%一般用于整数的求余操作,有时也叫取模。
/ 的左右操作数都是整数时表示整数除法(结果只取整数部分),否则表示浮点除法。
需要注意的是,整数被0除将会产生一个异常,而浮点数被0除会得到一个结果(无穷大或NaN)
我们也可以在赋值语句中采用一种简化的格式书写二元算术运算符。
例如 x+=4 等价于 x=x+4
我们通常将算术运算符放在赋值符号的左侧进行拼接(*=,/=,%=,+=。-=)
在程序编程中,加1和减1是数值变量最常见的操作。Java也借鉴C++的实现方式,使用自增++ 与自减-- 的运算符实现变量加减1的操作。
例如 :int n=3;n++
那么n的值将变为4。因为运算符会改变变量的值,所以这里的操作数不能是数值。所以4++就是一条非法语句。
其实自增++ 和自减-- 分两种情况:
前缀形式:++n;- -n(表达式使用改变后的值)
后缀形式:n++;n- -(表达式使用改变前的值)
这两种形式使变量本身的值改变是一样的,但是对使用它们的表达式会产生不一样的结果,在下面的示例里可以清晰的看到区别。
尽管了解了区别,但我不建议在其他表达式里使用自增/自减运算符,这不止会使代码变的难懂,还有可能产生其他bug。
这里的==用于判断运算符两侧是否相等,要与赋值运算符 = 区分开。对于关系运算符的返回结果只有true/false 两种,赋值运算符就不一样。
另外Java沿用C++的习惯,也使用逻辑运算符:与、或、非。并且使用“短路”的方式求值:如果第一个操作数已经可以判断整个表达式的值,那么第二个操作数就不必计算了。
“短路”方式例如&&运算,如果左操作数为false,那么就不会继续计算右操作数。
对于下面的示例表现为 a/0 不报错(正常情况下-除数不能为0,否则程序报错)。
“短路”方式例如|| 运算,如果左操作数为true,那么就不会继续计算右操作数。
!非运算,大家很熟悉,也不用多讲了。
三元运算符指 ?: 表示当?的条件为真时计算第一个表达式,否则计算第二个。
例如表达式 return x
按位的与& 或| 运算很简单,这里的位指的就是二进制位,所以我们只要把数值用二进制表示就能得到结果。
具体示例如下:
计算过程如下:
~运算的运算规则:如果位为0,结果是1,如果位为1,结果是0。非运算符是一元运算符。
具体示例:a=2,~a=-3(具体计算涉及补码的知识点,看不懂得可以了解一下补码)
计算过程如下:
这里简单说一下: 正数的原码,反码,补码都一样;负数的反码是对除了符号位(最高位)对原码取反,补码是对反码+1。对于负数计算机存储的都是补码,所以我们要计算此负数的源码,即源码等于(符号位不变)补码减一再取反。
^运算的运算规则:两个操作数的位中,相同则结果为0,不同则结果为1。异或运算符是二元运算符。
具体示例如下:
计算过程也比较简单:
<< : 左移运算符,num << 1,相当于num乘以2
>> : 右移运算符,num >> 1,相当于num除以2
>>> : 无符号右移,忽略符号位,空位都以0补齐
具体示例为:
这里需要说明的是,正数在输出二进制表示时,左面的0不输出;负数输出二进制位时要输出完整的32位
计算过程如下:
这里要注意的时,对移位运算符右侧的参数需要做模32的操作。即1<<35与1<<3的运算结果是一样的。
位运算符比加减运算符运算速度更快,一般能用位运算的就用位运算符。
尤其2,/2 的运算,可换成<<和>>。
运算符的优先级:
后缀(()[].) > 一元(++ – - ! ~)> 乘性(/%)> 加性(+ -)> 位移(>> << >>>)> 关系(> >= < <=)> 相等(== !=)> &> ^> |> ?:> 赋值(=,+=等)> 逗号
题目:输入一个整数,输出该数二进制表示中1的个数,如:9的二进制表示是1001,有2位是1,因此如果输入9,该函数输出2。
第一种思路:使用 >> 运算符,将数据右移,不断与数字 1做与 & 运算,若与运算的结果为1,则表示该位置二进制为1,number++;否则位置上为0,继续判断下一位。
细心的读者可能会发现,代码里我使用的右移是>>>而不是>>。因为我在写代码时,突然想到,如果这里n是负数,用>>右移的话,最左面补位补的是1,一直右移就一直补1会造成死循环 (1000)>>(1100)>>(1110)>>(1111)>>…>>1111。而使用>>>就不会出现问题了,因为此时无论n为正负数,在右移操作中都会补0,while总会停止。
思路二:对于任意数据n,n-1操作是将n的二进制表示中,最右面的1变为0,且最右面1的后面部分全取反。n=n & (n-1),则是将n的二进制表示中,最右面的1的后面全变为0。利用这一特性,统计二进制表示中1的个数。