【0 基础学 Java】(四)运算符

【0 基础学 Java】(四)运算符

码字不易,对你有帮助 点赞/转发/关注 支持一下作者

思维导图


目录


正文


前言

在正式开始讲 运算符 之前,我们先来讨论一下上节课我们所学的 变量 的一个注意点。

  • byte 与 char
  • short 与 char

上面两组类型之间的转换不管是从小到大还是从大到小,都需要进行强制类型转换

public class helloWorld{
	
	public static void main(String[] args) {
		
		byte bt = 10;// byte 类型大小为 1 个字节
		char ch = ' ';// char 类型大小为 2 个字节
		short sh = 10;// short 类型大小为 2 个字节
		
		ch = bt;// 将 1 个字节的 bt 赋值给 2 个字节的 ch
		//编译会报错:不兼容的类型: 从byte转换到char可能会有损失
		
		ch = sh;
		sh = ch;
		//编译器还是会报错:不兼容的类型:从short/char转换到char/short可能会有损失
	}
}

原因:

1、char 是字符型,而 byte 和 short 是数值型,他们之间不建议转换。

2、char 类型字符对应的 十进制 是没有负数的。


一 运算符

1. 算术运算符

+

-

*

/

%

注意:

  • int / int 结果还是 int, 需要使用 double 来计算

    int a = 1;
    int b = 2;
    System.out.println(a / b);
    
    // 结果为 0
    

    如何正确的输出我们想要的 0.5 呢?

    //以下三种方式得到的结果都是 0.5
    System.out.println(1.0 / 2);
    System.out.println(1 / 2.0);
    System.out.println(1.0 / 2.0);
    

    需要注意的是,在 1.0 / 2 时,1.0 无疑是 double 类型,在运算时 2 也会被提升为 double 类型,也就是 1.0 / 2.0

  • 0 不能作为除数

    int a = 1;
    int b = 0;
    System.out.println(a / b)
        
    // 运行结果
    Exception in thread "main" java.lang.ArithmeticException: / by zero
    at Test.main(Test.java:5)
    
  • % 表示取余,不仅仅可以对 int 求模,也能对 double 来求模

    System.out.println(11.5 % 2.0);
    
    //运行结果
    1.5
    
  • % 的操作数出现负数

    System.out.println(5 % 2);
    System.out.println(5 % -2);
    System.out.println(-5 % -2);
    System.out.println(-5 % -2);
    
    //运行结果
    1
    1
    -1
    -1
    

    我们在 【C语言必知必会】的【C语言入门到精通】的运算符一节中讨论过这个问题。

    简单的来说,结果正负取决于 左操作数 的正负


+=

-=

*=

/=

%=

int a = 10;
a += 1; // 等价于 a = a + 1
System.out.println(a);

//运行结果
11

++

--

int a = 10;
int b = ++a;
System.out.println(b);
int c = a++;
System.out.println(c);

//运行结果
11
11

结论:

  1. 如果不取自增运算的表达式的返回值, 则前置自增和后置自增没有区别。
  2. 如果取表达式的返回值, 则前置自增的返回值是自增之后的值, 后置自增的返回值是自增之前的值。

思考题:下面程序会输出什么?

int i = 10;
		
i = i++;
System.out.println(i);

点击查看答案

2. 关系运算符

==

!=

<

>

>=

<=


int a = 10;
int b = 20;
System.out.println(a == b);
System.out.println(a != b);
System.out.println(a < b);
System.out.println(a > b);
System.out.println(a <= b);
System.out.println(a >= b);

//运行结果
false
true
true
false
true
false

注意: 关系运算符的表达式返回值都是 boolean 类型。


3. 逻辑运算符

注意: 逻辑运算符的操作数(操作数往往是关系运算符的结果)和返回值都是 boolean 。

这一点是和 C 语言不同的地方:

int a = 1, b = 2;
		
System.out.println(a && b);

//编译错误
helloWorld.java:7: 错误: 二元运算符 '&&' 的操作数类型错误
System.out.println(a && b);
                     ^

应当做出如下修改:

boolean flag1 = false, flag2 = false;
		
System.out.println(flag1 && flag2);

//运行结果:
false

逻辑运算符主要有三个:

&&

||

!


逻辑与 &&

规则: 两个操作数都为 true, 结果为 true, 否则结果为 false 。

int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b && b < c);

//运行结果
true
逻辑或 ||

规则: 两个操作数都为 true, 结果为 true, 否则结果为 false 。

int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b || b > c)
    
//运行结果
true

逻辑非 !

规则: 操作数为 true, 结果为 false; 操作数为 false, 结果为 true(这是个单目运算符, 只有一个操作数)

int a = 10;
int b = 20;
System.out.println(!a < b);

//编译错误
! 只能作用于 boolean 类型,而 a 是 int 类型

短路求值

&& 和 || 遵守短路求值的规则。

System.out.println(10 > 20 && 10 / 0 == 0);
System.out.println(10 < 20 || 10 / 0 == 0);

//打印结果:
false
true

我们都知道, 计算 10 / 0 会导致程序抛出异常。但是上面的代码却能正常运行, 说明 10 / 0 并没有真正被求值。


结论:

  • 对于 && ,如果左侧表达式值为 false, 则表达式的整体的值一定是 false, 无需计算右侧表达式
  • 对于 || ,如果左侧表达式值为 true, 则表达式的整体的值一定是 true, 无需计算右侧表达式

& 和 | (不推荐使用)

& 和 | 如果操作数为 boolean 的时候, 也表示逻辑运算. 但是和 && 以及 || 相比, 它们不支持短路求值

System.out.println(10 > 20 & 10 / 0 == 0); // 程序抛出异常
System.out.println(10 < 20 | 10 / 0 == 0); // 程序抛出异常
4、位运算符

位运算符主要有 4 个:

&

|

~

^

位操作表示 按二进制位运算。计算机中都是使用二进制来表示数据的(01构成的序列), 按位运算就是在按照二进制位的
每一位依次进行计算。(这与 C 语言基本相同,我们在 C 的教程中也详细讲过,这里不做展开。)

按位与:&

如果两个二进制位都是 1, 则结果为 1, 否则结果为 0 。

int a = 10;//01010
int b = 20;//10100
System.out.println(a & b);

//运行结果:
0

操作数有负数的情况

byte a = -1;//1111 1111
byte b = 13;//0000 1101
 
 System.out.println(a & b);

//运行结果:
13

byte a = -1;//1111 1111
byte b = -2;//1111 1110

System.out.println(a & b);

//运行结果:
-2

这说明,负数补码的符号位是参数 & 运算的。

按位或:|

如果两个二进制位都是 0, 则结果为 0, 否则结果为 1 。

int a = 10;//01010
int b = 20;//10100
System.out.println(a | b);

//运行结果
3011110

注意: 当 & 和 | 的操作数为整数(int, short, long, byte) 的时候, 表示按位运算, 当操作数为 boolean 的时候, 表示逻辑运算 。

按位取反:~

如果该位为 0 则转为 1, 如果该位为 1 则转为 0 。

int a = 0xf;
System.out.printf("%x\n", ~a);

//运行结果:
fffffff0

解析:

  • 0x 前缀的数字为 十六进制 数字. 十六进制可以看成是二进制的简化表示方式. 一个十六进制数字对应 4 个二进制位.
  • 0xf 表示 10 进制的 15, 也就是二进制的 1111
  • printf 能够格式化输出内容, %x 表示按照十六进制输出(在 C 语言中,转换说明 x 表示以十六进制打印 unsigned int 类型的值,unsigned int 是 4 个 字节,Java 中虽然没有 unsigned int 但是 %x 应该同 C 一样打印 4 个字节。所以,a 虽然是 0xf, 但是被编译器看作是:0x0000000f )。
  • \n 表示换行符
按位异或:^

如果两个数字的二进制位相同, 则结果为 0, 相异则结果为 1 。

byte a = 10;//1010
byte b = 14;//1110
System.out.println(a ^ b);

//运行结果:
40010

5、移位运算(了解)

如果你想搞明白,可以去看看我的 C 语言的操作符的文章 和 【C进阶】第一节数据存储。

<<

>>

>>>


左移:<<

最左侧位不要了, 最右侧补 0 。

int a = 0x10;

System.out.printf("%x\n", a << 1);

//运行结果:(注意打印的格式是 16 进制)
20(相当于乘以 2
右移:>>

最右侧位不要了, 最左侧补符号位(正数补0, 负数补1) 。

int a = 0x10;
//0x10 -> 16 -> 0001 0000 >> 1 -> 0000 1000 -> 8

System.out.printf("%x\n", a >> 1);

// 运行结果
8(相当于除以 2

int b = 0xffff0000;//这是一个负数

System.out.printf("%x\n", b >> 1);

// 运行结果
ffff8000
无符号右移:>>>

最右侧位不要了, 最左侧补 0 。

int a = -1;
System.out.println(a >> 1);
System.out.println(a >>> 1);

//运行结果:
-1 
2147483647

思考一下:

byte a = -1;

System.out.println(a >>> 1);//这样会得到 127吗?

//运行结果:
2147483647

为什么会输出这样的值?

前面我们说过,运算过程中 byte,short 这类大小小于 4 个字节的类型会进行数值提升,转化为 int


那么这样可以吗?

byte a = -1;// 1111 1111
//a >>> 1 -> 0111 1111 1111 1111 1111 1111 1111 1111
byte b = (byte)(a >>> 1);
//知道了数值提升,我们这样将运算后的 int 转化为 byte ,这样可以得到正确结果吗? 

System.out.println(b);

//运行结果:
-1

这是因为:第二步强制类型转换时,int 会发生截断,byte 只得到 int 的后 8 位:1111 1111。在输出 b 时,1111 1111 还是会被当作 -1 。这样看似 >>> 操作符没有什么卵用,但是我们应该知道,在计算机内部真实的情况。

总结:
  1. 左移 1 位, 相当于原数字 * 2. 左移 N 位, 相当于原数字 * 2 的N次方。
  2. 右移 1 位, 相当于原数字 / 2. 右移 N 位, 相当于原数字 / 2 的N次方。
  3. 由于计算机计算移位效率高于计算乘除, 当某个代码正好乘除 2 的N次方的时候可以用移位运算代替。
  4. 移动负数位或者移位位数过大都没有意义 。
6、条件运算符

表达式1 ? 表达式2 : 表达式3

**含义:**当 表达式1 的值为 true 时, 整个表达式的值为 表达式2 的值; 当 表达式1 的值为 false 时, 整个表达式的值为 表达式
3 的值

// 求两个整数的最大值
int a = 10;
int b = 20;
int max = a > b ? a : b;
7、运算符优先级

运算符之间是有优先级的. 具体的规则我们不必记忆. 在可能存在歧义的代码中加上括号即可 。

想看详细的还是去看我 C 语言运算符相关的教学。

总结
  1. % 操作再 Java 中也能针对 double 来计算 。
  2. 需要区分清楚 前置自增 和 后置自增之间的区别 。
  3. 由于 Java 是强类型语言, 因此对于类型检查较严格, 因此像 && 之类的运算操作数必须是 boolean 。
  4. 要区分清楚 & 和 | 什么时候是表示按位运算, 什么时候表示逻辑运算 。

二 注释

Java 的注释方式和 C 一样,主要有以下几种:

//行注释
/*这是
一个
块注释*/
/*
 *这是
 *文档
 *注释
 */

三 关键字

与 C 语言相同,定义的 变量名 不能与 关键字 冲突。

用于定义访问权限修饰符privateprotectedpublic
定义类,函数,变量修饰符abstractfinalstaticsynchronized
定义类与类之间的关系extendsimplements
定义建立实例以及引用实例,判断实例newthissuperinstanceof
用于异常处理trycatchfinallythrowthrows
用于包packageimport
其他修饰符nativestrictfptransientvolatileassert

[0 基础学 java ] 系列的代码可以在我的 Github 仓库查看,地址如下:

https://github.com/hairrrrr/Java_SE_EnjoyLearning

欢迎 star !(点一个 star 方便你下回查看)

本系列的教学也可以在 GitHub 观看(GitHub 上看教学的好处是所有文章的目录比较清晰)。


以上就是本次的内容。

如果文章有错误欢迎指正和补充,感谢!

最后,如果你还有什么问题或者想知道到的,可以在评论区告诉我呦,我可以在后面的文章加上你们的真知灼见。

关注我,看更多干货!

我是程序圆,我们下次再见。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值