Java小白学习笔记——操作符

1. 赋值运算符

1.1 简介

运算符用法说明
=x=y把=号右边的值赋给左边的变量
+=x+=yx=x+y
-=x-=yx=x-y
*=x*=yx=x*y
/=x/=yx=x/y
%=x%=yx=x%y,就是求x除以y的余数

后面的五个运算符同时进行了运算和赋值的操作,这里为了方便表格的表示把它们归入了赋值运算符。
对于基本类型来说,赋值就是把一个变量y的值复制到另一个变量x当中去,就算之后对x做修改,也不会影响到y

1.2 别名现象

但是在对“对象”进行赋值的时候,事实上真正进行操作的是对象的引用,就是把一个对象的引用赋值给另一个对象的引用:

class Assignment{//创建一个类Assignment
	int i;
}
public class Operator {

	public static void main(String[] args) {
		Assignment a1 = new Assignment();
		Assignment a2 = new Assignment();//创建两个新的Assignment对象,a1、a2分别是它们的引用
		a1.i = 1;
		a2.i = 0;
		System.out.print(a1.i+",");
		System.out.println(a2.i);
		a2 = a1;//将a1赋值给a2
		System.out.print(a1.i+",");
		System.out.println(a2.i);
		a2.i = 2;//改变a2
		System.out.print(a1.i+",");
		System.out.println(a2.i);
		a1.i = 3;//改变a1
		System.out.print(a1.i+",");
		System.out.println(a2.i);
	}
}

结果如下:
结果图片
可以看到,在执行赋值语句a2=a1之前,二者对应的i值还是不同的,但执行完赋值语句后,a2的i值直接被a1“覆盖”了,并且无论对a1还是a2中的哪一个做改变,最终都是同时改变了a1和a2。

这说明,a1和a2在执行赋值语句a2=a1后包含的是同一个引用,这个引用指向的是同一个对象,原本a2包含的对对象的引用,是指向一个值为0的对象。在对a2赋值的时候,这个引用被覆盖,也就是丢失了;而那个不再被引用的值为0对象会由“垃圾回收器”自动清理。

在将一个对象传递给方法时也会产生别名问题:

class Assignment{
	int i;
}

public class PassObject {
	static void f(Assignment a) {
		a.i = 5;
	}

	public static void main(String[] args) {
		Assignment a3 = new Assignment();
		a3.i = 4;
		System.out.print(a3.i+",");
		f(a3);
		System.out.println(a3.i);
	}
}

结果为:
结果图片

在许多编程语言中,方法f()似乎要在它的作用域内复制其参数Assignment a的一个副本;但Java实际上只是传递了一个引用,相当于执行了a = a3,即对对象的赋值。所以代码行:a.i = 5;实际上改变了方法f()外的对象。

2. 算术运算符

2.1 简介

算术运算符图片
一元的“+”“-”除了表示正负之外,也会将较小类型的操作数提升为int类型,例如:

byte b = 1;
//接下来的两行代码会报错,因为“-”“+”把等式右边的b提升为了int类型,不能直接窄化转换为左边的byte类型
b = -b;
b = +b;

自增自减操作符“++”“–”只能用于操作变量,不能操作被final关键字修饰了的量,也不能用于操作值。

2.2 String类型与“+”

一个表达式中如果含有String类型,那么该表达式的结果一定是String类型的。并且对于一个String类型的表达式来说,“+”起到一个连接转换的作用:

String s = "abc";
int a = 1,b = 2,c = 3;
System.out.println(s+a+b+c);//结果为abc123
System.out.println(a+b+c+s);//结果为6abc
System.out.println(s+(a+b+c));//结果为abc6

第一个输出是由于String类型的s放在了表达式的开头,编译器会先将abc转换成字符串型,然后与原本的字符串型s连接。
第二个输出是由于String类型的s没有放在表达式的开头,因此编译器先将a,b,c作为整型处理,此时的前面两个+号执行加法运算,得到的结果6再转换成字符串类型,第三个+号才起到连接作用。
第三个输出是由于小括号的原因,先处理了三个整型的加法,再转换成字符串类型。

所以,有时我们可以利用

int a;
System.out.println(""+a);

的方式来将一个其它类型的变量转换为字符串类型,而不需要用到一些诸如toString()的方法。

3. 关系运算符

3.1 简介

关系运算符图片
关系运算符产生的结果为boolean类型,如果关系真实则得到true。

要注意,对浮点数的比较是非常严格的。即使一个数仅在小数部分与另一个数存在极微小的差异,仍然认为它们是“不相等”的。即使一个数只比零大一点点,它仍然是“非零”值。

3.2 ==和!=

“==”和“!=”适用于所有基本类型,而其余不适用于boolean类型,因为对true和false比较大小没有意义。

然而,对于对象来说,使用“==”和“!=”事实上是比较两个对象的引用是否相同,这与正常的认知不同:

public static void main(String[] args) {
		Integer i1 = new Integer(15);
		Integer i2 = new Integer(15);
		System.out.println(i1 == i2);
		System.out.println(i1 != i2);
	}

结果是:
结果图片
尽管i1和i2的内容是相同的,但是引用不同,由于“==”和“!=”比较的是对象的引用,所以会先输出false,再输出true。
如果要想比较对象的实际内容,则应使用equals()方法:

public static void main(String[] args) {
		Integer i1 = new Integer(15);
		Integer i2 = new Integer(15);
		System.out.println(i1.equals(i2));
	}

此时的结果就为true。但是注意,但你在对自己新写的一个类使用equals方法进行比较时,如果你没有在自己新写的那个类中重写equals()方法的话,还是会默认比较引用。当然,在大多数Java类库中都已经重写了equals()方法,来使其比较实际内容而非引用。

3.3 instanceof

instanceof是一个双目的关系运算符,用于判断一个对象是否能成为一个类的实例:

obj instanceof class

其中obj为一个对象,Class表示一个类或者一个接口,当obj为Class的对象,或者是其直接或间接子类,或者是其接口的实现类,结果都返回true,否则返回false。
例如:

//obj为Class的对象:
Integer i = new Integer(1);
System.out.println(i instanceof Integer);//结果为true
//obj为Class接口的实现类:
interface in{
	
}
class CL implements in{
	
}
CL cl = new CL();
System.out.println(cl instanceof in);//结果为true
//obj为Class的子类:
class CL2 extends CL{
	
}
CL2 cl2 = new CL2();
System.out.println(cl2 instanceof CL);//结果为true
System.out.println(cl instanceof CL2);//结果为false
//obj为null:
System.out.println(null instanceof CL2);//结果为false,即如果obj为null,那么将返回false。

4. 逻辑运算符

逻辑操作符能根据参数的逻辑关系,生成一个布尔值(true或false)。

4.1 简介

逻辑运算符图片
与在C及C++中不同的是:不可将一个非布尔值当作布尔值在逻辑表达式中使用:

//下面的代码是错误的,逻辑运算符只能用于boolean值
int i1 = 0, i2 = 0;
System.out.println(i1 && i2);

注意,如果在应该使用String值的地方使用了布尔值,布尔值会自动转换成适当的文本形式。

4.2 短路现象

在使用逻辑运算符时,当整个表达式的值已经可以确定,就不再进行后续其它式子的运算:

static boolean print(int i) {
		System.out.println("表达式"+i+"已被计算");
		if (i>=2) {
			return true;
		} else {
			return false;
		}
	}
boolean b1 = Str.print(1)&&Str.print(2)&&Str.print(3);
System.out.println("逻辑运算结果为:"+b1);
boolean b2 = Str.print(3)&&Str.print(2)&&Str.print(1);
System.out.println("逻辑运算结果为:"+b2);
boolean b3 = Str.print(1)||Str.print(2)||Str.print(3);
System.out.println("逻辑运算结果为:"+b3);

结果为:
结果图片
对于b1来说,先计算print(1),结果为false,由于&&表达式只要有一个值为false,则结果一定为false,所有计算完print(1)后就不需要再计算后续的式子了。因此,只输出了“表达式1已被计算”。
对于b2来说,一直计算到print(1)才能知道整个表达式的值为false,因此三个表达式都会被计算。
对于b3来说,计算到print(2)时结果为true,由于||只要有一个值为true就可以确定结果,因此后续的print(3)不在被计算,只输出前两个表达式被计算。

事实上,如果所有的逻辑表达式都有一部分不必计算,那将获得潜在的性能提升。

5. 位运算符

按位操作符用来操作整数基本数据类型中的单个“比特”(bit),即二进制位。按位操作符会对两个参数中每个对应的位执行布尔代数运算,并最终生成一个结果。

5.1 简介

位运算符图片

按位操作符可与等号(=)联合使用,以便合并运算和赋值:&=、|=和^=都是合法的(由于“~”是一元操作符,所以不可与“=”联合使用)。

//! float f1 = 1,f2 = 2;
//! float f3 = f1 & f2;位运算符只针对整型
int i1 = 2,i2 = 3;
int i3 = i1^i2;
System.out.println(i3);//结果为1
i3 = i1&i2;
System.out.println(i3);//结果为2
i3 = ~i1;
System.out.println(i3);//结果为-3
i3 = i1|i2;
System.out.println(i3);//结果为3

5.2 boolean型与位运算符

boolean类型看做1位来处理,我们可对它执行按位“与”(&)、按位“或”(|)和按位“异或”(^)运算,但不能执行按位“非”(~),而可以执行的是逻辑“非”(!)。
对于布尔值,按位操作符具有与逻辑操作符相同的效果,但是按位位运算不会出现短路现象。

5.3 移位运算符

  1. 左移位操作符(<<):能按照操作符右侧指定的位数将操作符左边的操作数向左移动(在低位补0)。
  2. “有符号”右移位操作符(>>):则按照操作符右侧指定的位数将操作符左边的操作数向右移动。“有符号”右移位操作符使用“符号扩展”——若符号为正,则高位插入0;若符号为负,则高位插入1。
  3. “无符号”右移位操作符(>>>):使用“零扩展”——无论正负,都在高位插入0。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值