算数运算符
+ (正数、加法、**连接符**)
-
*
/ (double/int,运算结果的类型 取决于大的数据类型)
% (取模、取余数)
++ (自增)自增就是相当于操作数+1
-- (自减)
前自增、后自增:
++a:前自增:++位于操作数的前面,先自增,后使用;
a++:后自增:先使用,后自增
后自增在JVM的运行原理:因为后自增要使用到没有+1之前的值,那么JVM会先声明一个变量用于保存没有+1之前的值。
例如:int i = 0;
i = i++; //这里若是i++,那么下一步的结果是1
System.out.println(i); //结果是0.
原理:1.int temp = i; //temp=0,声明了一个临时变量用于记录i没有+1之前的值
2.自增, 先i = i+1; 后 i=1;
3.return temp; //把temp的值返回到i;
4.整个过程中i的值经历了3次变化:0-->1-->0
连接符:让任何的数据类型都可以和字符串进行拼接;结果都是字符串类型;
举例:System.out.println(1+2+3+" world"+1+2+3); //结果6world123
分析:计算机每次运算的时候只能取两个数据运算,并且是从左往右运算;
取模:在java中,做取模运算时,结果的正负号取决于被除数,即%左边那个数。
举例:System.out.println(10%3); // 1
System.out.println(10%-3); // 1
System.out.println(-10%3); // -1
System.out.println(-10%-3); // -1
分析:在java中,做取模运算时,结果的正负号取决于被除数,即左边那个数。
自减:操作数-1
--a 前自减:先自减,后使用。
a-- 后自减:先使用,后自减。
例如:int i=1;
int sum1=--i; //前自减,先i=i-1,后sum=i。结果sum1=0
int sum2=i--; //后自减,先sum=i,后i=i-1。结果sum2=1
System.out.println(sum1+"---"+sum2);
赋值运算符
= (赋值运算符)
+= (运算前,会强制转换类型)
-= (运算前,会强制转换类型)
*= (运算前,会强制转换类型)
/= (运算前,会强制转换类型)
%= (运算前,会强制转换类型)
举例
举例1:以下例子会报错,
byte b1=1;
byte b2=2;
b2=b2+b1; //这一步需要做强制转换,即b2=(byte)(b2+b1)
system.out.print(b2);
举例2:正确
byte b1=1;
byte b2=2;
b2+=b1; //在编译时,+=运算符会被java编译器自动做类型的强制转换,即b2=(byte)(b2+b1)
system.out.print(b2);
比较运算符
比较运算符的结果都是返回一个布尔值,即true 或者false
== (判断是否等于)(=是赋值运算符,==是判断是否等于 比较运算符)
==用于比较两个基本数据类型数据的时候,比较的是两个变量所存储的值是否一致;
==用于比较两个引用类型变量的数据时候,比较的是两个引用类型变量所记录的内存地址是否一致
!= (不等于)
>
<
>=
<=
比较,举例
byte b=10;
long l=30;
System.out.println(l>b); //true,两个不同类型的数据可以进行比较,但是这两个不同类型的数据必须是兼容的类型。byte类型与long类型兼容,若是byte类型与boolean类型就不兼容了。
//这个比较的过程会先把b转换为long类型的数据,然后在进行比较
System.out.println('a'>50);//true,此处先将a转换为97在与50比较
逻辑运算符
逻辑运算符的作用,是用来连接布尔表达式的。
& (与)(只有左右表达式同时为true,结果才为true)
| (或)(只要左右表达式有一个为true,结果就为true)
^ (异或)(判断是否不相同。即左右两边相同,结果为false;左右两边不相同,结果为true)
! (非)
&& (短路与/双与)
|| (短路或/双或)
短路与 和 单与符号的相同点和不同点:
相同点:短路与 和 单与运算的结果是一样的。
不同点:使用短路与的时候,如果左边的布尔表达式为false,则不会再运算右边的布尔表达式,从而提高了效率。使用单与的时候,即使发现左边的布尔表达式为false,还是会运算右边的布尔表达式的。
举例1:
int workAge=1;
int age=24;
System.out.println(workAge>=2 <font color=#0099ff>&</font> age++>18);//用&,则左右表达式都要运算
System.out.println("age:"+age);//age:25
举例2:
int workAge=1;
int age=24;
System.out.println(workAge>=2 && age++>18);//用&&,若左边表达式为false,则不再计算右边表达式
System.out.println("age:"+age);//age:24
短路或 与 单或 的相同点和不同点:
相同点:运算的结果是一致的。
不同点:使用短路或的时候,当左边的布尔表达式为true时,则不会再运算右边的表达式。使用单或的时候,发现左边的布尔表达式为true,还是会运算右边的布尔表达式。
位运算符
位运算符就是直接操作二进制位的。
& (与)(&用于两个int型数据之间,它就是位运算符;&用于两个表达式之间,它就是逻辑运算符)
| (或)
^ (异或)(如果操作数A连续异或同一个操作数两次,那么结果还是操作数A。a^b和b^a效果是一样的)
~ (取反)
举例:
例一:System.out.println(6&3); //结果是2
计算过程:可以把1看成true,把0看成false。都为true时才为true,即都是1时才为1,其余都为0。
00000110 6
& 00000011 3
---------------
00000010 2
例二:System.out.println(6|3); //结果是7
计算过程:可以把1看成true,把0看成false。都为false时才为false,即都是0时才为0,其余都为1。
00000110 6
| 00000011 3
---------------
00000111 7
例三:System.out.println(6^3); //结果是5
计算过程:可以把1看成true,把0看成false。两位数字相同时才为true,即两个都是0或者两个都是1时,才为1,其余都为0。
00000110 6
^ 00000011 3
---------------
00000101 5
例四:6^3 再^3,=6
计算过程:
00000110 6
^ 00000011 3 (第一次异或3)
---------------
00000101 5
^ 00000011 3 (第二次异或3)
---------------
00000110 6 (结果还是它本身)
例五:System.out.println(~7); //7取反,结果是-8
计算过程:
00000111 7
~取反
---------------
11111000 - (此处是补码,补码最高位为1,代表是负数)
减- 00000001 1 (补码-1)
---------------
11110111 -7
~取反
---------------
00001000 8 (源码)
异或^:可使用异或,对图片数据进行加密
举例:对图片进行加密。(解密的话,需将加密的图片放入inFile中,同时outFile指定解密到哪个路径即可)
import java.io.*;
class ImageTest{
public static void main(String[] args) throws Exception{
//找到图片文件
File inFile = new File("F:\\图片\\1.jpg");
File outFile = new File("E:\\加密的图片1.jpg");
//建立数据通道,让图片的二进制数据流入
FileInputStream input = new FileInputStream(inFile);
FileOutputStream output = new FileOutputStream(outFile);
//边读,把读到的数据异或一个数据,把数据写出
int content = 0;//该变量是用于存储读取到的数据
while((content = input.read()) !=-1){ //while是循环,如果没有到文件的末尾,那么继续读取数据,读取到的数据已经存入content变量中
output.write(content^12);//把读取到的每一个数据都异或个12
}
//关闭资源
output.close();
input.close();
}
}
位运算符常见考题:
例题1:交换两个变量值(尽量不使用第三方变量)
int a = 3;
int b = 5;
//方式1:定义第三方变量
int temp = a; //3
a = b; //a=5
b = temp;
System.out.println("a+"+a+",b="+b);
//方式2:不借用第三方变量,用相加法。缺点:两个int类型的数据相加,有可能会出现超出int的表示范围
a = a + b; //a=8
b = a - b; //b=8-5=3
a = a - b; //a=8-3=5
System.out.println("a+"+a+",b="+b);
//方式3:可以使用异或。缺点:逻辑不清晰
a = a^b; //a=3^5
b = a^b; //b=(3^5)^5=3
a = a^b; //a=(3^5)^3=(5^3)^3=5
System.out.println("a+"+a+",b="+b);
例题2:取出一个二进制数据的指定位数。例如读取该二进制数据的低4位即1101
00000000-00000000-00010100-01001101 (源二进制数据)
& 00000000-00000000-00000000-00001111 (做与的运算,与的对象是:我们不要的位数都用0,要的位数都用1)
------------------------------------------
00000000-00000000-00000000-00001101 (得到我们想要的最后4位)
移位运算符
移位运算符
<< (左移)
>> (右移)
>>> (无符号右移)
左移原理:换算成二进制数据,整体左移,左侧多出的数据位删除,右侧新产生的空缺位补0。
规律:一个操作数进行左移运算的时候,结果就是=操作数*2的n次方,n就是左移的位数
举例:
System.out.println(3<<1); //将3左移1位,结果是6。要换算成二进制数据,然后左移一位。即3*2(1)=6
System.out.println(3<<2); //将3左移2位,结果是12。要换算成二进制数据,然后左移一位。即3*2(2)=12
System.out.println(3<<3); //将3左移3位,结果是24。要换算成二进制数据,然后左移一位。即3*2(3)=24
右移原理:换算成二进制数据,整体右移,右侧多出的数据位删除,左侧新产生的空缺位补0或1(若原二进制数是正数,左侧补0;若是负数,左侧补1)
规律:一个操作数,在做右移运算的时候,实际上等于该操作数除以2的n次方,n是右移的位数。
举例:3>>1 = 3 / 2(1) =1
3>>2 = 3 / 2(2) =0
无符号右移 与右移的区别:
进行右移运算的时候,如果操作数是一个正数,那么左边的空缺位使用0补,如果操作数是一个负数,那么左侧的空缺位使用1补。而无符号右移的时候,不管是正数还是负数都统一使用0补。
常见考题:
使用最高的效率计算出2乘以8的结果。
解题思路:通常认为的2*8 在计算机中既存储2的二进制数值,又存储8的二进制数值,然后两个二进制数相乘,效率不高。若用左移的方法解此题,即 2<<3 = 2*2(3) = 16.这种方式只需在计算机中存储2的二进制数值,然后进行左移即可。
三元运算符(三目运算符)
格式:
布尔表达式 ? 值1 : 值2 ;
若布尔表达式的结果为true时,则返回值1,;若表达式结果为false时,则返回值2.
例子:
int age=26;
String result= age>=18?"成年人":"未成年人";
System.out.println(result); //结果为 成年人
注意:
使用三元运算符的时候,一定要使用该表达式返回的结果,或者是定义一个变量接收该表达式返回的结果。
运算符的优先级
赋值运算符 优先级最低