目录
<<:举例如果问你写一条2*8最快的算数方式,答:(2<<3) ,这样的算法实际等于2*2^3 2<<3实际上就是"2"的二进制"10"向左移动了三位"10000"
(了解即可)关于表达式同种类型问题,要求 表达式1 和 表达式2 类型一致,期间会自动类型转换提升再比较,或者不提升但容易接参数出现问题,后面接触包装类详细说明
运算符
说明:是一种具有特殊功能的符号,用于表示数据的运算、赋值和比较等
分类:
- 算术运算符
- 赋值运算符
- 比较运算符(关系运算符)
- 逻辑运算符
- 位运算符
- 三元运算符
算术运算符
package javase3;
public class Operator1 {
public static void main(String[] args) {
//简单的加减乘不演示
//除号 "/"
int num1 = 12;
int num2 = 5;
int result1 = num1/num2;//2 整数相除结果为整数,后面小数会舍弃小数
double result2 = num1/num2;//2.0 与上同理
double result4 = (num1+0.0)/num2;//2.4 此时是double类型的num1除于num2,最终结果就是double类型
double result5 = (double)num1/num2;//2.4 遇上同理
//求余数 "%",结果的符号与被模数的符号相同.也就是结果的正负值取决于%前面的值
int result6 = num1%num2;//2
int result7 = -num1%num2;//-2
int result8 = -num1%-num2;//-2
int result9 = num1%-num2;//2
double result10 = 2.1/1.1;//1.8181818181818181 取模运算的结果不一定总是整数。
//值++或者值-- 先运算,后自增
//++值或者--值 先自增,后运算
int i1 = 10;
int i2 = i1++;
System.out.println("i1:"+i1+",i2:"+i2);//i1:11,i2:10
int i3 = 10;
int i4 = ++i3;
System.out.println("i3:"+i3+",i4:"+i4);//i3:11,i4:11
short s1 = 10;
// s1 = s1 + 1;//编译错误,因为1默认是int类型,运算结果参考大类型也就是int类型
s1 = (short)(s1+1);//11
++s1;//12,自增并不会改变数据类型,后面学的"+="也不会改变数据类型
byte b1 = 127;
++b1;//-128
/*取一个数随机数的每个位数上的熟*/
int i5 = 123;//随机数
int i6 = i5/100;//取百位数 1
int i7 = i5%100/10;//取十位数 2
int i8 = i5%10;//取个位数 3
}
}
代码总结注意点:
- 如果对负数取模,可以把模数负号忽略不记,如:5%-2=1。但被模数是负数则不可忽略。此外,取模运算的结果不一定总是整数。
- 对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃小数部分。例如:intx=3510;x=x/1000*1000;
- “+”除字符串相加功能外,还能把非字符串转换成字符串.例如:System.out.println(“5+5=”+5+5); //打印结果是5+5=55
赋值运算符
说明:
- 符号:=,+=, -=, *=, /=, %=
- 当“=”两侧数据类型不一致时,可以使用自动类型转换或使用强制类型转换原则进行处理
package javase3;
public class Operator2 {
public static void main(String[] args) {
/*记住一个特点,使用赋值运算符运算并不会改变赋值运算符左边原有的数据类型及其最后赋值运算过程中其原有的值,
这点很重要!!!!!!还有运算符优先级问题,后面拓展练习和图片解析会有解释*/
int num1 = 10;
num1 += 2; //12 这个操作就好比num1=num1+2; 但又不完全是,但可以这样理解
int num2 = 12;
num2 %= 5;//2 这个操作就好比num2 = num2 % 5; 但又不完全是,但可以这样理解
/*在开发中,如果要使得变量实现+2的操作,最好使用"+="这种方式,因为不会改变原有的数据类型*/
short s1 = 10;
s1 += 2;//12
Short s2 = Short.valueOf(s1);//转换成Short包装类型,后面会学习每个基本数据类型对应的包装类型
System.out.println(s2 instanceof Short);//true 转换成Short包装类型判断是short类型
/*拓展练习*/
//连续赋值,这里编译却并没有提示错误,可能是BUG,但是在使用的时java会报提示这几个局部变量并没有被初始化
int i1;
int i2,i3;
i1=i2=i3=10;//先将10赋予给i1,再将i1的值赋予给i2,再将i2的值赋予给i3
int i4=10,i5=10;
int sd = 0;
/*先从左往右看,看看那个变量用了拓展运算方式,这个赋值运算符左边的变量只会到最终赋值才会发生变化,然后从右往左开始计算,
sd=1 但是sd+=这种运算方式没到最后赋值是不会改变自己本身的值,也就是sd+=sd=1本质还是sd+=1*/
sd+=sd=1;
System.out.println("sd:"+sd);//sd:1
int a=0,b=0,c=0;
/*与上面同理,先从左往右看,从右往左开始计算,b+=这种运算方式没到最后是不会改变自己本身的值,也就是还是0,
但是a的值没有被赋值运算符控制可以改变,因此a的值受到a=1影响,计算流程也就是b+=(a=1)/1*/
b+=(a=1)/(b=1);
System.out.println("a:"+a);//a:1
System.out.println("b:"+b);//b:1
/*与上同理,c+=限制了c变量没到最后赋值运算是不会改变自身的值,c的本质还是0,++c只是获得一个1的结果,简化后运算还是c+=1*/
c += (++c);
System.out.println("c:"+c);//c:1
int a1,b1;
a1=b1=0;
/*与上面同理,a1和b1都被运算符限制了,本质上只是a1和b1还是为0,也就是b1+=1/1-->a1*=1-->b1+=0,最终a1和b1都是0*/
b1+=a1*=b1+=(a1=1)/(b1=1);
System.out.println("a1:"+a1);//a1:0
System.out.println("b1:"+b1);//b1:0
/*a1=b1=0*/
b1+=b1+=a1+1;//与上同理,b1+=1
System.out.println("a1:"+a1);//a1:0
System.out.println("b1:"+b1);//b1:1
/*a1=0,b1=1
* 与上面同理,但有那么一点不同,这里b1被赋值运算符限制,而a1没有.也就是a1不仅能得出值,还能改变自身的值,而b1能得出值,
* 但本质上还是自己本身也就是1,计算流程:b1+=1+2+1+2-->b1+=6-->b1=1+6*/
b1+=++a1+(++a1+b1+++b1++);
System.out.println("a1:"+a1);//a1:2
System.out.println("b1:"+b1);//b1:7
}
}
比较运算符
注意:
- 比较运算符的结果都是
boolean
型,也就是要么是true,要么是false。 - 比较运算符“
==
”不能误写成“=”
package javase3;
public class Operator3 {
/*
运算符之三:比较运算符
== != > < >= <= instanceof
结论:
1.比较运算符的结果是boolean类型
2.区分 == 和 =
*/
public static void main(String[] args) {
int i1 = 10;
int i2 = 20;
System.out.println(i1==i2);//false
boolean b1 = true;
boolean b2 = false;
System.out.println(b1==b2);//false
}
/*这里不做引用类型的数据类型比较,因为会有一些规则,例如Integer,String常量池问题,涉及到JVM内存问题*/
}
逻辑运算符
&
—逻辑与|
—逻辑或!
—逻辑非(反义词的意思)&&
—短路与||
—短路或^
—逻辑异或(相同则为false,不同则为false)
注意:
- 逻辑运算符用于连接布尔型表达式,在Java中不可以写成3<x<6,应该写成x>3 & x<6 。
- “&”和“&&”的区别:
- 单&时,左边无论真假,右边都进行运算;
- 双&时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。
- “|”和“||”的区别同理,||表示:当左边为真,右边不参与运算。
- 异或(^)与或( | )的不同之处是:当左右都为true时,结果为false。理解:异或,追求的是“异”!
package javase3;
/*
运算符之四:逻辑运算符
& && | || ! ^
说明:
1. 逻辑与运算符操作的都是boolean类型的变量
*/
public class Operator4 {
public static void main(String[] args) {
//区分& 与 &&
//相同点1:& 与 && 的运算结果都相同
//相同点2:当符号左边是true时,二者都会执行符号右边的运算
//不同点:当符号左边是false时,&继续执行符号
//开发中,推荐使用&&,效率更高
//区分:| 与 ||
//相同点1:| 与 || 的运算结果都相同
//相同点2:当符号左边是false时,二者都会执行符号右边的运算
//不同点3:当符号左边是true时,|继续执行符号右边的运算,而||不再执行符号右边的运算
//开发中,推荐使用||,效率更高
/*这里只演示&和&&,|和||与其相反*/
//&
boolean b1 = false;
int num1 =10;
if (b1 & num1++>0){//两个条件都判断
System.out.println("都为true,判断结果为true");
}else{
System.out.println("一个为false或者都为false,因此判断结果都为false");//打印这句
}
System.out.println("num1 = "+num1);//num1 = 11 ,验证了&两个条件都进行执行判断
//&&
boolean b2 = false;
int num2 = 10;
if(b2 && num2++>0){//两个条件都判断
System.out.println("都为true,判断结果为true");
}else{
System.out.println("一个为false或者都为false,因此判断结果都为false");//打印这句
}
System.out.println("num:"+num2);//num2 = 10 验证了&&运算符号左边为false时就会短路,不再执行右边判断,直接得出false结果
//!
boolean b3=false;
boolean b4=!b3;//true
boolean b5=!b4;//false
System.out.println("b4:"+b4);//b4:true
System.out.println("b5:"+b5);//b5:false
//^,这里顺便也演示if()函数的另外写法
if(true^false) System.out.println("两个boolean值不一样,结果为true,执行这条代码");//代码被执行
if(true^true) System.out.println("如果两个boolean值不一样,结果为true,执行这条代码");//代码未被执行,直接下一条代码
System.out.println("否则就是两个boolean值一样,结果为flase,执行这条代码");//代码被执行
/*拓展练习,这里可以用debug进行调试来看值的变化*/
boolean b6 =true;
boolean b7 =false;
short z = 42;
if((z++==42) && (b7=true)) z++;//if(true && true) z++;z=44 b7=true b6=false
if((b6=false) || (++z==45)) z++;//if(false || true) z++;z=46 b6=false b7==true
System.out.println("b6:"+b6);//b6:false
System.out.println("b7:"+b7);//b7:true
System.out.println("z:"+z);//z:46
}
}
位运算符
说明:
位运算就是将java中十进制的数转换成二进制进行运算
<<:举例如果问你写一条2*8最快的算数方式,答:(2<<3) ,这样的算法实际等于2*2^3
2<<3实际上就是"2"的二进制"10"向左移动了三位"10000"
>>:左移同理,只不过是除2ⁿ,二进制数向右移
&、|、^:
~:
>>>无符号右移动:
无符号右移运算符的使用
(以32位为例)
1.为正的十进制整数
如:64 >>> 5①第一步:操作数的绝对值,转化为二进制
100 0000②第二步:补码(操作数为正数)
0000 0000 0000 0000 0000 0000 0100 0000③第三步:右移5位
0000 0000 0000 0000 0000 0000 0000 0010结果为:2 (实际上缩小了5倍)
2.为负的十进制整数
如:-64 >>> 5①第一步:操作数的绝对值,转化为二进制
100 0000②第二步:补码(操作数为负数)
1000 0000 0000 0000 0000 0000 0100 0000③第三步:取反(符号位不变,其他位1、0相互转换),在第一位加上1
1111 1111 1111 1111 1111 1111 1100 0000④第四步:右移5位
0000 0111 1111 1111 1111 1111 1111 1110结果为:134217726 (实际上放大了$&@倍)
如何使用位运算异或^来交换两个数的值
说明:记住下面这个规则即可
int num1 = 1;
int num2 = 2;
num1 = num1 ^ num2;
num2 = num3 ^ num2;
num1 = num3 ^ num1;
System.out.println("num1 = " + num1 + ",num2 = " + num2);//num1=2,num2=1;
三元运算符
(了解即可)关于表达式同种类型问题,要求 表达式1 和 表达式2 类型一致,期间会自动类型转换提升再比较,或者不提升但容易接参数出现问题,后面接触包装类详细说明
/*三目运算符要求表达式要相同类型,因此int提升变成了大类型double,对比完成后重新装箱成Double类型,用Object类型接受,变成了多态*/
Object o1= true? new Integer(1) : new Double(2.0);
/*运行时先是用了Double类型的toString方法,因为编译看左边,运行看右边,因此是变成1.0字符串类型后再打印到控制台*/
System.out.println(o1/*.toString()*/);//1
Object o2 = true ? new String("1") : new Double(2.0);
System.out.println(o2);//1
Object o4 = true ? new Boolean(true) : new Double(2.0);
System.out.println(o4);//true
三元运算符演示
package javase3;
public class Operator5 {
/*
运算符之六:三元运算符
1.结构:(条件表达式)?表达式1 : 表达式2
2. 说明
① 条件表达式的结果为boolean类型
② 根据条件表达式真或假,决定执行表达式1,还是表达式2.
如果表达式为true,则执行表达式1
如果表达式为false,则执行表达式2
③ 表达式1 和表达式2要求是一致的。
④ 三元运算符是可以嵌套的
3. 凡是可以使用三元运算的地方,都是可以改写if-else。
反之,则不一定成立!!!
*/
public static void main(String[] args) {
int i1 = 12;
int i2 = 5;
String s1 = (i1>i2)? "左边大":"右边大";//左边大 结果为"true",选择左边的表达式
System.out.println(s1);
/*表达式1和表达式2要为同种类型,java有两种不同类型,并且一定要有能够同时存的下两个类型的数据类型接受必须返回的结果*/
double d1 = (i1>i2)? 2:1.0;//表达式1和表达式2都是基本数据类型,double变量能够能存下int类型和double类型
// float f1 = (i1>i2)? 2:1.0;//编译错误,java: 不兼容的类型: 从double转换到float可能会有损失
Object s2 = (i1>i2)? Integer.valueOf(2):"你好啊";//2,Object是任何类的父类
/*拓展练习,获取三个数最大的值*/
int n1 = 12;
int n2 = 30;
int n3 = -43;
int max1 = (((n1>n2)?n1:n2)>n3)?((n1>n2)?n1:n2):n3;//30
System.out.println("max1:"+max1);//max1:30
//将上面改写成if
int max2 = n2;
if(n1>n2) max2=n1;
if(n3>max2) max2=n3;
System.out.println("max2:"+max2);//max2:30
}
}
运算符的优先级(了解作为参考)
- 运算符有不同的优先级,所谓优先级就是表达式运算中的运算顺序。如下表,上一行运算符总优先于下一行。
- 只有单目运算符、三元运算符、赋值运算符是从右向左运算的。