运算符使用细节
double除法的细节
public static void main(String[] args){
double a = 10 / 4;
double b = 10.0 / 4;
System.out.println(a);
System.out.println(b);
}
整数相除只会保留整数(无论是变量还是常量都一样),然后再赋给double,因此a为2。10.0为double类型,double/int 或者 double/double 都会保留小数,因此b为2.5。
取余的本质
public static void main(String[] args){
int a = -10 % 3;
int b = 10 % -3;
System.out.println(a);
System.out.println(b);
}
取余的本质是一个公式—— a % b = a - a / b * b 。
前置++和后置++
用临时变量的规则进行解释。
前置++:先自增,再进行相关操作——对于 b = a++,(1) a = a + 1; (2) temp = a; (3) b = temp;
后置++:先进行相关操作,后自增——对于 b = a++,(1) temp = a; (2) a = a + 1; (3) b = temp;
public static void main(String[] args){
int a = 10;
int b = a++;//先把a赋给b,a再加一
int c = 10;
int d = ++c;//c先加一,再把c赋给d
System.out.println("a="+a);
System.out.println("b="+b);
System.out.println("c="+c);
System.out.println("d="+d);
}
int i = 1;
i = i++;
根据规则进行判断—— (1) temp = i; (2) i = i +1; (3) i = temp; 因此最终i仍然为1。
int i = 1;
i = ++i;
根据规则进行判断—— (1) i = i + 1; (2) temp = i; (3) i = temp; 因此最终i为2。
三元运算符里的++和—:
int a = 10;
int b = 99;
int result = a < b ? a++ : b--;
System.out.println("result=" + result);
System.out.println("a=" + a);
System.out.println("b=" + b);
a<b为真,返回a++,因为是后置++,因此返回a后,a再加一,对b不进行操作。
赋值语句的bool值问题
boolean a = false;
if(a = false)//这里是赋值表达式
System.out.println(111);//没有输出
System.out.println(a);//a最后仍为false
boolean类型在实际编译的过程都是转化为int类型进行底层运算的,false转为0,true转为非0整数。 if(a = false) ==> if((a = 0) != 0) 也就是a先赋为0,再判断是否不等于0,结果为false,不输出。
同理 if(a = true) ==> if((a = 1) != 0) a先赋为1,再判断是否不等于0。
短路与和逻辑与
短路与:&& 逻辑与:&
两者的共同点:判断结果相同,全部都是true则为结果true,出现一个false则结果为false。
两者的不同点:对于&&短路与而言,如果第一个条件为false,后面的条件就不会再判断。对于&逻辑与而言,如果第一个条件为false,后面的条件仍然会判断。&&效率较高。
public static void main(String[] args){
int a = 5,b = 9;
if(a < 1 && ++b < 50) {//短路与
System.out.print("");
}
System.out.print("a=" + a + " b=" + b);//结果b仍为9,说明后面没有判断,++没起作用
}
public static void main(String[] args){
int a = 5,b = 9;
if(a < 1 & ++b < 50) {//逻辑与
System.out.print("");
}
System.out.print("a=" + a + " b=" + b);//b为10,++起作用了
}
同理,短路或(||)与逻辑或(|)的区别就是——短路或如果第一个条件为true,则第二个条件不会判断,最终结果为true,效率高。 而逻辑或不管第一个条件是否为true,第二个条件都要判断。
开发中基本使用 && 和 || 。
逻辑异或(a ^ b)—— 当a和b不同时,结果为true,否则为false。
四种进制
进制简介
二进制:0-1,满2进1,以0b或0B开头。
十进制:0-9,满10进1。
八进制:0-7,满8进1,以数字0开头。
十六进制:0-9以及A(10)-F(15),满16进1,以0x或0X开头表示,A-F不区分大小写。
二进制转十进制
从最低位开始(最右边),将每个位上的数提取出来,乘以2的(位数-1)次方,然后求和。对于八进制和十六进制转十进制,只需要把2换成8或16即可。
十进制转二进制
将该十进制数不断除以2,直到商为0为止,然后将每步得到的余数倒过来,就是对应的二进制。对于十进制转八进制和十六进制,只需把除以2改为除以8或16。
二进制转八进制
从低位开始(最右边),将二进制数每三位一组(因为二进制111正好为7),转成对应的八进制数即可。如果最后不够三位,在最前面补零。
举例:0b11010101 —— 101为5,010为2,011为3,按顺序摆放,结果为 0325。
二进制转十六进制
从低位开始,将二进制数每四位一组(因为二进制1111正好为15),转成对应的十六进制数即可。
举例:0b11010101 —— 0101为5,1101为13即D,排好序结果为0xD5。
八进制转二进制
将八进制数每一位,转成对应的一个三位的二进制数即可,不足三位前面补零。
举例:0237 —— 2为10(即010),3为11(即011),7为111,整体为 0b010 011 111。
十六进制转二进制
将十六进制数每一位,转换成对应的一个四位的二进制数即可,不足四位前面补零。
举例:0x23B —— 2为 0010,3为 0011,B为 1011,整体为 0b0010 0011 1011。
位运算符
原码、反码、补码
- 二进制的最高位是符号位——0表示整数,1表示负数。
2. 正数的原码,反码,补码都一样(三码合一)。
3. 负数的反码 = 它的原码符号位(也就是最高位)不变,其它位取反(1变0,0变1)。
4. 负数的补码 = 反码 + 1。
5. 数字0的反码,补码都是0。
6. Java中的所有数都是有符号的。
7.在计算机运算的时候,都是以补码的方式进行运算的。当我们看运算结果的时候,要看它的原码。位运算符介绍
按位与 &:两位全是1,结果为1,否则为0。
按位或 | :两位有一个为1,结果为1,否则为0。
按位异或 ^ :两位一个为0,一个为1(也就是不同),结果为1,否则为0。
按位取反 ~ :把0变成1,把1变成0。
算数右移 >> :从最低位开始删除n个字符,如果该数为正,则高位补0,若为负数,则高位补1
算数左移 << :从符号位右边开始删除n个字符,不分正负数,低位补0
逻辑右移(无符号右移)>>> :从最低位开始删除n个字符,不管是正数还是负数,高位都补零。
举例:
2&3 的计算——
2的原码为 00000000 00000000 00000000 00000010
由三码合一原则得,2得补码也为 00000000 00000000 00000000 00000010
同理得3的补码为 00000000 00000000 00000000 00000011
2&3为 00000000 00000000 00000000 00000010 (根据补码进行计算),这是一个正数,原码与补码相同,得到2&3为2。
~ -2 的计算:
先得到 -2 的原码 10000000 00000000 00000000 00000010 (可以简写成 10000010)
再得到 -2 的反码 11111111 11111111 11111111 11111101
最后得到 -2 的补码 11111111 11111111 11111111 11111110 (补码等于反码加一)
~ -2操作后为 00000000 00000000 00000000 00000001
这就是运算后的补码,因为操作之后变成了一个正数,因此三码合一,运算后的原码与补码相同,得到 ~ -2为 1。
~2 的计算:
先得到 2的原码 00000000 00000000 00000000 00000010,根据三码合一原则,补码相同。
~2操作后为 11111111 11111111 11111111 11111101 得到运算后的补码。
再得到运算后的反码 11111111 11111111 11111111 11111100 (反码等于补码加一)
最后得到运算后的原码 10000000 00000000 00000000 00000011 (注意最高位不变)
根据原码计算,得到 ~2 为 3。
主要就是注意:计算后得到的是补码,根据正数还是负数进行转换,转换成反码,再转换成原码,反码转原码最高位不变。
20 >> 2 的计算:
20的原码为 00000000 00000000 00000000 00010100 (可简写为 00010100)
20的补码与原码相同,为 00010100,向右删除2位,结果为 000101,然后在高位补上2个0(因为是正数),结果为 00000101,十进制为5(也就是20 / 2 / 2)
-20 >> 2 的计算:
-20的原码为 10000000 00000000 00000000 00010100 (简写为 10010100,第一位是符号位)
-20的反码为 11101011 补码是 11101110,向右删除2位,结果为 111011,在高位补上2个1,结果为 11111011(计算后的补码),计算后的反码为 11111010,计算后的原码为 10000101,得到结果为 -5 (注意负数不一定是除以n个2,比如 -7>>2,结果为-2)。
-20 >>> 2的计算:(注意这里负数就不能用简写了,因为补充的内容与符号位相反)
-20的原码是 10000000 00000000 00000000 00010100
-20的反码是 11111111 11111111 11111111 11101011
-20的补码是 11111111 11111111 11111111 11101100
向右删除2位,结果为 11111111 11111111 11111111 111011
在高位补上2个0,结果为 0011111111 11111111 11111111 111011 (操作后的补码)
这里需要注意一点—— >>>运算符的结果,就是操作后的补码!所以最终结果为 1073741819(也就是这个补码所对应的十进制值,不用再计算它的原码了)。