Java运算符

Java运算符

  • 概述
  • 算术运算符
            • 算术运算符
            • 算术运算符练习题1
            • 算术运算符练习题2
  • 赋值运算符
            • 赋值运算符
            • 扩展赋值运算符隐含强制类型转换
  • 比较运算符
            • 比较运算符
  • 逻辑运算符
            • 逻辑运算符
  • 位运算符(了解)
            • 位运算符
  • 三目运算符
            • 三目运算符不应该过多叠加
  • 运算符的优先级
            • Java运算符优先级

概述

>(green!)

程序的世界里数据是无处不在的,计算机的最基本用途之一就是执行数学运算,程序员编程实际上也是围绕着数据的计算处理展开的。Java作为一门程序设计语言,也提供了丰富的运算符来操纵变量,本节我们来学习一下Java当中的运算符。

很容易想到的运算符比如"加+ 减- 乘* 除/"四种运算符,不难发现:运算符起着连接变量的作用,表示对变量的运算规则。

其中:

被运算符连接起来的变量称之为操作数,整个运算符和变量组成的式子称之为表达式,表达式通过运算符连接操作数。

根据运算符能够连接的操作数的个数的多少,可以将运算符分为下列几类:

  1. 一元运算符:只需要一个操作数参与运算,得到一个结果
  2. 二元运算符:需要两个操作数参与运算,得到一个结果
  3. 多元运算符:超过两个操作数参与运算,得到一个结果

补充:

表达式(expression) vs 语句(statement)

  • 表达式一般都有确定的结果(值),不能构成一条能单独执行的代码(往往不能以分号结尾)
  • 语句都是可以单独执行代码,以分号结尾,多数语句没有结果

算术运算符

>(green!)

算术运算符(arithmetic)指最常见的一些数学运算符,它们在Java中的作用和在数学中的作用基本是一样的。

对于int a = 10 和 int b =20,有如下算术运算符和相关的例子:

算术运算符
操作符 描述 例子
+ 加法:相加运算符两侧的值,得到和 a+b=30
- 减法:左操作数减去右操作数,得到差 a-b=-10
* 乘法:相乘操作符两侧的值,得到积 a*b=200
/ 除法:左操作数除以右操作数,得到商 a/b=0
取余(取模):左操作数除以右操作数,得到余数 a%b=10
++ 自增:操作数的值增加1 a++一次是11
自减:操作数的值减少1 a–一次是9

>(green!)

算术运算符大多都比较简单,加减乘除这些都不提了,说一些可能引起错误的注意事项:

  1. "%"不是数学当中的百分号,而是取余(模)运算符,表示左边除以右边,结果是它们的余数。
  2. "/"即数学当中的除法,表示左边除以右边得到商。
  3. 需要注意的是,整型除以整型结果仍然是整型,得不到小数。 这和表达式的类型提升有关。

除开上面讲的外,最需要注意的就是自增(++)/自减(–),它们是面试题目中的常客。它们具有以下特点:

  1. 自加自减都是一元运算符,并且仅用于连接变量,常量无法用自增自减运算符连接。
  2. 自增和自减的使用有两种情况:
    1. 变量和运算符直接构成一个表达式,并单独使用。这时自增自减符号的含义就是表示执行一次,变量就加一或者减一,非常简单。并且变量和运算符谁在前,谁在后,对运算结果是没有任何影响的。
    2. 变量和自增自减符号,单独构成一个表达式后又参与了运算或者输出语句时。自增自减符号和操作数的位置就至关重要了:
      • 自增自减符号在变量前面,变量先自增自减,再参与后续运算或者赋值
      • 自增自减符号在变量后面,变量先参与运算或者赋值,再自增自减。
  3. 自增自减在日常开发更多还是配合for循环单独使用,尽量不要将自增自减组成的表达式放在其它表达式中,可读性很差。
  4. 暂时没了。

>(red!)

小试牛刀

  1. 求a、b、c的值。

    算术运算符练习题1
    int a = 10;
    int b = 10;
    int c = 10;
    a = b++;
    c = --a;
    b = ++a;
    a = c--;
    
  2. 求x,y值

    算术运算符练习题2
    int x = 4;
    int y = (x++) + (++x) + (x*10);
    

赋值运算符

>(green!)

赋值(assignment)运算符指为变量指定新值完成赋值作用的运算符,赋值运算符需要连接两个操作数,是典型的二元运算符。赋值运算符可以分为两类:

  1. 基本的赋值运算符,即" = "等号。
  2. 基于等号扩展而来的扩展赋值运算符,比如:" += “,” -= “,” *= "等。

不管是什么赋值运算符,赋值运算符总是把右边的操作数(或计算后的结果)赋值给左边,运算方向从右向左。既然是赋值,左边必须是一个变量来接收这个值。

对于两个操作数a和b,有如下赋值运算符和使用案例:

赋值运算符
操作符 描述 例子
+= 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数 a + = b等价于a = a + b
-= 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数 a - = b等价于a = a - b
*= 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数 a * = b等价于a = a * b
/= 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数 a / = b等价于a = a / b
%= 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数 a%= b等价于a = a%b
<<= 左移位赋值运算符 a << = 2等价于a = a << 2
>>= 右移位赋值运算符 b >> = 2等价于b = b >> 2
&= 按位与赋值运算符 a&= 2等价于a = a&2
^= 按位异或赋值操作符 a ^ = 2等价于a = a ^ 2
|= 按位或赋值操作符 b | = 2等价于b = b | 2

>(green!)

扩展的赋值运算符有一个非常重要的特点:扩展的赋值运算符隐含强制类型转换,无需再写强制类型转换的语法。例如下列代码就是合法的:

扩展赋值运算符隐含强制类型转换
// 正常情况下short + 1结果是int类型
short s1 = 1;
s1 += 1;

当然即便是强制隐含的强转,仍然属于强转,仍然会存在数据失真的问题。

最后一点:

上面提到过,表达式一般是有结果的。赋值运算符构成的赋值表达式也是表达式,所以它也是有结果的,其结果是赋值表达式右边要赋给左边变量的值。 这就意味着诸如下列代码是合法的:

int b = (b = 10);

注:当然它没什么意义,你也不要这么写代码。

比较运算符

>(green!)

比较(comparison)运算符指的是用来判断两个变量(或常量)大小的运算符。显然既然是比较,自然需要两个操作数,比较运算符是典型的二元运算符。比较的结果,也就是比较运算符组成的表达式(也叫布尔表达式)的结果必然是一个布尔值,也就是true或者false。

对于两个操作数 int a = 10,int b = 20,有以下表格:

比较运算符
运算符 描述 例子
(==) 检查如果两个操作数的值是否相等,如果相等则条件为真。 (a == b)为假。
!= 检查如果两个操作数的值是否相等,如果值不相等则条件为真。 (a != b) 为真。
> 检查左操作数的值是否大于右操作数的值,如果是那么条件为真。 (a > b)为假。
< 检查左操作数的值是否小于右操作数的值,如果是那么条件为真。 (a < b)为真。
>= 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。 (a >= b)为假。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。 (a <= b)为真。

注:(==)就是运算符==,之所以加括号是为了避免表格的格式出现错误。

>(green!)

使用细节和注意事项:

  1. 在比较时,基本数据类型和基本数据类型比,引用数据类型和引用数据类型比。其中

    1. 基本数据类型的数值类型的比较,上述运算符都是可用的。但布尔类型仅适用于"==“或者” != "的比较。

    2. 引用数据类型的变量比较只能使用" == “和” != ",而且不是任意两个引用数据类型变量都能够比较。

      注:这一条随着知识点的学习,会不断加深理解,大家可以自行测试一下。

  2. 基本数据类型的数值类型和char是可以相互比较的,boolean只能自己和自己比较。引用数据类型的比较,只能相同类型之间比较,比如String和String比较,String和System就没有可比性。

  3. 两个浮点数的比较不建议直接使用比较运算符,还有诸如引用数据类型的比较等知识点,我们等到日后再谈。(面向对象讲)

逻辑运算符

>(green!)

逻辑(logical)运算符指的是专门连接布尔类型变量、常量进行运算的运算符。 当然逻辑运算表达式的结果也一定是boolean类型。

对于 boolean a = true; boolean b = false 有以下案例:

逻辑运算符
操作符 描述 例子
& 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 (a & b)为假
| 称为逻辑或运算符。如果任何两个操作数任何一个为真,条件为真。 (a | b)为真
^ 成为逻辑异或运算符。相同时为false,不同时为true (a ^ b) 为真
&& 称为短路与逻辑运算符。当且仅当两个操作数都为真,条件才为真。 (A && B)为假
|| 称为短路或逻辑运算符。如果任何两个操作数任何一个为真,条件为真。 (A | | B)为真
! 称为逻辑非运算符,用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。 !(A && B)为真

>(red!)

逻辑与和逻辑或有短路与非短路两种类型,那么短路与不短路有啥区别呢?

其实非常简单,对于逻辑或来说,一旦左边的操作数的结果确定是true,那么整个表达式的结果一定是true,右边实际上是不需要再进行计算的;同理逻辑与也是意义,一旦左边的操作数确定是false,那么右边无论是什么结果都是false。

短路就是依据这种原理,若左边的操作数已经能够决定表达式的值了,后面就都不算了。短路逻辑运算符的计算结果不变,但是执行效率变高了。所以建议:大家在使用逻辑与或时,一律使用短路版本。 在有些书籍里,甚至已经不把 &| 列入逻辑运算符中,而是直接列为位运算符。

在实际开发中,&&||! 最常用。

位运算符(了解)

>(green!)

位(shift)运算符,全称"移位运算符",是直接对整数的二进制位进行计算的运算符。由于能够直接对位,进行移位运算操作,所以位运算符的最大优点是运算效率高,缺点是对人来说不够直观。位运算符仅做了解,不作为重点。

对于int a = 60 和 int b = 13有以下案例:

位运算符
操作符 描述 例子
如果相对应位都是1,则结果为1,否则为0 (a&b),得到12,即0000 1100
| 如果相对应位都是0,则结果为0,否则为1 (a | b)得到61,即 0011 1101
^ 如果相对应位值相同,则结果为0,否则为1 (a ^ b)得到49,即 0011 0001
按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 (〜a)得到-61,即1100 0011
(<<) 按位左移运算符。左操作数按位左移右操作数指定的位数。在一定范围内,每左移一位,相当于乘以2 a << 2得到240,即 1111 0000
>> 按位右移运算符。左操作数按位右移右操作数指定的位数。在一定范围内,每右移一位,相当于除以2 a >> 2得到15即 1111
>>> 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 A>>>2得到15即0000 1111

注:(<<)就是运算符<<,之所以加括号同样是为了避免表格的格式出现错误。

>(green!)

简要说一说运算规则:

  1. <<>> 的实质

    1. << 左移就是把左边移出去的高位截断,在低位补数,无论原先的数是正是负,空位都补0。在一定范围内,M << n 可以这么算 M << n = M * 2^n,即左移几位就表示乘以几个2。但是一旦超出范围,甚至可能把正数左移成负数。
    2. >> 右移就是把右边移出去的低位截断,在高位补数,正数补0,负数补1。在一定范围内,M >> n 可以这么算 M >> n = M / 2^n,即右移几位就表示除以几个2。右移虽然不会改变正负,但是一旦出现小数会丢失小数位。
  2. >>>>> 的区别

    1. >> 是有符号右移,在高位补数时,正数补0,负数补1。
    2. \>>> 是无符号右移动的时候,无论是正数负数,最高位是0还是1,被移除的低位丢弃,右移后最高位空缺位补0。
  3. &、| 、^(与、或、异或)位运算符

    Java运算符_第1张图片
  4. ~取反位运算符

    取反位运算符
  5. ^异或位运算符

    Java运算符_第2张图片

小tips:

在计算机中普遍使用^表示幂运算,但在Java中它是一个位运算符。那么在Java中该怎么求一个数的次幂呢?

使用以下代码:

Math.pow(double)

>(red!)

一个经典的问题:怎么算 2*16 最高效?

三目运算符

>(green!)

三目(ternary)运算符,也被称之为三元运算符,即指的是需要三个操作数的运算符。

它的语法是:

(条件表达式) ? 表达式1 : 表达式2;

它具有以下特点:

  1. 当条件表达式为true时,执行表达式1,否则执行表达式2。
  2. 三目运算符的最大特点就是,它一定会执行一个表达式, 所以它一定会有一个结果。
  3. 正是由于它必须执行表达式。而语句不能放在表达式的位置,这极大的限制了三目运算符的使用。

何时比较适合使用三目运算符呢?

if…else从使用效果上来说,是可以完全替代三目运算符的。但是使用三目运算符,代码更加简洁、更加优雅并且逻辑更加直观,实测三目运算符的运算效率要比if稍微高一点。所以,如果能够使用三目运算符尽量使用它,而不是if。

但是也要注意,不要使用过于复杂的三目运算符,否则会导致程序可读性变差。比如下列代码:

三目运算符不应该过多叠加
// 求三个数的最大值
int max = (a > b) ? (a > c) ? a : c : (b > c) ? b : c;
boolean b = true ? false : true == true ? false : true;

我相信你不会愿意看到这种代码吧。

运算符的优先级

>(green!)

运算符有不同的优先级,所谓优先级就是在表达式运算中的运算顺序。运算符的优先级决定了谁先进行运算,是既重要也不重要的知识点:

  1. 重要在于,运算符的优先级对表达式结果有显著影响。如果不知道运算优先级,一个表达式你肯定看不懂。
  2. 不重要的地方在于可以使用小括号"()"主动控制优先级。

简单了解一下,Java运算优先级的大体规则:

  1. 所有的数学运算都认为是是从左向右的,Java语言中大部分运算符也是从左向右结合的。
  2. 但是单目运算符,赋值运算符,三目运算符不符合1中的规律
    1. 其中单目运算符,赋值运算符是从右向左结合,也就是从右向左运算的。
    2. 三目运算符实际上是一种选择结构,是一种特殊的运算。

>(red!)

下表中列出了运算符的优先级顺序,编号越小的运算符优先级越大。

Java运算符优先级
编号 类别 操作符 计算顺序
0 后缀 () [] . (点操作符) 左到右
1 一元 + + - !〜 从右到左
2 乘性 * /% 左到右
3 加性 + - 左到右
4 移位 >> >>> << 左到右
5 关系 >> = << = 左到右
6 相等 == != 左到右
7 按位与 左到右
8 按位异或 ^ 左到右
9 按位或 | 左到右
10 逻辑与 && 左到右
12 逻辑或 | | 左到右
13 条件 ?: 从右到左
14 赋值 = + = - = * = / =%= >> = << =&= ^ = | = 从右到左
15 逗号 左到右

虽然我们无需具体记忆这些优先级,但是仍然需要记住—— 赋值运算符的优先级往往最低。

你可能感兴趣的:(Java笔记,java,面试,经验分享)