透析Java本质的36个话题02运算符与表达式

发布时间 2023-11-26 22:42:36作者: lartimes

1. 莫衷一是——i+++j该如何计算?

三个加号

​ 在java中默认 前面结合 也就是 (i++) + j

  int i = 25;
        int j = 2;
        int result = i++ + j;
        System.out.println(i);
        System.out.println(j);
        /*26   2*/

贪心规则

编译器的贪心规则,分析符号的时候,编译器会尽可能多地结合有效地符号

例如: i ++ + j
+ 、 ++ 都是有效的符号, 但是+++ 不是有效的。
而a - -b  a - 负b, 编译器会a-- b 编译错误

为何贪心?

贪心规则是有用的,因为这样可以对转义字符等进行特殊处理。

编译器尽可能多地对有效字符结合,否则转义字符将时区作用。 
对于“、1717” 、 “\431”,会按两个字符处理。因为这两个数值都炒股了八进制转义字符的取值范围("\0" -- "\377");

2.千差万别——++i与i++仅是“先加”与“后加”的差别吗?

前置++ 与 后置++

​ 举出一个特殊的例子

  int i = 25;
i = i++;//这里是后置
System.out.print(i);//25

后置++ 的自白

//前置
int i= 25;
int j = ++i * 25;

//编译之后
i+=1;
int j = i * 25;
//后置
int i= 25;
int j = i++ * 25;

//编译之后
int temp  = i;
i+=1;
int j = temp * 25;

3.大相径庭——相除与求余在Java中的具体表现

整型相除与求余运算的表现。
浮点类型相除与求余运算的表现。
浮点相除与求余运算的各种特殊情况。
浮点值+0与-0的差别。

特殊的浮点值

   int a = 25;
        float b = 23.5f;
        float divided = 0.0f;
        try {
            int c = a/0;
        } catch (Exception e) {
            System.out.println("int 0 divide");
        }
        try {
            int c = a%0;
        } catch (Exception e) {
            System.out.println("int 0 mod");
        }

        try {
            float c = b/0.0f;
        } catch (Exception e) {
            System.out.println("float 0 divide");
        }
        try {
            float c = b%0.0f;
        } catch (Exception e) {
            System.out.println("float 0 mod");
        }

除数为0的浮点运算
Infinity 、 -Infinity 、 NaN

+0 -0 的差异

1.当+0 -0参与浮点类型的相关运算,符号不同
2.+0 -0 在浮点类型变量存储中,符号位是不同的
3.Java类库中的某些类也是吧浮点类型的+0 -0视为完全不同的力两个1数值处理

4.移形换位-移位运算的真实剖析

​ Java中三bit运算符 左移<< 、右移>>、无符号右移>>>

3种移位运算符的使用。
移位运算对右侧操作数的处理。
移位运算与乘除运算的关联。
无符号右移。

超过自身位数1的移位置

​ 3 >> 32
对于整形来说,Java会首先对移动的bit位进行取余操作,int/long最大的bit位作为模量
​ 当移位为 负数时候。

左边为int类型, 右侧操作数只有低5位是有效的。首先与0x1f进行与运算,再进行位运算。
同样,long只有低6位有效, 可以看作右侧操作数与0x3f做与运算

移位运算与乘除运算

*左移一位 === 2 、 右移一位 === 1/2 : 前提条件是是奇数, 因为涉及到舍入问题

也就是: 一旦不能整除,就会涉及到舍入模式

-9 /2 == -4 (向上舍入 趋于0)
-9 >> 1 == -5 (向下舍入 )
所以,乘以2"与左移n位的值是相等的,如果可以整除,除以2"与右移n位的值也是相等的。如果不能整除,当被除数为正数时,除以2"与右移n位的值相等,当被除数为负数时,除以2"与右移n位的值则是不相等的。

        int a = -8;
        int b = a << 1;
        System.out.println(b);
        int c = a >>> 1; //2147483644
        //补码进行运算, 所以会溢出。
        // 无符号>>> 左侧符号0
        System.out.println(Integer.toBinaryString(a));
//11111111111111111111111111111000
        System.out.println(Integer.toBinaryString(c));
//01111111111111111111111111111100

5.鞭劈近里-条件运算符(? : )的深入

" ? :"条件表达式的类型

  • 条件运算含有三个表达式,表达式1必须为booleaan 或Boolean类型,表达式2与表达式3可以i是任意类型,根据表达式1的取值不同,只会计算表达式2与表达式3 其中的一个。
  • 根据表达式2与3的类型不同,条件表达式的类型也会不对。

6.井然有序-运算顺序的详细挖掘

从左到右的计算顺序

  int b =  a +  (++a) + (a = 1) + a; // 5 a=1  1 + 2 + 1 + 1;

复合运算符

复合运算符可以自动将右侧运算的结果转华安为左侧操作数的类型

byte b = 25;
b = b + 1;//编译失败
b+=1;//编译通过

7.异曲同工-变换变量的3种方式

  1. 中间变量

  2. 相加减

  3. 异或操作

       int a = 5;
          int b = 25;        System.out.println(Integer.toBinaryString(a));        System.out.println(Integer.toBinaryString(b));
            // a: 0 0101
             // b :1 1001
            a = a^ b;
            // 11100
            b = a ^b;
            //00101
            a = a ^ b; 
    

8.择木而栖-开关选择表达式switch的类型内幕

对包装类的处理

 Integer a = 2;
switch (a){ //编译之后, a.intValue();
    case 2->{
        System.out.println("2");
    }
    case 3->{
        
    }
     default -> throw new IllegalStateException("Unexpected value: " + a);
 }

对枚举类的处理

对于枚举类型, 首先会在内部生成一个匿名类, 该匿名类含有一个int[]类型的静态final成员变量,数组的长度位枚举常量的个数,数组元素的值位枚举常量的序数(ordinal方法返回的值)。
	switch对枚举进行处理时, 辅助的静态匿名类 由编译器生成。如果子集生命匿名类, 类中不允许有静态成员

对String类型的处理

会将switch语句拆分成两个switch语句, 第一个1switch根据1对象哈希码对应一个1临时变量赋值,第二个switch根据这个值匹配1case 。

String s="Apple";String sl=S;
byte byte0 =-1;
switch (sl.hashCode()) {
	case 1982479237:
		if (sl.equals( "Banana")){
		byte0=0;
		break;
	case63476538:
		if(sl.equals( "Apple")){
		byte0 =1;
		break;
switch (byte0){
case0:
System.out.println("B");break;
case l:
System.out.println("A");break;

	switch表达式可以是 byte、short、char、int、Byte、Short、Character、Integer、String或枚举类型。
	case表达式必须是常量表达式或枚举常量名,并且其类型可以赋值给switch表达式类型。switch表达式的类型为基本数据类型的包装类型时,将包装类型拆箱为基本数据类型。
	当switch类型为枚举类型时,会创建一个匿名类来辅助完成。
	当switch类型为String类型时,将switch语句拆分为两个switch语句,分别对 String对象的哈希码及临时变量来辅助完成。