操作符

 在最底层,Java中的数据是通过适用操作符来操作的。

  Java是建立在C++基础之上的,所以C和C++程序员应该非常熟悉Java的大多数操作符。当然,Java也做了一些改进与简化。

  如果读者熟悉C或C+=的原发,那么只需快速浏览本章和下一章,看看Java与这些语言之间的差异。

3.1 更简单的打印语句

    System.out.println();

3.2 使用Java操作符

    操作符接受一个或多个参数,并生成一个新值。

    参数的形式与普通的方法调用不同,但效果是相同的。

    加号和一元的正号(+)、减号和一元的负号(-)、乘号(*)、除号(/)以及赋值号(=)的用法与其他编程语言类似。

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

    几乎所有的操作符都只能操作“ 基本类型 ”。

     例外的操作符是“ = ” “  == ”和 “  != ” ,这些操作符能操作所有的对象(这也是对象易令人糊涂的地方)。

     除此以外,String类支持“ + ” 和 “ += ”。

   3.3   优先级

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

      例如,以下语句中的(1)和(2):

     //:operators/Precedence.java

      public class Precedence {

      public static void main(String[] args)

    {

        int x = 1,y=2,z=3;

        int a = x+y-2/2 + z;

        int b = x + (y-2)/(2+z);

        System.out.println(“a=” + a + “ b= ”+ b );

   }

}

  a = 5 b=1;

  这两个语句看起来大体相同,但是从输出就可以看出它们具有迥然不同的含义,而这正是使用括号的结果。

 3.4 赋值

      赋值使用操作符 “ = ”。它的意思是“ 取右边的值(即右值),把它复制给左边(即左值) ”。

      右值可以是任何常数、变量或者表达式(只要它能生成一个值就行)。但左值必须是一个明确的,已经命名的变量。

      也就是说,必须有一个物理空间可以存储等号右边的值。

       举例来说,可将一个常数付给一个变量:

       a = 4;

        但是不能把任何东西付给一个常数,常数不能作为左值(比如不能说 4 =a;)。

        对于基本数据类型的赋值是很简单的。基本类型存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接讲一个地方的内容复制到了另一个地方。

        但是在对象“ 赋值 ”的时候,情况却发生了变化。对一个对象进行操作时,我们真正操作的是对对象的引用。所以倘若“ 将一个对象赋值给另一个对象 ”,实际是将“ 引用 ”从一个复制到另一个地方。这意味着假若对象使用 c= d,那么 c和d都指向原本只有d指向的那个对象。

       下面这个例子将向大家阐示这一点:

对象赋值

   

      原本t1包含的对对象的引用,是指向一个值为9的对象。在对t1赋值的时候,这个引用被覆盖,也就是丢失了;而那个不再被引用的对象会由“ 垃圾回收器 ”自动清理)

      这种特殊的现象通常称作为“ 别名现象 ”,是Java操作对象的一种基本方式。在这个例子中,如果想避免别名问题应该怎么办呢?可以这样写:

       t1.level = t2.level;

       这样便可以保持两个对象的域内容彼此独立,而不是将t1和t2绑定到相同的对象。但你很快就会意识到,直接操作对象内的域内容容易导致混乱,并且,违背了良好的面向对象程序设计的原则。这可不是一个小问题,所以从现在开始大家应该留意,为对象赋值可能会产生意想不到的结果。

    3.4.1 方法调用中的别名问题

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

  

一个对象传递给方法时

    

        在许多编程语言中,方法f()似乎要在它的作用域内复制其参数Letter y的一个副本;但实际上只是传递了一个引用。所以代码行

        y.c = “z”;

       实际改变的是f()之外的对象。

       别名引起的问题及其解决办法是很复杂的话题,本书的在线补充材料涵盖了此话题。但是你现在就应该知道它的存在,并在使用中注意这个陷阱。

   3.5 算术操作符

    Java的基本算术操作符与其他大多数程序设计语言是相同的。

    其中包括加号(+)、减号(-)、除号(/)、乘号(*)以及取模操作符(%,它从整数除法中产生余数)。整数除法会直接去掉结果的小数位,而不是四舍五入地圆整结果

  Java也使用一种来自C和C++的简化符号同时进行运算与赋值操作。这用操作符后紧跟一个符号来表示,它对于Java中的所有操作符都适用,只要其有实际意义就行。例如,要将x加4,并将将结果赋回给x,可以这么写:x+=4;

     下面这个例子展示了各种算术操作符的用法:

    

  

各种操作符 的用法 

       3.5.1一元加、减操作符

      一元减号(-)和一元加号(+)与二元减号和加号都使用相同的符号。

      根据表达式的书写形式,编译器会自动判断出使用的是哪一种。

      3.6     自动递增和递减

      和C类似,Java提供了大量快捷运算。这些快捷预算使编码更方便,同时也使得代码更容易阅读,但是有时可能是代码阅读起来更困难。

      递增和递减运算时两种相当不错的快捷运算(常称为“ 自动递增 ”和“ 自动递减 ”运算)。

      其中,递减操作符是“ -- ”,意为 “ 减少一个单位 ”;

                 递增操作符是“++”,意为 “ 增加一个单位 ”。

       举个例子来说,假设 a 是一个int (整数)值,则表达式++a就等价于(a=a+1)。递增和递减操作符不仅改变了变量,并且以变量的值作为生成的结果。

       这两个操作符各有两种使用方式,通常称为“ 前缀式 ”和“ 后缀式 ”。

      “ 前缀递增 ”表示“ ++ ”操作符位于变量或表达式的前面;而“ 后缀递增 ”表示 “ ++ ”操作符位于变量或表达式的后面。类似地,“ 前缀递减 ” 意味着 “ -- ”操作符位于变量或表达式的前面;而“ 后缀递减 ”意味着 “ -- ”操作符位于变量或表达式的后面。

       对于前缀递增和前缀递减(如 ++a或 --a),会先执行运算,再生成值。而对于后缀递增和后缀递减(如 a++或a--),会先生成值,再执行运算。

       从中可以看到,对于前缀形式,我们在执行完运算后才得到值。但对于后缀式,真实在执行之前就得到值。它们是除那些涉及赋值的操作符以外,唯一具有“ 副作用 ”的操作符。也就是说,它们会改变操作数,而不仅仅是使用自己的值。

     3.7 关系操作符

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

    3.7.1 测试对象的等价性

      关系操作符 == 和 != 也适用于所有对象,但这两个操作符通常会使第一次接触Java的程序员感到迷惑。

       下面是一个例子:

对象的操作符比较

 

       如果想比较两个对象的实际内容是否相同,又改如何操作呢?此时,必须使用所有对象都适用的特殊方法 equals()。但这个方法不适用于 “ 基本类型 ”,基本类型直接使用 == 和 !=即可。

        实际上equals()的默认行为是比较引用,所以除非在自己的新类中覆盖equals()方法,否则不可能表现出我们希望的行为。

       大多数Java类库实现了eauals()方法,以便用来比较对象的呢日用,而非比较对象的引用。

      3.8 逻辑操作符

     逻辑操作符“ 与 ”(&&)、“ 或 ”(||)、非(!)能根据参数的逻辑关系,生成一个布尔值(true或false)。

     “ 与 ”、“ 或 ”、“ 非 ”操作只可应用于布尔值。与在C及C++中不同的是:不可将一个非布尔值当做布尔值在逻辑表达式中使用。

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

      3.8.1  短路

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

       3.9 直接常量

      一般来说,如果在程序里使用了“ 直接常量 ”,编译器可以准确地知道要生成什么样的类型,但有时候确实模棱两可的。如果发生这种情况,必须对编译加以适当的“ 指导 ”,用与直接量相关的某些字符来额外增加一些信息。

       直接常量后面的后缀字符标志了它的类型。

       若为大写(或小写)的L,代表 long(但是,使用小写字母l容易造成混淆,因为它看起来很像数字1)。

       大写(或小写)字母F,代表float;

       大写(或小写)字母D,则代表double。

        十六进制数适用于所有整数据类型,以前缀(零x,不是字母Ox)0x或(0X),后面跟随0-9或小写(或大写)的a-f来表示。如果试图将一个变量初始化成超出自身表示范围的值(无论这个值的数值形式如何),编译器都会向我们报告一条错误信息。注意在前面的代码中,已经给出了char、byte以及short所能表示的最大的十六进制值。如果超出范围,编译器会将值自动转换为int型,并告诉我们需要对这次赋值进行“ 窄化转型 ”(转型将在本章稍后部分定义)。这样我们就可清楚地知道自己的操作是否越界了。

         八进制数由前缀0以及后续的0~7的数字来表示。

         在C、C++或者Java中,二进制数没有直接常量表示方法。但是,在使用十六进制和八进制计数法时,以二进制形式显示结果非常有用。通过适用Integer和Long类的静态方法 toBinarString()可以很容易地实现这一点。

      3.9.1 指数计数法

     Java采用了一种很不直观的计数法来表示指数,例如:

     

指数计数法

 

      

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值