06、Java基础教程之程序概念·中

  • 本节学习目标
  • 1️⃣ 运算符
    • 1.1 关系运算符
  • 1.2 算术运算符
  • 1.3 三目运算符
  • 1.4 逻辑运算
    • 1.4.1 与操作
    • 1.4.2 或操作
    • 1.4.3 非操作
  • 1.5 位运算
    • *位运算规则
    • 1.5.1 位与运算
    • 1.5.2 位或运算
  • * 总结

*

本节学习目标

  • 掌握Java中各类运算符及其运算使用;

1️⃣ 运算符

Java中的语句有很多种形式,表达式就是其中一种形式。Java中的表达式由操作数、运算符、结果类型和求值顺序等元素组成,这些元素共同构成了复杂的逻辑和计算过程。

  • 操作数(Operands):操作数是表达式中的值或者变量,它们可以是字面值、变量、常量或函数调用的返回值。例如,5、x、true等都是操作数;
  • 运算符(Operators):运算符是用于组合和操作操作数的符号。Java中有多种类型的运算符,包括算术运算符(如加法 +、减法 -、乘法 * 等)、关系运算符(如等于 ==、不等于 !=、大于 >` 等)、逻辑运算符(如与 &&、或 ||、非 ! 等)、赋值运算符(如赋值 =、复合赋值 += 等)等;
  • 表达式的结果类型:表达式的结果类型可以是任意有效的Java数据类型,包括基本数据类型(如整数、浮点数、布尔值等)和引用数据类型(如对象、数组等)。表达式的结果类型取决于所使用的运算符和操作数的类型;
  • 表达式的求值顺序:Java中的表达式通常按照特定的优先级和结合性规则进行求值。例如,多个操作符同时出现时,按照算术运算符优先级的顺序进行求值。

以下面的表达式(z+100)为例,“z”与“100”都是操作数,而“+”就是运算符:

*

图1表达式的结构

Java提供了许多运算符,这些运算符除了可以处理一般的数学运算外,还可以做逻辑运算、地址运算等。

根据不同的类型,运算符可分为赋值运算符、算术运算符、关系运算符、逻辑运算符、条件运算符、括号运算符等,将这些常见的运算符及其基本的操作范例信息汇总如下表:

运算符 类型 示例 结果 描述
= 赋值运算符 int x=10; x=10 为变量x赋值为数字常量10
?: 三目运算符 int x=10>5?10:5 x=10 将两个数字中较大的值赋予x
+ 算术运算符 int x=20+10; x=30 加法计算
算术运算符 int x=20-10; x=10 减法计算
* 算术运算符 int x=20*10; x=200 乘法计算
/ 算术运算符 int x=20/10; x=2 除法计算
% 算术运算符 int x=10%3; x=1 取模(取余)计算
> 关系运算符 boolean x=20>10; x=true 大于
< 关系运算符 boolean x=20<10; x=false 小于
>= 关系运算符 boolean x=20>=20; x=true 大于等于
<= 关系运算符 boolean x=20<=20; x=true 小于等于
== 关系运算符 booleanx=20==20; x=true 等于
!= 关系运算符 booleanx=20!=20; x=false 不等于
++ 自增运算符 int x=10;int y=x++*2; x=11 y=20 “++”放在变量x之后,表示先使用x计算,之后x的内容再自增
int x=10;int y=++x*2; x=11 y=22 “++”放在变量x之前,表示先将x的内容自增,再进行计算
自减运算符 int x=10;int y=x–*2; x=9 y=20 “–”放在变量x之后,先使用x计算,之后x的内容再自减
int x=10;int y=–x*2; x=9 y=18 “–”放在变量x之前,表示先将x的内容自减,再进行计算
& 逻辑运算符 boolean x=false & true; x=false AND,与,全为true时结果才为true
&& 逻辑运算符 boolean x=false&& true; x=false 短路与,全为true结果为true
| 逻辑运算符 boolean x=false | true; x=true OR,或,有一个为true结果为true
|| 逻辑运算符 boolean x=false|| true; x=true 短路或,有一个为true结果为true
! 逻辑运算符 boolean x=!false; x=true NOT,否,true变false,false变true
() 括号运算符 int x=10*(1+2); x=30 使用()改变运算的优先级
& 位运算符 int x=19&20; x=16 按位与
| 位运算符 int x=19|20; x=23 按位或
^ 位运算符 int x=19^20; x=7 异或(相同为0,不同为1)
~ 位运算符 int x=~19; x=-20 取反
<< 位运算符 int x=19<<2; x=76 左移位
>> 位运算符 int x=19>>2; x=4 右移位
>>> 位运算符 int x=19>>>2; x=4 无符号右移位
+= 复合赋值运算符 a+=b a+b的值存放到a中(a=a+b)
-= 复合赋值运算符 a-=b a-b的值存放到a中(a=a-b)
*= 复合赋值运算符 a*=b ab的值存放到a中(a=ab)
/= 复合赋值运算符 a/=b a/b的值存放到a中(a=a/b)
%= 复合赋值运算符 a%=b a%b的值存放到a中(a=a%b)

需要注意的是,在Java中不同的运算符具有不同的优先级。当一个表达式中存在多个运算符时,优先级较高的运算符会先于优先级较低的运算符进行计算。将各运算符的优先级信息汇总如下表:

优先级 运算符 类型 结合顺序
1 () 括号运算符 由左至右
1 [] 方括号运算符 由左至右
2 !(非)、+(正号)、-(负号) 一元运算符 由右至左
2 ~(取反) 位运算符 由右至左
2 ++、– 自增、自减运算符 由右至左
3 *、/、% 算术运算符 由左至右
4 +、- 算术运算符 由左至右
5 <<、>> 位左移、位右移运算符 由左至右
6 >、>=、<、<= 关系运算符 由左至右
7 ==、!= 关系运算符 由左至右
8 &(AND,与) 位运算符 由左至右
9 ^(XOR,异或) 位运算符 由左至右
10 |(OR,或) 位运算符 由左至右
11 && 逻辑运算符 由左至右
12 || 逻辑运算符 由左至右
13 ?: 三目运算符 由右至左
14 =、+=、-=、*=… 赋值运算符 由右至左

如果表达式中含有相同优先级的运算符,则会按照表格所示结合性规则(从左到右或从右到左)进行求值。此外,使用括号可以改变运算符的默认优先级,确保表达式按照所需顺序进行计算。

而从实际运用来讲,这些运算符的优先级没有必要专门去记,熟能生巧,也建议读者在必要时可以使用“()”去改变优先级。

需要注意在实际运用时,不要写太过复杂的运算操作。比如以下类似的代码:

//	案例1:不建议的代码
public class TestDemo{
   
     
	public static void main(String args[]){
   
     
		int numA=10;
		int numB=20;
		int result=numA*2numB*numA+++numBnumA+numB;
		System.out.println(result);
	}
}

程序执行结果:

-143

虽然以上程序可以得到最终的计算结果,但是如此复杂的运算代码,代码的可读性和可维护性就变得太差了,可能其他的同事或领导看到都想叼人了,所以在编写程序的时候,应该本着编写“简单代码”的原则,而像本程序这样的代码尽量不要去编写。

1.1 关系运算符

关系运算符的主要功能是进行数据的大小关系比较,返回的结果是boolean型数据(只有truefalse两种取值),常用的关系运算符有:大于(>)、大于等于(>=)、小于(<)、小于等于(<=)、等于(==)、不等于(!=)。

//	案例2:使用关系运算符
public class TestDemo{
   
     
	public static void main(String args[]){
   
     
		System.out.println("3>1=" + (3>1));		//使用大于号
		System.out.println("3<1=" + (3<1));		//使用小于号
		System.out.println("3>=1=" + (3>=1));	//使用大于等于号
		System.out.println("3<=1=" + (3<=1));	//使用小于等于号
		System.out.println("3==1=" + (3==1));	//使用等于号
		System.out.println("3!=1="+(3!=1));		//使用不等于号
	}
}

程序执行结果:

3>1=true
3<1=false
3>=1=true
3<=1=false
3==1=false
3!=1=true

此程序演示了各种关系运算符的使用,考虑到运算符的优先级问题,使用了“()”运算符先进行关系运算,避免字符串直接拼接出现错误的结果。而对于关系运算符的使用往往是结合后续的分支、循环等程序逻辑控制语句一同进行使用。

1.2 算术运算符

算术运算符在开发中经常使用到,例如,进行四则运算、求模(取余)、自增等操作

//	案例3:使用四则运算
public class TestDemo{
   
     
	public static void main(String args[]){
   
     
		int numA=10;
		int numB=20;
		System.out.println("加法计算:"+(numA+numB));
		System.out.println("减法计算:"+(numA-numB));
		System.out.println("乘法计算:"+(numA*numB));
		System.out.println("除法计算:"+(numA/(double)numB));
	}
}

程序执行结果:

加法计算:30
减法计算:-10
乘法计算:200
除法计算:0.5

四则运算符的基本操作就是“+”、“-”、“*”、“/”,在程序中进行除法计算时,考虑到计算的精度问题,所以将其中一个int型变量强制转换为了double型变量。而“”也是在开发之中较为常见的计算,所谓的“”实际上就是余数的概念,例如:10*3的结果是商3余1,其中余数1就是“”,对于求模,可以使用“%”运算符。

//	案例4:使用求模计算
public class TestDemo{
   
     
	public static void main(String args[]){
   
     
		int numA=10;
		int numB=3;
		System.out.println(numA % numB);
	}
}

程序执行结果:

1

本程序分别定义了两个int型变量,随后使用“%”进行了求模计算,最终的结果就是1

虽然Java提供了四则运算操作,但是为了简化用户的编写,在运算符里面又提供了一些简化的复合赋值运算符:*=/=+=-=%=,这些运算符表示参与运算后直接进行赋值操作,下面来看一个具体的代码。

//	案例5:使用复合赋值运算符
public class TestDemo{
   
     
	public static void main(String args[]){
   
     
		int num=10;
		num*=2;//等价:num=num*2;
		System.out.println(num);
	}
}

程序执行结果:

20

此程序使用了“num*=2”语句替代了“num=num*2”的语句,相比较后者,代码的长度更加简短。

而还有一类运算符是“++”(自增)、“--”(自减),它根据位置不同,执行的顺序也不同。

  • 前置用法:++变量、–变量:先在前面表示的是先进行变量内容的自增1或自减1,再使用变量进行数学计算;
  • 后置用法:变量++、变量–:先使用变量内容进行计算,而后再实现自增或自减的操作。
//	案例6:使用前置自增
public class TestDemo{
   
     
	public static void main(String args[]){
   
     
		int numA=10;	//定义整型变量
		int	numB=20;
		//“++”写在变量前面,表示先对numA的变量内容加1
		//而后使用处理后的numA变量的内容+numB变量的内容
		int result=++numA+numB;
		System.out.println("numA=" + numA);
		System.out.println("result="+result);
	}
}

程序执行结果:

numA=11
result=31

本程序中 “int result=++numA+numB;”,语句使用了“++numA”,表示在与numB进行加法计算时,首先先对numA的变量内容进行自增1的操作,即执行完“++numA”之后,numA的内容首先变为11,然后利用11这个值与numB变量的20进行计算,最终的结果就是31

//	案例7:使用后置自增
public class TestDemo{
   
     
	public static void main(String args[]){
   
     
		int numA=10;	//定义整型变量
		int	numB=20;
		//“++”写在后面,表示先使用numA的内容进行加法计算
		//而加法计算完成之后再对numA的内容进行自增
		int result = numA+++numB;
		System.out.println("numA=" + numA);
		System.out.println("result=" + result);
	}
}

程序执行结果:

numA=11
result=30

此程序与前一程序的区别在于“++”出现的位置,在计算中由于“++”在numA的后面(numA+++numB),所以表示先使用numA当前的内容与numB进行加法计算,再进行自己的自增1操作,所以最终的计算结果为30

1.3 三目运算符

三目是一种赋值运算的形式,执行三目时可以以一个布尔表达式的结果进行赋值,基本的语法结构如下。

数据类型变量 = 布尔表达式 ? 满足此表达式时设置的内容:不满足此表达式时设置的内容;

//	案例8:使用三目运算符实现赋值
public class TestDemo(
	public static void main(String args[){
   
     
		int numA=10;  // 定义int型变量
		int numB=20;
		//如果numA 大于numB, 返回 true,则将numA 的内容赋值给max
		//如果numA 小于numB, 返回 false,则将numB 的内容赋值给max
		int max= numA>numB ? numA:numB;
		System.outprintln(max);
	}
}

程序执行结果:

20

此程序主要是判断 numAnumB 哪个变量的内容较大 (numA > numB), 如果此时的判断条件成立,则表示使用 numA 的变量内容为 max 变量赋值,反之,则使用 numB 的变量内容为max 变量赋值。

对于上面案例的操作,实际上也可以不使用三目运算符完成,可以通过编写如下形式的判断体语句完成:

//	案例9:利用判断语句实现三目运算的功能
public class TestDemo{
   
     
	public static void main(String args[]){
   
     
		int numA=10;
		int numB=20;
		int max=0;
		//用if语句替代:int
		if(numA>numB){
   
      // 如果numA 的内容大于numB,max 变量的内容为numA 的内容
			max=numA;
		}else{
   
     		//如果numA 的内容小于numB,max 变量的内容为numB 的内容
			max=numB;
		}
		System.out.println(max);
	}
}

程序执行结果:

20

此程序使用一个分支语句的形式替代了三目运算符的使用,但可以发现的是使用三目运算的赋值操作要明显比 if….else分支语句的判断赋值代码更简单。

1.4 逻辑运算

逻辑运算一共包含3种:与(多个条件一起满足)、或(多个条件有一个满 足)、非(使用“!”操作,可以实现 true 变 false 以及 false 变 true 的结果转换), 而与和或操作的真值表,如下表所示:

条件1 条件2 &、&&(与)结果 |、||(或)结果
true true true true
true false false true
false true false true
false false false false

1.4.1 与操作

与操作表示将若干个条件一起进行连接判断,同时满足返回 true,有一个不满足返回 false,对于与 操作有两种运算符:&(普通与)、&&(短路与)。

//	案例10:使用普通与“&”
public class TestDemo {
   
     
	public static void main(String args[]){
   
     
		if ((1!=2)&(10%2==0){
   
          // 使用普通与判断多个条件
			System.out.printIn("Hello World!");
		}
	}
}

程序执行结果:

Hello World!

程序逻辑:

*

图2案例程序执行逻辑

此程序最后输出了字符串,说明&的表达式中的结果值都为true,而现在有一种情况是,如果前面的条件已经返回了 false,后面不管有多少个 true, 按照与操作的 定义,最终的结果还是false,那么完全没有必要进行后续的判断,所以可以使用短路与进行操作:

//	案例11:使用短路与(&&)
public class TestDemo {
   
     
	public static void main(String args[]){
   
     
		if  ((1 ==2)&&(10/0==0)){
   
     
			System.out.printin("Hello World!");
		}
	}
}

程序执行结果: 正常结束。
程序逻辑:

*

图3案例程序执行逻辑

注意此程序不会因为(10/0==0)而报错,因为前面的条件返回了false(“1== 2”的结果为false),所以后面的所有判断都没有继续执行到,所以最终的结果只会是false, 而如果此时使用的是&而非&&则会导致报错,此处不再做更多演示。

1.4.2 或操作

或操作是若干个条件一起判断,其中只要有一个返回 true, 结果就是 true, 只有都返回 false 的时候结果才是 false, 或操作有两种运算: |||

//	案例12:使用普通或操作(|)
public class TestDemo(
	public static void main(String args[])(
		if((1==1)|(10/0==0)){
   
     
			System.out.println("Hello World !");
		}
	}
}

程序运行结果:

Exception  in  thread"main"java.lang.ArithmeticException:/  by  zero at TestDemo.main(TestDemo.java:3)

此程序中使用普通或“|”操作,但在程序运行的时候出现了异常,即程序中给出的两个判断条件都执行了:

*

图4案例程序执行逻辑

通过程序发现,使用普通或操作的过程中,即使前面的条件满足了,后面的也会进行正常的判断,而或运算中,只要有一个为 true, 那么最终的结果就一定是 true, 所以对于后面的判断似乎没有任何意义,因为不管返回是何种结果都不会影响最终的结果—true, 下面使用短路或(||) 来调整程序。

//	案例13:使用短路或操作(||)
public class TestDemo(
	public static void main(String args[]){
   
     
		if((1==1)||(10/0==0)){
   
     	
			System.out printIn("Hello World!");
		}
	}
}

程序执行结果:正常结束。

可以发现,前面的条件(1== 1)满足了就会返回 true, 不管后面是何条件最终的结果都是true, 所以后面的表达式不再执行,程序也没有任何异常产生。程序逻辑如下:

*

图5案例程序执行逻辑

需要注意的是,在实际生产应用编写代码的过程中考虑到性能问题,都会优先考虑短路与和短路或操作。

1.4.3 非操作

非就是针对布尔结果进行求反。

//	案例14:使用非操作(!)
public class TestDemo {
   
     
	public static void main(String args[]){
   
     
		boolean flag = true;                          //定义布尔型变量
		System.out.println(!flag);                  //对变量结果进行非操作
	}
}

程序执行结果:

false

非操作的主要功能是进行布尔结果的转换,由于程序中定义的 flag 变量的内容为 true, 所以经过 非处理之后其结果变为 false

1.5 位运算

位运算在Java 中有:&|^>><<>>>, 而所有的位运算都是采用 二进制数据进行操作的。

Java 定义的位运算(bitwise operators)直接对整数类型的位进行操作,这些整数类型包括 long,int,short,char 和 byte。
位运算符主要用来对操作数二进制的位进行运算,按位运算表示按每个二进制位(bit)进行计算,其操作数和运算结果都是整型值。

Java 语言中的位运算符分为位逻辑运算符和位移运算符两类:
(1)位逻辑运算符包含 4 个:&(与)、|(或)、~(非)和 ^(异或)
(2)位移运算符包含3个:<< 位左移、>> 位右移、>>> 无符号右移

*位运算规则

Java 定义的位运算直接对整数类型的位进行操作,运算时会先将十进制数据变为二进制数据。而十进制和二进制之间的数据转换规则如下:

十进制数据变为二进制数据的原则为:数据除2取余,随后倒着排列。例如:25 的二进值为11001,但是由于Java的int型数据为32位,所以实际上最终的数据 为:“0000000000000000000000000011001”。转变过程如下图:

*

然后再将二进制原码转成二进制补码,之后再正式进行运算。其中需要注意的点有:

  • 正数的原码,反码和补码都一样;
  • 负数的反码:符号位保持不变,其他位取反;
  • 负数的补码:反码 + 1;
  • 最高位为符号位,0表示正数,1表示负数;
  • 0的反码和补码都是0。

1.5.1 位与运算

//	案例15:使用位与操作
public class TestDemo{
   
     
	public static void main(String args[]){
   
     
		int numA= 9;                                           //定义整型变量
		int numB=11;                                         //定义整型变量
		System.out.println(numA & numB);//位与操作
	}
}

程序执行结果:

9

计算过程分析:
9的二进制: 00000000000000000000000000001001
11的二进制:00000000000000000000000000001011
&”结果: 00000000000000000000000000001001 转换为十进制是: 9

1.5.2 位或运算

//	案例16:使用位或操作
public class TestDemo {
   
     
	public static void main(String args[]){
   
     
		int numA =9;                                           //定义整型变量
		int numB=11;                                         //定义整型变量
		System.out.println(numA  |  numB);    // 位或操作
	}
}

程序执行结果:

11

计算过程分析:
9的二进制:00000000000000000000000000001001
11的二进制: 00000000000000000000000000001011
|”结果: 00000000000000000000000000001011 转换为十进制是: 11

* 总结

本文介绍了Java中常见的各类运算符,包括一元运算符、算术运算符、移位运算符、关系运算符、相等运算符、位运算符、逻辑运算符、条件运算符和赋值运算符等等。每种运算符都有其特定的运算方式和特征,可以应用于不同的场景。

运算符类型 作用 应用场景
一元运算符 用于对单个操作数进行操作,例如逻辑非、求反以及自增和自减等 在控制流语句和逻辑判断中非常有用
算术运算符 支持基本的数学运算,如加法、减法、乘法和除法等 用于处理数字计算和相关算术问题
移位运算符 可对二进制数据进行位级操作,包括左移、带符号右移和无符号右移 用于编码、解码和处理位模式数据
关系运算符 用于比较两个操作数的大小关系,例如小于、大于、小于等于和大于等于 用于判断条件和排序问题
相等运算符 用于判断两个操作数是否相等或不相等 在条件判断和对象比较等方面非常有用
位运算符 用于对整数类型的二进制数据进行位级操作,包括位与、位或和位异或等 在处理位标志、掩码和位操作等方面非常常见
逻辑运算符 用于对布尔值进行逻辑运算,包括逻辑与、逻辑或和逻辑非等 用于条件判断和逻辑表达式求值
条件运算符 是Java中唯一的三元运算符用于根据条件的结果选择执行不同的操作 经常用于编写替换简单的if-else语句
赋值运算符 用于将右侧的值赋给左侧的变量,并支持一些复合赋值运算符的使用 在数值计算和变量操作中非常频繁

在编写复杂的Java程序时,了解各类运算符的运算方式、特征以及运算符优先级是至关重要的。正确地应用运算符可以简化代码逻辑,提高程序的效率和可读性。

通过本文所提供的应用场景案例,读者可以进一步理解不同运算符的实际应用。掌握这些运算符的用法将帮助开发人员更好地处理问题并设计出更高效的算法。



本文部分案例及图片来源:
《第一行代码JAVA》

[* ]nbsp_nbsp 7