Java学习笔记——操作符

本文为Java编程思想第四版的学习笔记,在此感谢作者Bruce Eckel给我们带来这样一本经典著作,也感谢该书的翻译及出版人员。本文为原创笔记,转载请注明出处,谢谢。


1.使用Java操作符

操作符接受一个或多个参数,并生成一个新值。参数的形式与普通的方法调用不同,但效果是相同的。加号和一元的正号(+)、减号和一元的负号(-)、乘号(*)、除号(/)以及赋值号(=)的用法与其他编程语言类似。

操作符作用于操作数,生成一个新值。另外,有些操作符可能会改变操作数自身的值,这被称为“副作用”。那些能改变操作数的操作符,最普遍的用途就是用来产生副作用,但要记住,使用此类操作符生成的值,与使用没有副作用的操作符生成的值,没有什么区别。

几乎所有的操作符都只能操作“基本类型”。例外的操作符是“=”、“==”和“!=”,这些操作符能操作所有的对象(这也是对象易令人糊涂的地方)。除此之外,String类支持“+”和“+=”。


2.优先级

当一个表,达式中存在多个操作符时,操作符优先级就决定了各个部分的计算顺序。Java对计算顺序做了特别的规定。其中,最简单的柜子就是先乘除后加减。程序员基本记不住或者忘记其他优先级规则,所以应该用括号明确规定计算顺序。


3.赋值

3.1赋值操作符“=”,它的意思是“取右边的值(即右值),把它赋值给左边(即左值)。右值可以是任何常数、变量或者表达式(只要它能生成一个值)。但左值必须是一个明确的、已命名的变量。也就是说,必须有一个物理空间可以存储等号右边的值。


3.2 对于基本数据类型的赋值是很简单的。基本类型存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接讲一个地方的内容复制到了另一个地方。例如,对基本数据类型使用a=b,那么b的内容就复制给a。若接着又修改了a,而b根本不会受这种修改的影响。但是在为对象”赋值“的时候,情况却发生了变化。对一个对象进行操作时,我们真正操作的是对对象的引用。所以倘若”讲一个对象赋值给另一个对象“,实际是将”引用"从一个地方复制到另一个地方。这意味着假若对对象使用c=d,那么c和d都指向原本只有d指向的那个对象。这种特殊的现象称为“别名现象”,是Java操作对象的一种基本方式。将一个对象传递给方法时,也会产生别名问题。


别名引起的问题及其解决方法是很复杂的话题,本菜鸟会在另外的博文中作为专题进行分析,但是现在我们应该知道它的存在,并在使用中注意这个陷阱。


4.算数操作符

4.1 Java的基本算术操作符与其他大多数程序设计语言是相同的。其中包括加号(+)、减号(-)、乘号(*)、除号(/)以及取模操作符(%,它从整数除法中产生余数)。整数除法会直接去掉结果的小数位,而不是四舍五入地圆整结果。Java也使用一种来自C和C++的简化负号同时进行运算与赋值操作,这用操作符后紧跟一个等号来表示,它对于Java中的所有操作符都使用,只要其有实际意义就行。例如,要将x加4,并将结果赋回给x,可以这么写:x += 4。


4.2 一元加、减操作符

一元加号(+)和减号(-)与二元加号和减号都使用想通的符号。根据表达式的书写形式,编译器会自动判断出使用的是哪一种。例如语句 x = -a;含义是显然的。编译器能正确识别下述语句:x = a * -b;但对着会被搞糊涂,所以有时更明确地写成:x = a * (-b);一元减号用于转变数据的符号,而一元加号只是为了与一元减号相对应,但它唯一的作用仅仅是将较小类型的操作数提升为int。


5.自动递增和递减

5.1 自动递增(++):增加一个单位;自动递减(--)减少一个单位。

5.2 这两个操作符有两种使用方式:“前缀式”和“后缀式”。会先执行运算后生成值,而后缀式则先生成值,在执行运算。对于前缀式,我们在执行完运算后才得到值,但对于后缀式,则是在运算执行之前就得到值。它们是除那些设计赋值的操作符以外,唯一具有“副作用”的操作符,也就是说,它们会改变操作数,而不仅仅是使用自己的值。


6.关系操作符

6.1 关系操作符生成的是一个boolean(布尔)结果,它们计算的是操作数的值之间的关系。如果关系是真实的,关系表达式会生成true(真);如果关系不真实,则生成false(假)。关系操作符包括小于(<)、大于(>)、小于或等于(<=)、大于或等于(>=)、等于(==)以及不等于(!=)。等于和不等于适用于所有基本数据类型,而其他比较符不适用于boolean类型。因为boolean值只能为true或false,“大于”和"小于“没有实际意义。


特别注意:对于浮点数的比较是非常严格的,即使一个数仅在小数部分与另一个数存在微小的差异,仍然认为它们是不相等的。比如我们想测试浮点型变量 float与0.6是否相等,直接写float == 0.6,也许不会得到正确的结果。这种问题的产生于浮点数在机器中的表示方式有关,通常我们需要这样写:float <= 0.6 && float >=0.6,来判断float是否与0.6相等。


6.2 测试对象的等价性

这也是一个比较复杂而且容易让人糊涂的地方,本菜鸟会在之后的博文中做具体的分析讨论,这里指记录结论:

1)关系操作符”==“和”!="也适用于所有对象,但是如果有如下代码:

{

Integer n1 = new Integer(47);

Integer n2 = new Integer(47);

System.out.println(n1 == n2);

}

输出的结果却为false,因为此处比较的n1和n2的引用。

2)如果上述代码中比较之处用n1.equals(n2),则结果为true,此处比较的为n1和n2的实际内容。但如果不是Integer对象而是自定义对象(Integer为Java内置的int的包装器类),并且我们没有重写equals()方法,则结果仍然为false,这是因为,equals()方法为Object类的方法,所有的类都默认存在这个方法,但是Object类中,equals()方法执行的操作实际上是比较对象的引用。对于Integer这样的Java内置的包装器类,Integer内部重写了equals()方法,使其比较的为Integer对象的实际内容。还有一个更为复杂的String类型,以后本菜鸟会做专门总结。


7.逻辑操作符

7.1 逻辑操作符“与”(&&)、“或”(||)、“非”(!)嫩根据参数的逻辑关系,生成一个布尔值(true或false)。“与”、“或”、“非”操作只可应用于布尔值。与在C和C++中不同的是:不可将一个非布尔值当做布尔值在逻辑表达式中使用。注意,如果在应该使用String的地方使用了布尔值,布尔值会自动转换成适当的文本形式。


7.2 短路。当使用逻辑操作符时,我们会遇到一种“短路”的现象。即一旦能够明确无误地确定整个表达式的值,就不在计算表达式余下部分了。因此,整个逻辑表达式靠后的部分有可能不会被运算。


8.直接常量

8.1 所谓“直接常量",实际上就是在程序中直接使用一个常量的值,如int n = 1;这里的1就是直接常量。这里我们需要注意的是,一般来说,如果程序使用了”直接常量“,编译器可以准确地知道要生成什么样的类型,但有时候确实模棱两可。如果发生这种情况,必须对编译器加以适当的”指导“,也就是在直接常量之后加上某些字符来增加额外的信息,如0.6f表示这是一个float类型浮点数,而不是double类型的浮点数。


8.2 指数记数法

Java中采用了一种很不直观的记数法来表示指数,它用e来代表10的次幂,这会让初学的我们有些不习惯,会把e当做自然对数的基数(就是那个约等于2.71828的),如Java中1.38e^-43,表示的含义是1.39 * 10^-43而不是1.39 * 2.71828^-43。

注意:编译器通常会将指数作为双精度数(double)处理,所以float f = 1e-43f;这个语句中,如果没有后面的f,就会收到一条错误提示,告诉我们必须使用类型转换将double转换成float。


9.按位操作符

按位操作符用来操作证书基本数据类型中的单个"比特(bit)",即二进制位。安慰操作符会对两个参数中对应的为执行布尔代数运算,并最终生成一个结果。按位运算符主要有”按位与(&)“、”按位或(|)“、”按位非(~)“和”异或(^)“四种。这里需要注意的有如下两点:

1)我们将布尔类型作为一种但比特值对待,所以它多少有些独特。我们可以对它执行按位”与“、按位”或“和按位”异或“运算,但不能执行按位”非“运算(大概是为了避免与逻辑NOT混淆)。在移位表达式中不能使用布尔运算。

2)对于布尔值,按位操作符具有与逻辑操作符相同的效果,只是它们不会中途”短路“


10.移位操作符

10.1 移位操作符的运算对象也是二进制的”位“。移位操作符只可用来处理整数类型(基本类型的一种)。Java中移位操作符主要有三种:

1)左移位操作符(<<),能按照操作符右侧指定的位数将操作符左边的操作数想做移动(在低位补0);

2)”有符号“右移操作符(>>),按照操作符右侧指定的位数将操作符左边的操作数向右移动。”有符号“右移位操作符使用”符号扩展“,若符号为证,则在高位插入0,若符号为负,则在高位插入1.

3)Java中增加了一种”无符号“右移操作符(>>>),它使用”零扩展“:无论政府,都在高位插入0.


10.2 如果对char、byte或者short类型的数值进行移位处理,那么在移位进行之前,它们会被转换为int类型,并且得到的结果也是一个int类型的值。只有数值右端低5位才有用,这样可以防止我们移位超过int型值所具有的位数。(译注:因为2的5次方为32,而int型只有32位)若对一个long类型的数值进行处理,最后得到的结果也是long。此时只会用到数值右端的低6位,以防止以为超过long型数值具有的数。(这里笨鸟不是很理解作者在说的是什么,求教)”移位“可与”等号“(<<=或>>=或>>>=)组合使用。在进行无符号右移时,可能会遇到一个问题:如果对byte或short值进行这样的位移运算,得到的可能尺正确的结果。它们会先被转换成int类型,再进行右移操作,然后被阶段,赋值给原来的类型。


有一点值得注意:移位是有周期性的,如int i = -1; 对i>>>32;这个表达式的值为-1,因为int为32为,右移32位相当于没有右移,具体为什么,本鸟尚不理解。


11.三元操作符if-else

boolean-exp ? value0:value1


12.字符串操作符+和+=

这个操作符在Java中有一项特殊用途:连接不同的字符串。这项功能在C++中似乎是个不错的主意所以引入了操作符重载机制,以便C++程序员可以为几乎所有操作符增加功能,但这过于复杂。与C++相比,尽管操作符重载在Java中更易实现,但仍过于复杂,所以Java程序员不能像C++和C#程序员那样是现在记得重载操作符。


字符串操作符有一些很有趣的行为。如果表达式以一个字符串起头,那么后续所有操作数都必须是字符串类型(请记住,编译器会把伤心好内的字符串序列自动转换成字符串)


13.使用操作符时常犯的错误

使用操作符时我们有时会犯一些错误,有以下几点,请注意:

1)即使对表达式如何计算有点不确定,也不愿意使用括号

2)Java不会将int值转化成布尔值,因此不要将int值作为布尔值使用

3)Java中有一个与C和C++中类似的问题,即使用按位”与“、按位”或“代替逻辑”与“、逻辑”或“。Java编译器可防止这个错误发生,因为它不允许我们随便把一种类型当做另一种类型来用。


14.类型转换操作符

14.1要想执行类型转换,需要将希望得到的数据类型置于圆括号内,放在要进行类型转换的值的左边。即可对数值进行类型转换,亦可对变量进行类型转换。注意:扩展转换,是安全的,不必显式地进行转换,但是窄化转换则是危险的,若无论如何要这么做,必须显式地进行类型装换。

14.2 截尾与舍入

在执行窄化转换时,必须注意截尾与舍入问题。Java中,在执行窄化转换时,总是执行截尾操作,故如想得到舍入结果,需调用相关函数。

14.3 提升

1)如果对基本数据类型执行算数运算或按位运算,只要比int小(即char,byte或者short),那么在运算之前,这些值会自动转换成int,这样一来,最终生成的结果就是int类型

2)表达式中出现的最大的数据类型决定了表达式最终结果而数据类型。


15.Java没有sizeof()

在C和C++中,sizeof()操作符可以告诉你为数据项分配的字节数。在C和C++中,需要使用sizeof()的最大原因是为了”移植“.Java不需要sizeof()操作符来满足这方面的需求,因为所有数据类型在所有机器中的大小都是相同的,我们不必考虑移植问题——它已经被设计在语言中了。


总结:本章主要内容是Java中操作符的相关知识,相信学过编程语言的同学对这个并不陌生,掌握起来也没有什么难度。只是Java中有些需要注意的点,需要警惕。归纳如下:

1)能够对布尔型进行的运算非常有限。我们只能赋予它true和false值,并测试它为真还是假,而不能对布尔值想家,或对布尔值进行其他任何运算。

2)在char、byte和short中,我们可以看到使用算数操作附中数据类型提升的效果。对这些类型的任何一个进行算术运算,都会得到一个int结果,必须将其显式地类型转换回原来的类型(窄化转换可能会造成信息丢失),以将其赋值给原本的类型。但是,复合赋值并不需要类型转换。

3)除boolean以外,任何一种基本类型都可以通过类型转换变为其他基本类型。











  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值