Java 之路 (三) -- 操作符

发个牢骚,最近看 《Thinking in Java》,不知道是不是我的错觉,总觉得里面写的知识虽然很循序渐进,但是总是很散乱,对每个知识点没有总结性质的叙述。大概这就是我太菜了吧。

另外,我总是在途中下意识以为,我写这篇文章是给彻头彻尾的小白看的。但是其实不是,我只是记录书中的知识点,学习之余复习罢了。

告诫自己,我的初衷是什么。


学习内容:

操作符的使用 及一些 易错点 (这里的 操作符等同于运算符)

  • 算数操作符
  • 赋值操作符
  • 关系操作符
  • 逻辑操作符
  • 按位操作符
  • 移位操作符
  • 三元操作符
  • 字符串操作符
  • 类型转换操作符。

由于操作符在各个语言里都存在,而 Java 和 C/C++ 里的操作符相差不大,所以基础一带而过,易错点重点强调,


1. 使用 Java 操作符

(1) 操作对象:

  • “=”、“==”、“!=” 这三个操作符可以操作所有对象
  • “+”、“+=” 支持操作基本数据类型 + String 类型
  • 其余操作符只能操作 基本数据类型

(2) String 配合 “+” 时会发生类型转换,比如 String a = "a"+12;,会把 int 型的 12 (任何非 String 类型的数据)转换成 String 类型然后接在 “a” 后面。

(3) 运算符的优先级

Java 之路 (三) -- 操作符_第1张图片
20160507105151091.jpg

(4) 直接常量:

  • 简单来说就是在 常量前/后面加上特定的字符 以准确的告知编译器生成什么样的类型。

  • 对应关系:

    • long -> 后缀 L/l
    • float -> 后缀 F/f
    • double -> 后缀 D/d
    • 十六进制 -> 前缀 0X/0x
    • 八进制 -> 前缀 0
  • 举例:

    long a = 10L;
    float b = 10f; 
    int i1 =0x2f;
    int i2 = 027;
    double c = 10d;
    

(5) 指数计数法

  • 用字符 e 表示对数中的 e
  • 举例
    float x = 1.39e43f,表示1.39e^43

(6) Java 中没有 sizeOf

  • 原因是对于 Java 而言,所有数据类型在所有机器中的大小是相同的。

2. 算术操作符

(1) 涉及的具体操作符:

  • +、-、*、/、%

(2)注意问题

  • 计算过程中,可能会出现精度的转换(精度为表达式中最高的精度)

    int a = 1234;
    a = a / 100 * 100;
    
    //结果为 a = 1200
    //原因是 1234 / 100 = 12.34,但是它会自动转换成 int 类型,
    //小数点舍弃就成了 12,12 * 100 = 120
    //所以最后结果为 1200
    
  • 一元加(+)、一元减(-)

    • 一元减表示 负数
    • 一元加没什么实际意义,唯一的作用是将较小类型的操作数的精度提升至 int 型。
  • 取模运算 %

    • 适用于除布尔类型以外的所有基本数据类型
  • 运算与赋值结合

    • 涉及符号:+=、-=、*=、/=、%=
    • 意义:以 += 为例,a+=b 表示 a = a + b,即 计算 a + b 的值,然后把这个值赋值给 a。
  • 在计算的时候, “+” ,“+=”是运算符,在字符串中“+”,“+=”是连接符。

(3) 自增(++)和自减(--)

这是很容易疑惑的点,这里特意拿出来强调。

  • 首先是二者的意义:++ 表示增加 1 ,-- 表示减少 1。

  • 其次是使用方式:前缀式(形如 ++a)和 后缀式(形如 a++)

    • 前缀式意味着 先生成值,后执行运算

    • 后缀式意味着 先执行运算,后生成值

      简单来说就是,把这个变量用作他处 和 改变变量本身值 的前后顺序,举个栗子:

    int i = 1;
    System.out.println("i:" + i);
    System.out.println("++i:" + ++i);//先生成值(i=2),后执行运算(输出2)
    System.out.println("i++:" + i++);//先执行运算(输出2),后生成值(此时i=2+1=3)
    System.out.println("i:" + i);//输出3
    System.out.println("--i:" + --i);//先生成值(i=2),后执行运算(输出2)
    System.out.println("i--:" + i--);//先执行运算(输出2),后生成值(此时i=2-1=1)
    System.out.println("i:" + i);//输出 1
    
    /*输出为:
    i: 1
    ++i: 2
    i++: 2
    i: 3
    --i: 2
    i--: 2
    i: 1
    */
    

3. 赋值运算

(1) 涉及的操作符为:“=”

(2) 注意问题:

  • 常数不能作为左值
  • 基本类型赋值:a=b,此时是将 b 的内容复制给 a,接着改变 a,b 不会受到影响
  • 对象赋值:a=b,实际上是将 b 这个"引用"复制给了 a,即此时 a、b 两个引用指向同一个对象。同时 a 原本指向的对象会丢失。
  • 在条件判断时,如果写成 while(a=b) 会报错,Java 中 a=b 的结果并非布尔值,而只有布尔值能作为条件判断的表达式。相反在 C/C++ 中,a=b 相当于 一个非 0 的值,而任何非0的值逻辑上都等价于 true,所以在 C/C++中,这样写会死循环。

4. 关系操作符

(1) 也可以称作 比较 操作符/运算符,涉及的操作符为:

  • ==、>=、>、<、<=、!=

(2) 关系操作符生成的是一个 boolean 结果

(3) 特殊问题(== 和 !=):

  • 对于基本数据类型:== 和 != 比较的是值本身。

  • 对于非基本数据类型:== 和 != 比较的是对象的引用

    如果需要比较对象的内容是否相等,则需要通过 equals() 方法,某些情况下需要我们覆盖该方法,以实现比较内容。


5. 逻辑操作符

(1) 涉及的操作符为

  • &&(与)、||(或)、!(非)

(2) 生成的是一个 boolean 结果

(3) 特殊问题:

  • Java 中只能将逻辑操作符用于 boolean 类型的数据上,同时不能将非 boolean 值用在逻辑表达式中,这有别于 C/C++(C 中任何非 0 的数字都可以表示 逻辑 true)
  • Java 中存在短路现象:即 一个逻辑表达式前半段已经得出结果时,后半段不会被执行,比如 (true || 1 == 2),由于 true 已经保证这个表达式的最终结果是 true,所以后面的 1==2 不会被执行。

6. 按位操作符

(1) 涉及的操作符为:

  • &(按位与)、|(按位或)、^(按位异或)、~(按位非)

(2) 操作对象:二进制的"位"

(3) 操作的结果是 boolean 值

(4) 按位操作符可以与 "=" 连用,也表示先运算再赋值

(5) 运算规则

操作符 运算 规则 示例 结果
&(二元) AND(与) 同时为1,结果才为1 1 & 1
1 & 0
1
|(二元) OR(或) 有一个为1,结果即为1 0 | 1
0 | 0
1
0
^(二元) XOR(异或) 二者不同,结果为1 1 ^ 1
1 ^ 0
0
1
~(一元) NOT(非) 按位取反 1
0
0
1

7. 移位操作符

(1) 涉及的操作符:

  • <<(左移位)、>>(有符号右移位)、>>>(无符号右移位)

(2) 操作对象:二进制的"位",只能处理整数类型(基本类型)

(3) 移位规则

  • <<:将 左侧的操作数向左移动,移动的位数为右侧操作数的值(低位补0)
  • >>:将 左侧的操作数向右移动,移动的位数为右侧操作数的值(若符号为正,则高位补0;若符号为负,高位补1)
  • >>>:>>的基础上,无论正负,都在高位补 0

8. 三元操作符 if-else

(1) 也成为条件操作符,这不同于下一章提到的控制执行流程的 if-elseif-else

(2) 形式为:

  • boolean-exp ? value0 : value1;
  • 判断 boolean-exp 的结果,如果是 true,执行 value0;如果是 false,执行 value1;

(3) 三元操作符会产生一个值,value0 或 value1;而普通的 if-else 控制结构是不会产生值的。


9. 字符串操作符

(1) 涉及的操作符

  • + 和 +=
  • 表示字符串的连接

(2)注意问题:

  • 一个表达式以字符串起头的话,那么后续所有操作数都必须是字符串型(也就是说会强转为字符串类型)

    String s = "a + b + c ";
    int a=1,b=2,c=3;
    System.out.println(s + a + b + c);
    //输出结果为:a+b+c 123
    //因为会先将 a,b,c分别转换为字符串类型,然后再拼接在一起
    
    System.out.println(s + (a + b + c));
    //此时输出结果为 a+b+c 6
    

10. 类型转换操作符

(1) 形式:"(" + "目标类型" + )",比如:

int i = 100;
long i1 = (long)i;

(2) 截尾和舍入

  • flaot 和 double 转型为整型值时,会对该数字进行截尾(即舍弃小数点部分,只保留整数部分)
  • 如果需要舍入的结果:使用 java.lang.Math 中的 round() 方法

(3) 提升

  • 表达式中出现的最大的数据类型决定了表达式最终结果的数据类型。
  • 比如:flaot 值 和 doule 值相乘,结果就是 double

总结

本章介绍的就是些基本的操作符,或者说运算符,倒是没什么难点,不过还是有一些点需要注意,在文中我也特意指出来了。

这里我还是忍不住吐槽一句,《Thinking in Java》对操作符的分类有点迷,且不论操作符和运算符二者的叫法问题,比如 移位和按位操作符通常都归入位运算符这,而本书中却强行分开,总感觉分类有些过细了,当然这只是我个人看法而已。

本以为这一章会特别的枯燥,事实也的确如此,实际上还是发现了一些原本忽视的点,比如针对 a=b 是否能用于条件判断这一点,一直深受 C 的影响,只不过由于良好的编程习惯才没有犯错(笑),不过现在也算是排除了这一点错误,也是有所收获。

最后,希望本文对大家也有所帮助,共勉。

你可能感兴趣的:(Java 之路 (三) -- 操作符)