Java编程运算符和运算符优先级

时间:2022-05-01 21:02:22
    计算机,顾名思义,就是计算的机器,所以在编程中,也要进行大量的计算(运算),运算的符号简称为运算符。

        由于计算机可以进行各种运算,所以提供了很多的运算符号,这些运算符号一部分是现实里经常使用的,也有不少是计算机中新增的。

         学习运算符,首先要掌握每种运算的运算规则,然后在适当的时候使用对应的运算符。这需要对于运算符最够的熟悉,并具备一定的计算机基础知识。

         运算符的种类很多,为了方便学习,以下按照类别来进行介绍。

 

1、 算术运算符

    算术运算符,也称数学运算符,是指进行算术运算的符号,语法中对应的符号、功能以及说明参看下表

表4-1 算术运算符
符号 名称 功能说明
+ 加法运算
- 减法运算
* 乘法运算
/ 除法运算
% 取余 求两个数字相除的余数

    在算术运算符中,+、-、*和/的运算规则和数学基本相同,在四则运算中,乘除优先于加减,计算时按照从左向右的顺序计算,不同的地方在于:

    程序中乘号不能省略,在数学上可以写y = 2x,但是程序中必须写成y=2 *x.

    运算结果的类型和参与运算的类型中最高的类型一致,例如整数加整数还是整数。影响最大的是除法,整数除整数结果还是整数,例如10/3的结果是3,而不是3.333.

    接着来说说取余运算符,%的功能是取两个数字相除的余数,例如10%3表示计算10除以3的余数,则结果应该是1.取余运算在编程中的用途也比较大,比较常见的用途有:控制规则变化,控制随机数字的区间等。

    算术运算符基本使用的示例代码如下:

    int n = 3 + 5;

    int a = 10;

    int b = 20;

    int c = a * b;

    double d = 100.2;

    double d1 = d + a;

    在算术运算符部分,需要特别注意的一个语法现象是“晋升”。晋升指低于int的3种数字类型(byte、short和char)进行算术运算后,结果会自动提升成int类型。示例代码如下:

    byte b1 = 10;

    byte b2 = 20;

    byte b3 = b1 + b2; //语法错误,类型不匹配

    int n = b1 + b2;    //或者 byte b3 = (byte)(b1 + b2);

    在程序中使用算术运算符实现程序中的数学运算,在运算时也可以加入小括号,和数学一样,在程序中也是先计算小括号内部的,然后再计算小括号外部的内容,示例代码如下:

    int a = 1;

    int b = 2;

    int c = 3;

    int d = c * (a + b) + c;

    另外一个需要注意的就是,变量在计算时必须被赋值,否则直接报语法错误,例如:

    int n;

    int m = 2 * n;

 

2、 比较运算符

    比较运算符实现数据之间大小或相等的比较。

    比较运算符运算的结果是一个boolean类型的值,如果比较结果成立则为true,否则为false. Java语言中比较运算符的表示和功能见下表4-2.

表4-2 比较运算符
符号 名称 功能说明
> 大于 比较左侧数字是否大于右侧数字
< 小于 比较左侧数字是否小于右侧数字
>= 大于等于 比较左侧数字是否大于或等于右侧数字
<= 小于等于 比较左侧数字是否小于或等于右侧数字
== 等于 比较左侧数字是否等于右侧数字
!= 不等于 比较左侧数字是否不等于右侧数字

    比较运算符的运算规则和现实中的规则一样。需要注意的问题主要有以下几个:

    boolean类型只能比较相等和不相等,不能比较大小。

    l >=的意思是大于或等于,两者成立一个即可,所以5>=5成立。

    在数学上表示的区间[1,10),也就是数字大于等于1同时小于10,在程序中不能写成如下格式:1<=n<10,这种书写在语法上是错误的,如果需要表达这种区间,则参看4.3逻辑运算符实现部分。

    判断相等的符号是两个等号,而不是一个等号,这个需要特别小心。

    比较运算使用的示例代码如下:

    int a = 10;

    boolean b = (a > 3); //该条件成立,则将值true赋值给变量b

    boolean c = (b == true); //条件成立,结果为true在实际代码中,数值、变量以及运算结果都可以直接参与比较,只是程序中为了增强可读性,有些时候需要将比较分开进行书写。

    比较运算符是程序设计中实现数据比较的基础,也是很多逻辑实现的基础,在程序逻辑中,经常通过比较一定的条件,来判断后续的程序该如何执行。

 

 

3、 逻辑运算符

    逻辑运算符是指进行逻辑运算的符号。逻辑运算主要包括与(and)、或(or)和非(not)三种,在程序中主要用来连接多个条件,从而形成更加复杂的条件。

    逻辑运算符的运算结果是boolean类型。

    参与逻辑运算的数据也必须是boolean类型。

    关于逻辑运算符的种类和说明参看表4-3.

表4-3 逻辑运算符
符号 名称 功能说明
&& 逻辑与 两个条件同时为true才为true,否则为false
|| 逻辑或 两个条件有一个为true则为true,否则为false
! 逻辑非 只操作一个数据,对数据取反

    逻辑运算符使用示例代码:

    boolean b1 = true;

    boolean b2 = false;

    boolean b3 = b1 && b2; //则b3的值是false

    b3 = b1 || b2;        //则b3的值是true

    b3 = !b1;           //则b3的值是false

    在实际程序中,可以根据逻辑的需要使用对应的逻辑运算符号。实际使用示例:

    表示变量n是否属于[0,10)区间int n = 4;boolean b = (n >=0) && (n < 10);对于变量n来说,只要n同时满足大于等于零,且小于10,则位于[0,10)区间,由于程序中无法书写0<=n<10这样的条件,则必须通过逻辑运算符进行连接。

    表示变量n不属于[0,10)区间一种写法是:

    int n = 4;

    boolean b = !((n >= 0) && (n < 10));

    这里,对于属于该区间的条件取反,则可以获得不属于该区间的条件。

    另一种写法是:

    int n = 4;

    boolean b = (n < 0) || (n >= 10);

    这里做了一个简单的变通,如果变量n不属于该区间,则在数学上只需要满足n小于0或者n大于等于10的任何一个条件即可,这样的或者关系在程序中实现时使用逻辑或实现。

    在程序设计中,根据逻辑需要,使用对应的逻辑运算符,可以实现相对比较复杂的组合条件,从而实现对应程序的功能。

    最后说一下&&和&的区别,其实在进行逻辑与运算时,既可以使用&&也可以使用&,在功能上本身没有区别。两者区别的位置在,对于&来说,如果左侧条件为false,也会计算右侧条件的值,而对于&&来说,如果左侧的条件为false,则不计算右侧的条件,这种现象被称作短路现象。

    示例代码:

    int n = -1;

    boolean b1 = (n >= 0) && (n < 10);

    boolean b2 = (n >= 0) & (n < 10);

    则对于第二行代码来说,两个条件都将被计算,而对于第三行代码来说,因为n >= 0这个条件不成立,则n < 10根本不会被执行。当然,两者得到的最终结果是一样的。

    对于现在的代码来说,区别不大,但是如果后续的条件是一个方法(方法的概念后续将介绍到),则将影响程序逻辑。

    验证&和&&功能的示例代码如下:

    public class Test{

    public static void main(String[] args){

    int n = 10;

    boolean b = (n < 8) && ((n = 1) != 0);

    int m = 20;

    boolean b1 = (m < 8) & ((m = 1) != 0);

    System.out.println(n);

    System.out.println(m);

    }

    }

 

4、赋值运算符

    赋值运算符是指为变量或常量指定数值的符号。最基本的赋值运算符是“=”。

    由于Java语言是强类型的语言,所以赋值时要求类型必须匹配,如果类型不匹配时需要能自动转换为对应的类型,否则将报语法错误。示例代码:

    byte b = 12;      //类型匹配,直接赋值

    int n = 10;       //类型匹配,直接赋值

    double d = 100; //类型不匹配,系统首先自动将100转换成100.0,然后赋值

    char c = -100;   //类型不匹配,无法自动转换,语法错误

    需要强调的是,只能为变量和常量赋值,不能为运算式赋值,例如:

    int a = 10;

    int b = 2;

    a + b = 100; //不能为运算式a + b赋值,语法错误

    常量只能赋值一次,否则也将出现语法错误,例如:

    final int N = 10;

    N = 20; //常量只能赋值一次,语法错误

    在基本的赋值运算符基础上,可以组合算术运算符,以及后续将学习的位运算符,从而组成复合赋值运算符。赋值运算符和算术运算符组成的复合赋值运算符如下表4-4所示。

表4-4 复合赋值运算符
符号 名称 功能说明
+= 加等 把变量加上右侧的值然后再赋值给自身
-= 减等 把变量减去右侧的值然后再赋值给自身
*= 乘等 把变量乘以右侧的值然后再赋值给自身
/= 除等 把变量除以右侧的值然后再赋值给自身
%= 取余等 把变量和右侧的值取余然后再赋值给自身

    实际使用示例:

    int n = 2;

    n += 3;

    说明:计算以前n的值是2,也就是把n + 3的值,也就是5再赋值给n,经过运算以后n的值为5,因为该代码只执行一次,所以不会导致循环。

    依次类推,其它的复合赋值运算符也是这样:

    int n = 10;

    n -= 2; //则n的值是8

    n *= 3; //因为n的初值是8,则n运算后的结果是24

    n /= 5; //因为n的初值是24,则n运算后的值是4注意:复合赋值运算不会改变结果的类型,所以在有些时候运算在逻辑上会出现错误,但是符合计算中数值的表述。例如:

    byte b = 127;

    b += 1;

    System.out.println(b);

    根据前面的介绍,byte类型的取值区间是-128~127,由于复合赋值运算符不改变结果的类型,则导致结果是-128,而不是128.原因如下:

    byte类型值127的机器数是01111111,0表示正数,后续的数值表示127

    该数值加1后,得到的数值是10000000,二进制加法

    而10000000在byte类型中恰好是-128的机器数表示形式其它类型的符合运算符也可能存在类似的情况,使用时需要注意。

 

 

5、其它运算符

    对于无法归类,或者单独占一类的运算符,将在下面进行介绍。

    l ++、——这两个运算符是程序中的递增和递减运算符。其意义参照以下示例代码:

    int n = 0;

    n++; // n = n + 1 System.out.println(n);

    n++的意义就是对原来变量n的值加1以后再赋值给自身,因为原来变量n的值是0,加1以后则变成1.同理,递减运算符的意义也是这样,示例代码:

    int m = 0;m——;

    System.out.println(m);

    m—的意义就是对原来变量m的值减1以后再赋值给自身,则m的值变成-1.需要注意的是++和—只能操作变量,而不能操作其他的内容,以下使用都是错误的:

    int a = 0;

    int b = 0;

    (a + b)++;   //错误

    final int M = 1;

    M++;      //错误

    5++;      //错误

    在实际书写时,++和—既可以写在变量的前面,也可以写在变量的后面,例如:

    int k = 0;

    k++;

    ++k;

    同理,——也可以这样,那么这些在实际使用中有什么区别呢?其实对于变量的值来说,没有区别,也就是++无论写后面还是写前面,变量的值肯定增加1,——无论写在后面还是前面,变量的值都减1.其最大的区别在于整个式子的值,如n++,规则如下:

    1)++或—写在变量前面,则该式子的值等于变量变化以前的值。

    2)++或—写在变量后面,则该式子的值等于变量变化以后的值。

    示例代码如下:

    int n = 1;

    int m= 1;

    n++;    //n的值变为2

    ++m;   //m的值变为2

    int k = n++; //n的初始值是2,则n++的值是2,结果n的值为3,k的值为2

    int j = ++m; //m的初始值是2,则++m的值是3,结果m的值是3,j的值为3

    同理,——也是这样。

    下面是一个稍微综合点的示例:

    int a = 0;

    int b = 0;

    a = b++; //a为0,b为1

    a = ++b; //a为2,b为2

    b = a++; //a为3,b为2

    a = ++b; //a为3,b为3

    说明:注释部分为对应行代码运行以后,a和b的值。

    在程序开发中,可以使用该区别简化代码的书写,但是不推荐这样做,因为这样将增加阅读代码的难度。

    l +、-前面介绍过加减运算符,其实+、-还有另外一个意义,也就是代表正负,通常情况下正号可以省略,而负号可以和数值、变量以及运算式进行结合,示例代码如下:

    int a = 0;

    int b = 1;

    int c = -5;c = -a;

    c = -(a + b);

    ? :这个运算符称为条件运算符,其作用是根据判断的结果获得对应的值,语法格式如下:

    条件式 ? 值1 : 值2

    语法要求条件式部分必须是boolean类型,可以是boolean值,也可以是boolean变量,或者是关系运算符或逻辑运算符形成的式子,值1和值2必须能够转换成相同的类型。

    功能说明:如果条件式的结果是true,则整个式子的值取值1的值,否则取值2的值。示例代码如下:

    int x = 10;

    int y = 20;

    int max = x > y ? x : y; //因为x大于y,则取变量x的值,然后赋值给max

    int a = -10;int abs = a > 0 ? a : -a; //实现求绝对值得功能

    ()括号,也是运算符的一种,作用是可以让括号内部的计算首先进行,这个和数学上一致,只是程序代码中可以使用这个组合任意的合法运算式。示例代码为:

    int a = 1 + 2 * 3;

    int a = (1 + 2) * 3; //和以上代码的运行结果不一致

    其实每个运算符都有自己的优先级,使用括号可以提升对应式子的优先级。关于运算符优先级的概念,后续将进行介绍

 

 

6、 运算符优先级

    在实际的开发中,可能在一个运算符中出现多个运算符,那么计算时,就按照优先级级别的高低进行计算,级别高的运算符先运算,级别低的运算符后计算,具体运算符的优先级见下表:

运算符优先级表

优先级 运算符 结合性
1 () [] . 从左到右
2 ! +(正) -(负) ~ ++ -- 从右向左
3 * / % 从左向右
4 +(加) -(减) 从左向右
5 << >> >>> 从左向右
6 < <= > >= instanceof 从左向右
7 ==   != 从左向右
8 &(按位与) 从左向右
9 ^ 从左向右
10 | 从左向右
11 && 从左向右
12 || 从左向右
13 ?: 从右向左
14 = += -= *= /= %= &= |= ^= ~= <<= >>=   >>>= 从右向左

    说明:

    1、 该表中优先级按照从高到低的顺序书写,也就是优先级为1的优先级最高,优先级14的优先级最低。

    2、 结合性是指运算符结合的顺序,通常都是从左到右。从右向左的运算符最典型的就是负号,例如3+-4,则意义为3加-4,符号首先和运算符右侧的内容结合。

    3、 instanceof作用是判断对象是否为某个类或接口类型,后续有详细介绍。

    4、 注意区分正负号和加减号,以及按位与和逻辑与的区别其实在实际的开发中,不需要去记忆运算符的优先级别,也不要刻意的使用运算符的优先级别,对于不清楚优先级的地方使用小括号去进行替代,示例代码:

    int m = 12;

    int n = m << 1 + 2;

    int n = m << (1 + 2); //这样更直观

    这样书写代码,更方便编写代码,也便于代码的阅读和维护。