Java操作符
赋值操作符
- 操作符:赋值(=)。
- 作用:把右值赋给左值。
- 左值:必须是一个明确的、已命名的变量。
- 右值:右值可以时任何常数、变量或表达式。
- 对基本类型赋值:基本类型存储了实际的数值,而非引用,所以赋值时是将一个地方的内容复制到另一个地方。
- 如对基本数据使用a=b,那么b的内容直接复制给a,如果此时再修改a的值,它是不会影响b的值的。
-
int a = 0; int b = a; b = 1; System.out.println("a = " + a + ", b = " + b); 输出: a = 0, b = 1
-
- 对向方法中传入基本类型的变量,会将变量的实参复制一份给形参,如果再在方法修改变量的值是不会影响实参的,因为此时是在修改形参的值。
-
static void test(int a) { a = 1; } int a = 0; System.out.println("before a = " + a); test(a); System.out.println("after a = " + a); 输出: before a = 0 after a = 0
-
- 如对基本数据使用a=b,那么b的内容直接复制给a,如果此时再修改a的值,它是不会影响b的值的。
- 对对象赋值:我们在操作对象时其实操作的是对象的引用, 所以赋值时是将引用复制到了另一个地方,对象没有被复制。
- 如对对象使用c=d,那么c和d将指向同一个对象,如果此时修改c的某个属性,通过d打印该属性,你将发现d的属性的值和c的一样,因为它们本来引用的就是同一个对象而已。
-
class Test { public int a; } Test c = new Test(); c.a = 0; System.out.println("before c.a = " + c.a + ", c = " + c); Test d = c; d.a = 1; System.out.println("after c.a = " + c.a + ", c = " + c); System.out.println("after d.a = " + d.a + ", d = " + d); 输出: before c.a = 0, c = com.eos.javalearn.Test@2401f4c3 after c.a = 1, c = com.eos.javalearn.Test@2401f4c3 after d.a = 1, d = com.eos.javalearn.Test@2401f4c3
-
- 同理,向方法中传入对象也只是传递了一个引用,如果在方法中修改的某个属性是可以修改的。
-
class Test { public int a; } static void test(Test test) { test.a = 1; } Test test = new Test(); test.a = 0; System.out.println("before a = " + test.a); test(test); System.out.println("after a = " + test.a); 输出: before a = 0 after a = 1
-
- 如果将对象传入方法,同时让其引用一个新的对象,这是不会起作用的,因为只是将实参的引用复制给了形参,在引用新的对象时,是让形参去引用,而不是实参引用。
-
class Test { public int a; } static void test(Test test) { System.out.println("before a = " + test.a + ", 形参test = " + test); Test test1 = new Test(); test1.a = 1; System.out.println("a = " + test1.a + ", 局部变量test1 = " + test1); test = test1; System.out.println("after a = " + test.a + ", 形参test = " + test); } Test test = new Test(); test.a = 0; System.out.println("before a = " + test.a + ", 实参test = " + test); test(test); System.out.println("after a = " + test.a + ", 实参test = " + test); 输出: before a = 0, 实参test = com.eos.javalearn.Test@2401f4c3 before a = 0, 形参test = com.eos.javalearn.Test@2401f4c3 a = 1, 局部变量test1 = com.eos.javalearn.Test@7637f22 after a = 1, 形参test = com.eos.javalearn.Test@7637f22 after a = 0, 实参test = com.eos.javalearn.Test@2401f4c3
-
- 如对对象使用c=d,那么c和d将指向同一个对象,如果此时修改c的某个属性,通过d打印该属性,你将发现d的属性的值和c的一样,因为它们本来引用的就是同一个对象而已。
算数操作符
- 操作符:加(+)、减(-)、乘(*)、除(/)、取余(%)。
- 取余运算:
- 性质:对所有int数值a和所有非零int数值b满足:(a / b ) * b + (a % b) == a。
- 因此,a%b = a-(a/b)*b。
- 比如:
- 10%3 = 10 - (10/3)*3 = 10 - 3 * 3 = 10 - 9 = 1。
- 3%10 = 3 - (3/10)*10 = 3 - 0 * 10 = 3 - 0 = 3。
- 整数除法会直接去掉结果的小数位,而不是四舍五入。
- Java也使用一种来自c和c++的简化符号同时进行运算与赋值操作。
x += 1
等同于x = x + 1
。
- 一元加、减操作符:
- 一元减号和一元加号和二元减号和加号使用的符号是相同的,分别是-和+。
-
int a = 1; int b = -a; //一元减号相当于负号 int c = a + -b; //可以这样写,编译器会自动判断,但是影响可读性 int d = c / (-b); //建议这样写 System.out.println("a = " + a + ", b = " + b + ", c = " + c + ", d = " + d); 输出: a = 1, b = -1, c = 2, d = 2
- 一元减号就相当于负号,对应的一元加号却仅仅只有一元减号的另一个作用——将较小类型的操作数提升为int。
- 这些较小类型包括char、short和byte。
- 如果对int、long、float、long使用一元减号,就是将它们转换为对应的负数。
- 一元减号和一元加号不作用于boolean类型。
-
//前3个都有问题 byte a = 0; byte b = +a; byte c = -a; short d = 0; short e = +d; short f = -d; char g = '0'; char h = +g; char i = -g; //以下的都没问题 float j = 0.1f; float k = +j; float l = -j; double m = 0.1d; double n = +m; double o = +m; long p = 10l; long q = +p; long r = -p; int s = 1; int t = +s; int u = -s;
自增、自减运算符
- 操作符:自增(++)、自减(--)。
- 作用:使变量的值加一或减一,同时以改变后的值作为变量的新值。
- 这两个操作符各有两种使用方式:
- 前缀式:先执行运算,再生成值。
- 后缀式:先生成值,再执行运算。
-
int i = 1; System.out.println("i = " + i); System.out.println("++i = " + ++i); System.out.println("i++ = " + i++); System.out.println("i = " + i); System.out.println("--i = " + --i); System.out.println("i-- = " + i--); System.out.println("i = " + i); 输出: i = 1 ++i = 2 i++ = 2 i = 3 --i = 2 i-- = 2 i = 1
关系操作符
- 操作符:小于(<)、大于(>)、小于或等于(<=)、大于或等于(>=)、等于(==)、不等于(!=)。
- 作用:用于计算操作数的值之间的关系。如果是关系是真实的,关系表达式会生成true;否则生成false。
- 等于和不等于适用于所有的基本数据类型,而其他比较符不适用于boolean类型。因为boolean值只能为true或false,大于或小于对它来说没有意义。
- 等于和不等于:
- 比较基本类型用==或!=。
- 两个对象用==或!=是比较引用是否相同。
- 一般来说,比较对象用equals()方法,同时,基本类型不能用该方法,因为只有对象才有这个方法。
- equals()方法的默认行为是比较引用。大多数Java类库都实现了equals()方法,以便用来比较对象的内容,而非比较对象的引用。
-
Integer a = new Integer(1); Integer b = new Integer(1); System.out.println("a==b = " + (a == b)); System.out.println("a!=b = " + (a != b)); System.out.println("a.equals(b) = " + a.equals(b)); 输出: a==b = false a!=b = true a.equals(b) = true
-
逻辑操作符
- 操作符:与(&&)、或(||)、非(!)。
- 作用:可以根据参数的逻辑关系生成一个布尔值。
- 与、或、非操作只可应用于布尔值。
- 布尔值与String一起用时会自动转换成文本形式。
- 当使用逻辑操作符时,会有一种短路现象。即一旦能够明确无误地确定整个表达式的值,就不会再计算表达式余下的部分了,这种现象将带来性能上的提升。
- 如:
1 < 2 && 2 >3 && 3 < 4
- 第1个比较运算结果为true,接着比第2个,发现为false,由于与的关系,需要三个表达式都为true时最后的结果才为true,此时发现了一个false,因此就不会再计算第3个比较运算的结果了,它会直接返回false。
-
int a = 1; int b = 2; int c = 3; System.out.println("a < b && b < c = " + (a < b && b < c)); System.out.println("a > b || b > c = " + (a > b || b > c)); boolean d = false; System.out.println("!d = " + !d); 输出: a < b && b < c = true a > b && b > c = false !d = true
- 如:
按位操作符
- 操作符:按位与(&)、按位或(|)、按位非(~)、按位异或(^)。
- 作用:用来对两个参数中对应的二进制位执行布尔代数运算,并生成一个结果。
- 按位与:二元操作符,两个位都为1,结果才为1,否则为0。
- 3&5=1:
-
0000 0011 & 0000 0101 ————————————————— 0000 0001
- 按位或:二元操作符,两个位中只要有一个位为1,结果就为1,否则为0。
- 3|5=7:
-
0000 0011 | 0000 0101 ————————————————— 0000 0111
- 按位异或:二元操作符,两个位相同就为0,否则就为1。
- 3^5=6:
-
0000 0011 ^ 0000 0101 ————————————————— 0000 0110
- 按位非:一元操作符,对位进行取反,如果是1,结果就是0;如果是0,结果就是1。
- ~5=-6:
-
~ 0000 0101 ————————————————— 1111 1010
-
A B A&B A|B A^B ~A 0 0 0 0 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 1 1 1 0 0
- 按位与:二元操作符,两个位都为1,结果才为1,否则为0。
- 按位操作符可与等号联用,如&=、|=、^=。由于按位非是一元操作符,它不可以与等号联用。
- 可以把布尔类型作为一种单比特值对待,它可以进行按位与、按位或、按位异或操作,但不能进行按位非操作,可能是为了避免与逻辑非混淆。
- 布尔的按位运算符和逻辑操作符效果相同,但是它没有短路现象。
-
A B A&B A|B A^B true true true true false true false false true true false true false true true false false false false false
- 按位与的应用:
- ①归零:
-
1101 1111 & 0000 0000 ———————————— 0000 0000
-
- ②取指定位:
-
1010 1110 & 0000 1111 ————————————— 0000 1110
-
- ③判断奇偶
-
0000 0101 & 0000 0001 ————————————— 0000 0001
-
- ①归零:
- 按位或的应用:
- 将某些为设置为1
-
1010 1110 | 0000 1111 ————————————— 1010 1111
-
- 将某些为设置为1
- 按位异或的应用:
- 翻转指定位:
-
1010 1110 ^ 0000 1111 ————————————— 1010 0001
-
- 翻转指定位:
移位操作符
- 操作符:左移位(<<)、右移位(>>)、逻辑右移位(>>>)。
- 移位操作符只能用来处理整数类型。
- 左移位:按照右侧指定的位数将左边的操作数向左移动(在低位补0,高位丢弃)。
- 右移位:按照右侧指定的位数将左边的操作数向右移动(低位丢弃,若符号为正,则在高位插入0;若为负,则插入1)。
- 逻辑右移位:按照右侧指定的位数将左边的操作数向右移动(低位丢弃,无论正负,都在高位插入0)。
- 对char、byte、short类型的数值进行移位处理时,会先将它们转换为int型再进行移位,并且得到的结果也是int类型。
- 移位操作符可与等号联用,如<<=、>>=、>>>=。
- 对short或byte的值进行逻辑右移位运算时,它会先转换成int型,在进行右移操作,然后被截断,赋值给原来的类型,这种情况下极有可能得到-1的结果。
三元操作符
- 形式:boolean=exp ? value1 : value2。
- 三元操作符也叫条件操作符,布尔表达式boolean=exp的结果为true,则整个表达式的结果就为value1,否则为value2。
-
int a = 10; int b = 20; int c = a > b ? a : b; System.out.println("c = " + c); 输出: c = 20
-
类型转换操作符
- 作用:允许我们显示地进行类型转换。
- 既可以对数值进行类型转换,也可以对变量进行类型转换。
- 例子:
int a = (int) 0.1;
。 - 转换分类:
- 窄化转换:将能容纳更多信息的数据类型转化成无法容纳那么多信息的类型。这就意味着可能会丢失信息。需要显式地进行类型转换,编译器会前置进行类型转换。
- 浮点数窄化为整型值时,总是对数字进行截尾。如果想得到四舍五入的结果,可以使用Math类的round()方法。
- 扩展转换:不必显示地进行类型转换。因为新类型能容纳原来的信息,不会有任何丢失。
-
int a = 200000; //窄化转换 short b = (short) a; //扩展转换 long c = a; System.out.println("a = " + a + ", b = " + b + ", c = " + c); 输出: a = 200000, b = 3392, c = 200000
- 窄化转换:将能容纳更多信息的数据类型转化成无法容纳那么多信息的类型。这就意味着可能会丢失信息。需要显式地进行类型转换,编译器会前置进行类型转换。
- Java允许我们把任何基本数据类型转换成别的基本数据类型,但布尔型除外,后者根本不允许进行任何类型的转换处理。
- 其他:
- 在对基本数据类型执行算术或按位运算时,只要比int小 ,运算前都会先自动转换成int再进行运算,同时得到的结果也是int型,如果想要把结果赋值给较小的类型,就必须使用类型转换。
- 对于上一条来说,通常默认的整数就是int,所以不用表明,但是如果两个int进行运算,可能出现结果超出int范围的值,这是编译器可能不会显示错误信息或发出警告,运行时也不会出现异常,但需注意。
- 通常,表达式中出现的最大的数据类型决定了表达式最终结果的数据类型。
- 如果将一个float值与一个double值相乘,结果就是double型。
- 如果将一个int值与一个long值相加,结果就是long型。
运算符优先级
- 如果不使用括号将按照以下优先级次序进行计算。
a && b || c
等同于(a && b) || c
。
- 同一级别的运算符按照从左到右的次序进行计算,但右结合运算符除外。
a += b -= c
等同于a += (b -= c)
。
优先级从高到低:
运算符 | 结合性 |
---|---|
[] 、 . 、()(方法调用) | 从左向右 |
! 、~ 、++ 、-- 、+(一元运算) 、-(一元运算) 、()(强制类型转换) 、new | 从右向左 |
* 、/ 、% | 从左向右 |
+ 、- | 从左向右 |
<< 、>> 、>>> | 从左向右 |
< 、<= 、> 、>= 、instanceof | 从左向右 |
== 、!= | 从左向右 |
& | 从左向右 |
^ | 从左向右 |
| | 从左向右 |
&& | 从左向右 |
|| | 从左向右 |
?: | 从右向左 |
= 、+= 、-= 、*= 、/= 、%= 、&= 、|= 、^= 、<<= 、>>= 、>>>= | 从右向左 |
直接常量
如果使用了直接常量,编译器能辨认出它是什么类型,但有时候又不一定。
我们需要用一些字符来增加类型的具体信息。
- 直接常的后缀字符标识了它的类型。
- long:大写的L或小写的l(一般用大写的L,因为小写的l像数字1,容易造成混淆);
- float:大写的F或小写的f。
- double:大小的D或小写的d。
- 十六进制整数:以0x或0X为前缀,后面跟随0~9或大写或小写的a~f来表示。
- 八进制数:以0以为前缀,后面跟0~7的数字来表示。
- 如果试图将一个变量初始化成超出自身表示范围的值,编译器就会报错,同时建议我们将值转化为int型。
- c、c++或java中,二进制数没有直接常量表示法。可以用Integer或Long类的toBinaryString()静态方法显示结果。
-
//十六进制 int a = 0x2f; int b = 0X2F; //八进制 byte c = 077; //long型 long d = 100L; long e = 100l; long f = 100; //float型 float g = 1; float h = 1F; float i = 1f; //double型 Double j = 1D; Double k = 1d;
-
- 指数计数法:用于表示指数。
- 1.39e-43表示1.39X10-43。
- e代表10的幂次,见到e时请转换思维,它并不是自然对数的基数。
- 编译器通常会将指数作为双精度数(double)处理,因此,定义float型指数时,必须在后面跟上大写或小写的F。
-
float v = 1.39e-43f; double v1 = 1.39e-43;
-