目录
一、赋值运算符
二、算数运算符
三、拓展算数运算符
(1)
(2)
(3)
知识补充(原码、反码、补码)
(4)练习
(5)好代码标准
(6)自增与自减
练习1
练习2
四、关系运算符
五、逻辑运算符
(1)逻辑与(&)与逻辑或(|)
(2)短路与(&&)与短路或(||)
<1> 短路与(&&)
<2> 短路或(||)
(3)异或运算(^)
<1> 不同为true
<2> 相同为false
(4)逻辑非( !)
六、位运算符
(1)左移运算符(<<)
(2)右移运算符(>>)
(3)不带号右移运算符(>>>)
补充知识
分析:
强化位运算
(4)按位与& 按位或|
(5)按位异或^ 按位取反~
七、条件运算符
八、运算符的优先级
一、赋值运算符
= 将右边的值赋值给左边的变量, 一定要等右边所有的代码运算完毕再进行赋值
int i = 100*10;
二、算数运算符+ - * / %
(1)在算数运算符使用的过程中,注意运算结果的数据类型,可能和参与运算的变量类型不一致。
如下图这样写是正确的:
但我们把int类型改成byte就会出错:
为啥呢?
我们来看一下,若i赋值为127,j赋值为127,那么i+j的值就超过了byte的范围。
为了解决这种问题,Java做了这样一个调整,当数据类型是小于int的整数,进行加减乘的时候,结果默认为int类型。为了避免数据范围太小,造成数据损失。
所以当i+j之后,结果是一个int类型的数据。但我们把它存储到变量z(byte类型)中的时候,就需要强制类型转换。
同样的,若变量i是一个byte类型,变量j是一个short类型,最终加起来还是int类型。
1、只要是两个比int类型小(或者等于int类型)的数据加(减、乘)起来,最终结果都是以int类型存储!
2、如果是大于int类型的变量参与数学运算,以最大的变量数据类型作为结果类型。
(2)在进行除法运算, 整数除以整数,不会保留小数位,除非其中一方是浮点数。
上节中对此类问题有所描述,可以去看上节内容:
(3)取模运算对于浮点数同样有效。
% 模运算 取模运算 去余数运算
我们先来看一下整数的取模运算:
数学运算中:23/7=3---2 (商3余2)
Java中 取模运算对于浮点数同样有效。
练习
倒序输出:
准备任意一个四位整数,倒叙输出。如:1234 >>> 4321
代码:
package demo3; import com.sun.javaws.IconUtil; public class Test3 { public static void main(String[] args) { int i=1234; //先输出4,再输出3/2/1 int g=i%10; //g=4 int s=i/10%10; //s=3 int b=i/100%10; //b=2 int q=i/1000; //q=1 System.out.print(g); //当输出语句带ln的时候(println),就表示换行 System.out.print(s); System.out.print(b); System.out.print(q); } }三、拓展算数运算符
+= -= /= *= %= ++ --
拓展算数运算符可以理解为算数运算符的简写,但是算数运算符会改变结果的数据类型。
拓展算数运算符直接在原来的变量上进行 *** 作,所以不会改变变量的数据类型。
(1)我们先来看这样一段代码:
赋值运算符= :先计算等号右边的结果,将结果赋值给左边的变量。
i=i+10; --->先计算右边i+10,等于20,再赋值给左边的i。
这个运算就相当于:int b=i+10; i=b;
拓展算数运算符就是对这种运算做一种简化的。
就是让i变量自增10个。即:i+=10;
同理:
i-=10; --> i=i-10;
i*=10; --> i=i*10;
i/=10; --> i=i/10;
i%=10; --> i=i%10;
(2)我们刚刚讲过,算术运算符在使用的时候,有这样一个特征:在算数运算符使用的过程中,注意运算结果的数据类型,可能和参与运算的变量类型不一致。
那么我们再来看下面的代码:
如上图所示,这样会报错。
因为b是byte类型,当和10进行加法运算之后,结果是以int类型来存储。当等号右边计算结束,它会将这个值赋值给左边的变量b,而变量b是byte类型!装不下。
这时候,需要一个强制类型转换。
而拓展运算符在这个运算的时候包含了一个隐形的数据类型的转换。
我们来看一下,用拓展运算符的结果是不报错的:
(3)拓展运算符不会改变原有变量的数据类型!
那这样不会出现上面说过的那个问题吗?就是如果等号右边的数值运算之后,超过了左边的变量的数据范围(也就是左边变量存不下右边的数值),那么会出现什么情况呢?
我们不妨来试一试:
知识补充(原码、反码、补码)注:本人才疏学浅,这个-118实在不知道如何得出来,在这里就不阐述了,只是在这里放一个结果。若哪位大佬路过,请帮我解答一下,谢谢!
计算机中用二进制表示数字。
不会十进制与二进制互转的可以看一下之前的文章(进制及其转换):
Java基础--常量和变量_m0_55746113的博客-CSDN博客https://blog.csdn.net/m0_55746113/article/details/122552312?spm=1001.2014.3001.5501
如6。正数三个都一样。
原码 00000000 00000000 00000000 00000110
反码 00000000 00000000 00000000 00000110
补码 00000000 00000000 00000000 00000110
如-6。
原码 10000000 00000000 00000000 00000110
反码 11111111 11111111 11111111 11111001
(保持原码符号位不变,剩下位置取反)
补码 11111111 11111111 11111111 11111010
(反码+1)--> 注意逢2进1
计算机中,不管是正数还是负数,都是以补码形式来存储的。
具体举例如下图:
(1)已知[X]原,求[X]补
(2)已知[X]补,求[X]原
(4)练习因为拓展运算符不会改变变量的数据类型,那么就需要注意数字的范围不要超过数据类型的范围。否则可能会造成数据的损失。
完成两个整数变量值的互换。
如:变量a为3,b为5。最终让a输出5,b输出3。
方法一、
代码:
package demo3; public class Test6 { public static void main(String[] args) { int a=10; int b=20; //方法1 借助中间变量完成 int c=a; a=b; b=c; System.out.println(a); //20 System.out.println(b); //10 } }
方法二、
代码:
package demo3; public class Test6 { public static void main(String[] args) { int a=10; int b=20; //方法2 a=a+b; //a=30 b=a-b; //b=30-20=10 a=a-b; //a=30-10=20 System.out.println(a); System.out.println(b); } }(5)好代码标准
(6)自增与自减好代码标准:
1、注释全面
2、简洁
3、格式规范
4、杜绝2B代码,不用追求黑客代码,最受欢迎的就是普通代码(阅读性最强)
简单来看,就是让变量自增和自减:
但有一点需要注意,这个自增和自减,放在变量前后的结果可能不同哦。
1、++、-- 在变量前面,先让变量自增/自减,然后再使用变量参与运算。
2、++、-- 在变量后面,先使用变量参与运算,然后再让变量自增/自减。
int i=10; int b=i++; //相当于:int b=i; i=i+1; int c=++i; //相当于:i=i+1; int c=i;练习1
代码:
package demo3; public class Test9 { public static void main(String[] args) { int i=10; int j=5; // ++i --> i=11 ,然后使用的也是11 // j-- --> 先使用j的值5,j再自减为4 int b=++i + j--;//b=11+5=16 System.out.println(i); System.out.println(j); System.out.println(b); } }练习2
简单来看
详细解释:
代码:
package demo3; public class Test10 { public static void main(String[] args) { int a=10; int b=a++; //b=10 a=11 //(--b)-->9 ,b=9 ;(++a)-->12 ,a=12 int c=(--b)+(++a); //c=9+12=21 //(c++)-->21 ,c=22 ;(a--)-->12 ,a=11 ;(++b)-->10 ,b=10 int d=(c++)-(a--)+(++b);//d=21-12+10=19 //(--d)-->18 ,d=18 ;(c++)-->22 ,c=23 ;(++b)-->11 ,b=11 ;(a--)-->11 ,a=10 int e=(--d)+(c++)-(++b)+(a--);//e=18+22-11+11=40 System.out.println(a);//10 System.out.println(b);//11 System.out.println(c);//23 System.out.println(d);//18 System.out.println(e);//40 } }四、关系运算符
数据大小关系
< > <= >= == !=
关系运算符:判断数据大小关系
运算结果是布尔类型 true / false。
package demo4; public class Test1 { public static void main(String[] args) { boolean b=10>20; System.out.println(b); System.out.println(10==20);//判断10与20是否相等,相等就输出true,不相等就输出false System.out.println(10!=20);//10不等于20,成立,输出为true boolean i=2>=3; //此处的含义是:2大于或等于3 System.out.println(i); //除数与被除数 //10(被除数)/3(除数) --> 10是被分开的,所以是被除数。除数不能为0,被除数不能为0。 } }
结果:
五、逻辑运算符& | ^ && || !
(1)逻辑与(&)与逻辑或(|)& 逻辑与运算 (并且) --> 多个条件同时为true,则为true,一方为false,则为false。 | 逻辑或运算 (或者) --> 多个条件任意一个为true,则为true。全为false,才为false。(2)短路与(&&)与短路或(||) <1> 短路与(&&)
我们可以发现,如下代码可以成功执行:
当我们把逻辑与(&)换成短路与(&&)的时候,结果不变:
Q:那么逻辑与和短路与有什么区别吗?
我们现在来把age的值改为10,结果显然为false。
短路与(&&)运算的时候,若前面一个表达式为false,就不会再判断之后的表达式了,即后面的表达式不会再被执行。因为结果就已经出来了,一个表达式为false,整个结果就是false。
Q:那我们如何知道后面的表达式没有被执行呢?
如果除数为0,那么就会出现ArithmeticException: / by zero的异常。
那么我们来看这样一段代码:
boolean b4=false && 1/0 >1; //短路与运算,如果第一个值为false,那么后面就不执行了 System.out.println(b4);//若第二个表达式没有被执行,程序就不会出现异常
可以看到结果是false,并没有出现异常。即:后面的表达式没有被执行。
而逻辑与(&)运算,无论第一个表达式是否为false,后面的表达式都会被执行!
那我们不妨用逻辑与(&)来执行刚才的代码,如下图显示结果:
可以看到结果是程序异常,验证了我们刚才的阐述,确实执行了后面的表达式。
那么如果第一个表达式是是true,我们并不能知道后面表达式是否为true。若为false,则整体为false,若为true,则整体才为true。所以,对于短路与(&&)运算,若第一个表达式为true,后面的表达式仍会被执行。
我们还是那刚才的例子来看:
可以看到,程序出现了异常,后面表达式被执行了。
<2> 短路或(||)总结:
短路与(&&)运算,发现前面的一项结果为false,则后面的条件不再运算。
短路或(||)运算和短路与(&&)差不多,只是条件不一样。
//短路或(||)运算,表达式若有一方为true,则整个结果就为true boolean b7=true || 1/0>1; //第一个条件已经为true,后面表达式的结果已经不重要了,结果都为true System.out.println(b7);
我们可以看一下结果:
我们可以看到,结果为true。即,并没有执行第二个表达式。(若执行第二个表达式的话,会出现异常哦)
那我们还可以来看一下逻辑或(|)运算:
boolean b8=true | 1/0>1; //逻辑或(|)运算,不管前面是否为true,后面表达式都会被执行 System.out.println(b8); //后面的表达式被执行了,程序会出现异常
总结:
短路或(||)运算,发现前面的一项结果为true时,则后面条件就不运算了。
注意: 以后基本使用短路的与运算和或运算。可以减少计算量。
(3)异或运算(^)异或运算:相同则为假(false),不同则为真(true)。
<1> 不同为true <2> 相同为false (4)逻辑非( !)逻辑非(!)--> 原来为true,加上之后为false;原来为false,加上之后为true。
也可以把叹号!直接写在输出语句中:
六、位运算符>> << >>> & | ^ ~
(1)左移运算符(<<)分析:
(2)右移运算符(>>)左移一位,相当于乘2 。
分析:
(3)不带号右移运算符(>>>)右移一位,相当于除2。
我们可以看到,这个结果和上面的右移运算符(>>)一样。
Q:>>和>>>有什么不一样?
我们先把a的值换成-8来看看:
补充知识注意:
>>和<<不会移动符号位,但是>>>会移动符号位。
知识补充(原码、反码、补码)-- 一网打尽_m0_55746113的博客-CSDN博客计算机中用二进制表示数字。不会十进制与二进制互转的可以看一下之前的文章(进制及其转换):Java基础--常量和变量_m0_55746113的博客-CSDN博客https://blog.csdn.net/m0_55746113/article/details/122552312?spm=1001.2014.3001.5501计算机中,不管是正数还是负数,都是以补码形式来存储的。既然最终是以补码来存储,那么为啥要有反码和原码呢?因为给我们补码数据,我们是不认识的。只有把补码转化为原码,我https://blog.csdn.net/m0_55746113/article/details/122625576?spm=1001.2014.3001.5501
<1> 6<<2=24
00000000 00000000 00000000 00000110
0000000 00000000 00000000 000001100
<2> 6>>1==3
00000000 00000000 00000000 00000110
000000000 00000000 00000000 0000011
<3> -6>>1
11111111 11111111 11111111 11111010
111111111 11111111 11111111 1111101
分析:>> 保留符号位置1 填1
>>> 不保留符号,不管是什么,都填0
1、 第一次
a=8
十进制8用二进制表示为:
8: 00000000 00000000 00000000 00001000
①8>>1: 00000000 00000000 00000000 00001000
最后的0溢出,最前面填符号位0(8是正数),最终得到:
00000000 00000000 00000000 0000100
将此二进制转化为十进制,得到:4
②8>>>1: 00000000 00000000 00000000 00001000
最后的0溢出,最前面无论什么情况都补0,最终得到:
00000000 00000000 00000000 0000100
将此二进制转化为十进制,得到:4
2、第二次
a=-8
十进制-8用二进制表示为:
-8:10000000 00000000 00000000 00001000 (原码)
11111111 11111111 11111111 11110111 (反码)
11111111 11111111 11111111 11111000 (补码)
①-8<<1:
11111111 11111111 11111111 11111000
“<<”不会移动符号位,我们可以看到,在移动的时候,我们将最高位移动,左移之后,最高位溢出,最后我们需要将最高位改符号位1(这里原本就是1,就不用动了),最后一位补0,最终得到:
1111111 11111111 11111111 111110000
我们得到的是补码,转换为原码(补码转反码 +1):
10000000 00000000 00000000 00001111
--> 10000000 00000000 00000000 00010000(原码)
将此二进制转化为十进制,得到:-16
②-8>>1 :
11111111 11111111 11111111 11111000
“>>”不会移动符号位,我们可以看到,在移动的时候,最后一位溢出,最后我们需要将最高位补符号位1,最终得到:
111111111 11111111 11111111 1111100
我们得到的是补码,转换为原码(补码转反码 +1):
10000000 00000000 00000000 00000011
--> 10000000 00000000 00000000 00000100(原码)
将此二进制转化为十进制,得到:-4
③-8>>>1:
11111111 11111111 11111111 11111000 (补码)
“>>>”会移动符号位,所以我们可以看到,在移动的时候,我们最高位还是以1来移动,最后的一位0溢出,最前面补0,最终得到:
0 11111111 11111111 11111111 1111100
我们得到的是补码,转换为原码(正数三个码相同):
01111111 11111111 11111111 11111100
将此二进制转化为十进制,得到:2147483644
// 11111111 11111111 11111111 11111000 (补码) // 11111111 11111111 11111111 11111000 (右移一位,最右边溢出一位) // 011111111 11111111 11111111 1111100 (无符号移位,高位补0) //--> 01111111 11111111 11111111 11111100 (整理之后) //--> 01111111 11111111 11111111 11111100 (原码) //--> 2,147,483,644 (十进制)
强化位运算总结(重点)
1、有符号右移:负数右移高位补1
2、无符号右移:高位补0
注:所有结果真实通过编译器运行得到!
如果对移位运算还是不熟悉,咱们可以再来举个例子:
<1> 5<<2 =20
//5: 00000000 00000000 00000000 00000101 (原码) // 00000000 00000000 00000000 00000101 (反码) // 00000000 00000000 00000000 00000101 (补码) int a=5<<2; // 00000000 00000000 00000000 00000101 (补码) // 00000000 00000000 00000000 00000101 (最左边两个溢出) // 000000 00000000 00000000 0000010100 (最后面补0) //--> 00000000 00000000 00000000 00010100 (整理之后) //--> 00000000 00000000 00000000 00010100 (转为原码) //--> 20 (转为十进制) System.out.println(a);
<2> 5>>2 =1
int b=5>>2; // 00000000 00000000 00000000 00000101 (补码) // 00000000 00000000 00000000 00000101(最右边两个溢出) // 0000000000 00000000 00000000 000001 (最前面补0) //--> 00000000 00000000 00000000 00000001 (整理之后) //--> 00000000 00000000 00000000 00000001 (转为原码) //--> 1(转为十进制) System.out.println(b);
<3> -5<<2 = -20
//-5: 10000000 00000000 00000000 00000101 (原码) // 11111111 11111111 11111111 11111010 (反码:原码符号位不变,其余取反) // 11111111 11111111 11111111 11111011 (补码:反码+1) int c=-5<<2; // 11111111 11111111 11111111 11111011 (补码) // 11111111 11111111 11111111 11111011 (最左边两个溢出) // 111111 11111111 11111111 1111101100 (最右边补0) //--> 11111111 11111111 11111111 11101100 (整理之后的补码) //--> 10000000 00000000 00000000 00010011 //--> 10000000 00000000 00000000 00010100 (原码) //--> -20 (转为十进制) System.out.println(c);
<4> -5>>2 = -2
int d=-5>>2; // 11111111 11111111 11111111 11111011 (补码) // 11111111 11111111 11111111 11111011(最后两位溢出) // 1111111111 11111111 11111111 111110 (负数右移高位补1) //--> 11111111 11111111 11111111 11111110 (整理之后的补码) //--> 10000000 00000000 00000000 00000001 //--> 10000000 00000000 00000000 00000010 (原码) //--> -2 (转化为十进制) System.out.println(d);
<5> -5>>>2 = 1073741822
int e=-5>>>2; // 11111111 11111111 11111111 11111011 (补码) // 11111111 11111111 11111111 11111011(最后两位溢出) // 0011111111 11111111 11111111 111110 (无符号右移,高位补0) //--> 00111111 11111111 11111111 11111110 (整理之后的补码) //--> 00111111 11111111 11111111 11111110 (原码) //--> 1073741822 (转化为十进制) System.out.println(e);(4)按位与& 按位或|
有的人可能会问,这不是逻辑与运算吗?
逻辑与运算两端运算完之后,结果是布尔类型。
如果与运算两端是整数的话,那就是按位与运算了。不是逻辑与运算。
<1> 按位与:同为1,则为1;一方为0,则为0。
//4、按位与 & //同为1,则为1;一方为0,则为0。 int e=8; // 0000 1000 int f=9; // 0000 1001 int g=e & f;// 0000 1000 --> 8 System.out.println(g);
<2> 按位或:一方为1,则为1;同为0,才为0。
//5、按位或 | //一方为1,则为1;同为0,才为0。 int e2=8; // 0000 1000 int f2=9; // 0000 1001 int g2=e2 | f2; // 0000 1001 -->9 System.out.println(g2);(5)按位异或^ 按位取反~
<1> 按位异或 ^:相同即为0,不同即为1
//6、按位异或 ^ //相同即为0,不同即为1 int e3=8; // 0000 1000 int f3=9; // 0000 1001 int g3=e3 ^ f3; // 0000 0001 -->1 System.out.println(g3);
<2> 按位取反~
6取反之后:-7
注意,反码是一种表现形式,取反(每一个位置都取反)是一个计算过程。
有的人会觉得按位取反是这样的规律:原来为0,变为1;原来为1,变为0。
但我们来 *** 作一下,会发现是不对的!!!
二进制存储的时候,会有一些算数方式,和正常算数方式不太一样。
我们要记住下面这样的规律:
-3 -2 -1 / 0 1 2 3
从1和0中间断开,如果是1,那么~1就是跟轴对应的-2。
如果是10,那对应的就是-11。以此类推。
其余的不需要深究,以后不大需要用这些的。
一般是用来写加密算法的,我们也不会去写。了解就可以啦。
七、条件运算符?:
条件运算符:Java中唯一的一个三目运算符。
Q:三目运算符?
我们可以看到,之前的运算符都是判断两个条件。
三目运算符有三个组成部分。
条件?值1:值2
当条件为真,就将值1赋值给a,当条件为假,就将值2赋值给a
可以做一些简单的逻辑判断。
public class Test3 { public static void main(String[] args) { //条件运算符 条件? 值1 : 值2 int a=true?10:20; //当条件为真,就将值1赋值给a,当条件为假,就将值2赋值给a System.out.println(a);//10 int b=false?10:20; System.out.println(b);//20 int i=10; int j=20; System.out.println(i>j?i:j);//谁大就输出谁 } }八、运算符的优先级
boolean b = 1+0>1 || 5>3?true:false;
所以优先级简单可以记忆为
算术运算符 >关系运算符 >条件运算符 > 逻辑运算符 > 赋值运算符
实在分不清楚 那么就用小括号提升运算优先级即可。
不用刻意去记忆。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)