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

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

微信搜公众号:不会编程的程序圆

看更多干货,获取第一时间更新

如果想看更好的排版,可以阅读原文
点击阅读原文

思维导图


image

目录


@[toc]

正文


前言

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

  • 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);

//运行结果
30(11110)

注意: 当 & 和 | 的操作数为整数(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);

//运行结果:
4(0010)


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 语言相同,定义的 变量名 不能与 关键字 冲突。

用于定义访问权限修饰符 private protected public
定义类,函数,变量修饰符 abstract final static synchronized
定义类与类之间的关系 extends implements
定义建立实例以及引用实例,判断实例 new this super instanceof
用于异常处理 try catch finally throw throws
用于包 package import
其他修饰符 native strictfp transient volatile assert

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

https://github.com/hairrrrr/Java_SE_EnjoyLearning

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

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


以上就是本次的内容。

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

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

关注我,看更多干货!

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容