1. 运算符概述
运算符是指对操作数的运算方式。组成表达式的Java操作符有很多种(什么是操作数和操作符,例如1+2,其中1和2都是操作数,+是操作符,操作符和操作数联合起来构成表达式)。运算符按照其要求的操作数数目来分,可以有单目运算符(1个操作数)、双目运算符(2个操作数)和三目运算符(3个操作数)。运算符按其功能来分,有算术运算符、赋值运算符、关系运算符、逻辑运算符、位运算符、条件运算符、字符串连接运算符和其他运算符。常见的运算符如下所示:
2. 运算符详解
2.1 算数运算符
算术运算符包括:+(两个数字求和)、-(两个数字相减)、*(两个数字乘积)、/(两个数字相除)、%(两个数字取模或者求余)、++(单目运算符,对数字自加1)、–(单目运算符,对数字自减1)。
public class ArithmeticOperatorTest01 {
public static void main(String[] args) {
int a = 10;
int b = 3;
System.out.println(a + b); //13
System.out.println(a - b); //7
System.out.println(a * b); //30
/*
* 在java 语言中 10 除以 3 结果不是 3.3333..
* 因为java 中有一个语法规则:int 类型和int 类型
* 做运算,最终的结果还是int 类型,所以 10 除以 3
* 的结果就是 3,这个过程会取整数位。
*/
System.out.println(a / b); //3
/*
* 10 对 3 求余数,3 乘 3 得 9,余 1。
*/
System.out.println(a % b); //1
/*
* ++和--都是单目运算符,++负责自加 1,--负责自减 1
* 以下程序重点研究++运算符,--运算符可以依照++运算
* 符进行类推。
*/
int i = 10;
i++;
System.out.println("i = " + i); //11
int j = 10;
++j;
System.out.println("j = " + j); //11
/*
* 根据以上的程序可以得出结论:++可以出现在变量前,也
* 可以出现在变量后,无论是变量前还是变量后,只要执行完
* ++,最终的结果都会让变量自加1。那么++出现在变量前
* 和变量后到底有什么区别呢?请看以下程序
*/
int k = 10;
int m = k++;
/*
* 根据以上结论,++无论是出现在变量前还是变量后,只要++执行
* 变量一定会自加1,那么 k 变量一定会自加 1,所以以下输出 k=11
*/
System.out.println("k = " + k); //11
/*
* 以上int m = k++;代码中++和=两个运算符同时存在,
* 那么此时这两个运算符哪个优先级高呢?java 语法中是这样
* 规定的,当++运算符出现在变量后,会先做赋值运算,再自
* 加 1,所以最后m = 10
*/
System.out.println("m = " + m); //10
int x = 10;
int y = ++x;
//上行代码执行结束后,我们可以确定 x 变量一定自加1 了,所以 x=11
System.out.println("x = " + x); //11
/*
* java 语法中又有这样的规定,++出现在变量前,会先进行自加 1
* 的操作,然后再做赋值运算,所以y = 11
*/
System.out.println("y = " + y); //11
}
}
运行结果:
第一:两个int类型数据进行数学运算之后的结果一定是int类型;第二:++或–可以出现在变量前也可以是变量后;第三:++无论出现在变量前还是变量后,只要执行了++,那么变量必然会自加1;第四:++出现在变量后会先进行赋值运算,再自加1;第五:++出现在变量前会先自加1,再进行赋值运算。
2.2 关系运算符
关系运算符主要是完成数据和数据之间的比较,比如:5>3,结果是true(真),5>10,结果是false(假),>、>=、<、<=、==、!=。
class RelationOperatorTest01 {
public static void main(String[] args) {
int a = 10;
int b = 10;
System.out.println(a > b);//false
System.out.println(a >= b);//true
System.out.println(a < b);//false
System.out.println(a <= b);//true
System.out.println(a == b);//true
System.out.println(a != b);//false
/*
* 比较两个字符串是否相等,不能使用“==”,
* 必须调用equals 方法,equals 方法以后会
* 讲解的,现在先记住吧
*/
System.out.println("abc".equals("abc"));//true
}
}
任何一个关系运算符的运算结果都是布尔类型,最后的结果不是true就是false,没有其他值,
2.3 逻辑运算符
逻辑运算符主要包括逻辑与(&),逻辑或(|),逻辑异或(^),短路与(&&),短路或(||)。所有逻辑运算符的特点是操作数都是布尔类型,并且最终的运算结果也是布尔类型。逻辑运算符的基本运算规则如下表所示:
测试:
public class LogicalOperatorTest01 {
public static void main(String[] args) {
System.out.println(5 > 3 & 5 > 4); //true
System.out.println(5 > 100 | 5 > 4); //true
System.out.println(!(5 > 3)); //false
System.out.println(!(5 < 3)); //true
System.out.println(true & true); //true
System.out.println(true & false); //false
System.out.println(true | false); //true
System.out.println(!false); //true
System.out.println(!true); //false
System.out.println(true ^ false); //true
System.out.println(true ^ true);//false
System.out.println(false^ false); //false
//重点研究逻辑与(&)和短路与(&&)的区别
int x = 100;
int y = 98;
int z = 99;
System.out.println(x > y & x > z); //true
System.out.println(x > y && x > z); //true
/*
* 通过测试得出,逻辑与(&)和短路与(&&)最终运行
* 结果相同那么它们有什么区别呢?请看以下代码。
*/
int m = 99;
int n = 100;
System.out.println(m > n & m > n++); //false
/*
* 逻辑与(&)运算符只有当两边的操作数都是true 的时候,
* 结果才是true,只要有一个是false,结果必然是false。
* 以上程序逻辑左边的表达式(m > n)显然结果是false,
* 通过左边的表达式已经可以得出结果是false 了,右边的
* 表达式没有执行的必要,那我们来看一下右边的表达式
* 有没有执行,只要输出n 就可以了断定。
*/
System.out.println("n = " + n); //101
/*
* 以上程序的运行结果是 101,足以说明 n++已经执行了。
* 也说明了逻辑与运算符无论左边表达式结果是true 还
* 是false,右边表达式一定会执行。
*/
//那我们来看一下短路与(&&)是怎样的?
int k = 99;
int f = 100;
System.out.println(k > f && k > f++); //false
System.out.println("f = " + f); //100
/*
* 通过以上测试得出f++并没有执行,因为左边表达式(k > f)
* 为false,右边的表达式就不再执行了,这种现象被称为短路
* 现象。也就是说对于短路与来说,左边的表达式只要为false,
* 就会发生短路,右边表达式不再执行了。
*/
}
}
通过以上的测试,可以得出短路与(&&)在左边的表达式结果为false的时候,右边的表达式则不再执行,这种现象被称为短路现象,这种机制也显得短路与比较智能一些,效率更高一些,所以在实际开发中短路与(&&)的使用率要比逻辑与高一些。但这并不是绝对的,有的时候也可能会选择使用逻辑与(&),这取决于你是否期望右边的表达式一定执行。
2.4 赋值运算符
赋值运算符目前也是只需要掌握=、+=、-=、=、/=、%=,其它和二进制相关的内容也是到后面遇到的时候再详细学习。赋值类的运算符包括基本赋值运算符(=)和扩展的赋值运算符(+=、-=、=、/=、%=)。
public class AssignmentOperatorTest01 {
public static void main(String[] args) {
//基本的赋值运算符
int i;
i = 10;
System.out.println("i = " + i);
i = 100;
System.out.println("i = " + i);
//扩展的赋值运算符
int x = 10;
x += 1; //等同于x = x + 1
System.out.println("x = " + x); //11
int y = 10;
y -= 1; //等同于y = y - 1
System.out.println("y = " + y); //9
int z = 10;
z *= 2; //等同于z = z * 2
System.out.println("z = " + z); //20
int m = 10;
m /= 3; //等同于m = m / 3
System.out.println("m = " + m); //3
int n = 10;
n %= 3; //等同于 n = n % 3
System.out.println("n = " + n); //1
}
}
x += 1和x = x + 1不是相同的
测试:
class AssignmentOperatorTest02 {
public static void main(String[] args) {
byte b = 10;
//以下程序编译报错,编译器提示错误信息为:
//Type mismatch: cannot convert from int to byte
/*
* 编译没有通过的原因:b 是byte 类型,1 是int 类型,根据之前
* 讲解的类型转换规则得知,byte 和int 混合运算最后结果是
* int 类型,int 类型的值无法直接赋值给byte 类型的变量b,
* 所以编译报错。
*/
//b = b + 1;
b += 1; //编译通过并可以正常运行
System.out.println("b = " + b); //11
//通过以上的测试得出:b = b + 1 和b += 1 是不一样的
//那么b += 1 等同于什么呢?
/*
* 实际上java 对于扩展类的赋值运算符进行了特殊的处理,
* 所有的扩展赋值运算符,最终都不会改变运算的结果类
* 型,假设前面的变量是byte 类型,那么后面的表达式运
* 算之后的结果还是byte 类型。所以实际上b += 1 等同于:
*/
b = (byte)(b + 1);
System.out.println("b = " + b); //12
b += 1000; //编译通过,并且可以正常运行
/*
* 以上代码实际上等同于:b = (byte)(b + 1000);
* 分析得出,显然结果已经超出了byte 类型取值范围,
* 所以精度一定会损失,最终的结果需要对计算机
* 二进制的原码反码补码进行研究。
*/
System.out.println("b = " + b); //-12
}
}
根据以上代码测试得出,对于扩展类的赋值运算符在运算的过程中不会改变运算的结果类型,也就是说byte b = 100; b += 1000;b变量最初是byte类型,最后的运算结果还是一个byte类型。这是一条固定的语法规则,大家记住就行了,以后在使用扩展类赋值运算符的时候要谨慎,不小心就会精度损失的。
2.5 条件运算符
条件运算符属于三目运算符,它的语法结构是:布尔表达式?表达式1:表达式2。它的运行原理是这样的,先判断布尔表达式的结果是true还是false,如果是true,则选择表达式1的结果作为整个表达式的结果,反之则选择表达式2的结果作为整个表达式的结果。
public class ConditionalOperatorTest01 {
public static void main(String[] args) {
//编译报错:这不是一个语句
//10;
boolean flag = true;
//编译报错:这不是一个语句
//flag ? 1 : 0;
//以上如果是一条完整的语句应该这样写
int k = flag ? 1 : 0;
System.out.println("k = " + k); //1
//三目运算符最经典的用法
boolean sex = true;
//当布尔变量sex 为true 则结果是'男',反之'女'
char gender = sex ? '男' : '女';
System.out.println("性别:" + gender); //男
sex = false;
gender = sex ? '男' : '女';
System.out.println("性别:" + gender); //女
//又如
int x = 100;
int y = 100;
System.out.println(x==y?"x 和y 相等":"x 和y 不相等");
}
}
2.6 字符串连接运算符
在java语言中所有的字符串都使用半角双引号括起来的,字符串属于引用数据类型,不属于基本数据类型的范畴,例如:String name = “jack”;,这就类似于int i = 10;是一样的,int是一种整数类型,i是变量,10是整数型字面量。那么String则是一种字符串类型,name是变量,”jack”是字符串型字面量。在java编程中对字符串的操作是非常频繁的,例如字符串的连接操作,此时就需要使用“+”字符串连接运算符了。
实际上“+”运算符在java语言中有两个作用,作用一是对数字进行求和运算,作用二就是字符串连接运算,,当“+”运算的时候,两边的操作数都是数字的话,一定会进行求和运算,只要其中有一个操作数是字符串类型,那么一定会进行字符串拼接运算,字符串拼接之后的结果还是字符串类型。需要注意的是,当一个表达式当中有多个“+”,并且在没有小括号的前提下,遵循自左向右的顺序依次执行。
class PlusTest01 {
public static void main(String[] args) {
int a = 10;
int b = 20;
//加号两边都是int 类型,执行求和运算
int c = a + b;
/*
* 以下代码虽然有两个加号,第一个加号在双引号当中,
* 不起任何作用,只是一个普通字符串,第二个加号由于
* 左边操作数是一个字符串,所以这个加号一定会进行
* 字符串连接,连接之后的结果还是一个字符串。
*/
System.out.println("a + b = " + c); //a + b = 30
/*
* 分析以下程序的输出结果?哪些加号进行求和,
* 哪些加号进行字符串连接
*/
System.out.println(a + " + " + b + " = " + a + b);
/*
* 分析以下程序的输出结果?哪些加号进行求和,
* 哪些加号进行字符串连接
*/
System.out.println(a + " + " + b + " = " + (a + b));
//定义一个字符串类型变量
String name = "jack";
/*
* 字符串拼接在实际开发中很常用,拼接的时候是有口诀,
* 大家记住,将变量放到字符串当中进行拼接,可以这样
* 做:1、在拼接的位置添加一个英文双引号;2、在双引
* 号中间添加两个加号;3、把字符串变量放到两个加号
* 中间。
*/
System.out.println("登录成功,欢迎"+ name + "回来!");
}
}
对于程序System.out.println(a + " + " + b + " = " + a + b);的分析见下图:
对于程序System.out.println(a + " + " + b + " = " + (a + b));的分析见下图: