1:运算符

一个运算符可 改变运算对象的值,这叫作“副作用”(Side Effect)。运算符常见的用途就 是修改自己的运算对象,从而产生副作用。但要注意生成的值亦可由没有副作用 的运算符生成。 几乎所有运算符都只能操作“主类型”(Primitives)。唯一的例外是“=”、 “==”和“!=”,它们能操作所有对象(也是对象易令人混淆的一个地方)。除此 以外,String 类支持“+”和“+=”。  

 

  2:赋值

但在为对象“赋值”的时候,情况却发生了变化。对一个对象进行操作时, 我们真正操作的是它的句柄。所以倘若“从一个对象到另一个对象”赋值,实际 就是将句柄从一个地方复制到另一个地方。这意味着假若为对象使用“C=D”,那 么C和D终都会指向初只有 D 才指向的那个对象

 

  3:==和!=

public class Equivalence {

  public static void main(String[] args) {

  Integer n1 = new Integer(47);

  Integer n2 = new Integer(47);
  System.out.println(n1 == n2);

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

  }

} ///:~
其中,表达式 System.out.println(n1 == n2)可打印出内部的布尔比较结果。 一般人都会认为输出结果肯定先是 true,再是 false,因为两个 Integer 对象都 是相同的。但尽管对象的内容相同,句柄却是不同的,而==和!=比较的正好就是 对象句柄。所以输出结果实际上先是 false,再是 true。这自然会使第一次接触 的人感到惊奇。

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

public class EqualsMethod {

  public static void main(String[] args) {

    Integer n1 = new Integer(47);

    Integer n2 = new Integer(47);

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

  }

} ///:~ 

正如我们预计的那样,此时得到的结果是 true

但事情并未到此结束!假设 您创建了自己的类,就象下面这样:
 //: c03:EqualsMethod2.java
class Value {

int i;

}
public class EqualsMethod2 {

   public static void main(String[] args) {

   Value v1 = new Value();

   Value v2 = new Value();

   v1.i = v2.i = 100;

   System.out.println(v1.equals(v2));

   }

} ///:~
此时的结果又变回了 false!这是由于 equals()的默认行为是比较句柄。所 以除非在自己的新类中改变了 equals(),否则不可能表现出我们希望的行为。 不幸的是,要到第 7 章才会学习如何改变行为。但要注意 equals()的这种行为 方式同时或许能够避免一些“灾难”性的事件。 大多数 Java 类库都实现了 equals(),所以它实际比较的是对象的内容,而 非它们的句柄。

 

  4:逻辑运算符

只可将 AND,OR 或 NOT 应用于布尔值。与在 C 及 C++中不同,不可将一个非 布尔值当作布尔值在逻辑表达式中使用。若这样做,就会发现尝试失败,并用一
个“//!”标出。

注意若在预计为 String 值的地方使用,布尔值会自动转换成适当的文本形 式。 

 

  5:按位运算符

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

我们可执行按位 AND,OR 和 XOR,但不能执行按位 NOT (大概是为了避免与逻辑 NOT 混淆)。对于布尔值,按位运算符具有与逻辑运算 符相同的效果,只是它们不会中途“短路”。此外,针对布尔值进行的按位运算 为我们新增了一个 XOR 逻辑运算符,它并未包括在“逻辑”运算符的列表中。在 移位表达式中,我们被禁止使用布尔运算,原因将在下面解释。 

 

  6:移位运算符

左移位运算符(<<)能将运算符左边的运算对象向左移动
运算符右侧指定的位数(在低位补 0)。“有符号”右移位运算符(>>)则将运算 符左边的运算对象向右移动运算符右侧指定的位数。“有符号”右移位运算符使 用了“符号扩展”:若值为正,则在高位插入 0;若值为负,则在高位插入 1。Java 也添加了一种“无符号”右移位运算符(>>>),它使用了“零扩展”:无论正负, 都在高位插入 0。这一运算符是 C 或 C++没有的。 

注意高位代表 正负号:0 为正,1 为负

 

  7:造型运算符

  7-1 “造型”(Cast)的作用是“与一个模型匹配”。

若进行一种名为“缩小转换”(Narrowing Conversion)的操作(也 就是说,脚本是能容纳更多信息的数据类型,将其转换成容量较小的类型),此 时就可能面临信息丢失的危险。此时,编译器会强迫我们进行造型,就好象说: “这可能是一件危险的事情——如果您想让我不顾一切地做,那么对不起,请明 确造型。

Java 允许我们将任何主类型“造型”为其他任何一种主类型,但布尔值 (bollean)要除外,后者根本不允许进行任何造型处理。“类”不允许进行造型。 为了将一种类转换成另一种,必须采用特殊的方法(字串是一种特殊的情况,本 书后面会讲到将对象造型到一个类型“家族”里;例如,“橡树”可造型为“树”; 反之亦然。但对于其他外来类型,如“岩石”,则不能造型为“树”)。 

在 Java 中看到象“1.39e-47f”这样的表达式时,请转换您的思维,从程序设计的 角度思考它;它真正的含义是“1.39×10 的-47 次方”。  

 

  7-2 注意如果编译器能够正确地识别类型,就不必使用尾随字符。对于下述语句:

long n3 = 200;

它并不存在含混不清的地方,所以 200 后面的一个 L 大可省去。然而,对于 下述语句:

float f4 = 1e-47f; //10 的幂数

编译器通常会将指数作为双精度数(double)处理,所以假如没有这个尾随 的 f,就会收到一条出错提示,告诉我们须用一个“造型”将 double 转换成 float。  

  7-3 通常,表达式中大的数据类型是决定了表达式终结 果大小的那个类型。若将一个 float 值与一个 double 值相乘,结果就是 double; 如将一个 int 和一个 long 值相加,则结果为 long。 

  7-4 Java 不需要 sizeof()运算符来满足这方面的需要,因为所有数据类型在所 有机器的大小都是相同的。我们不必考虑移植问题——Java 本身就是一种“与 平台无关”的语言。 

 

  8:运算符总结

   //! x = ~y;   //两个Boolean类型不能进行这种运算!!!

   //! f(!x);    

  //! f(x && y);    

  //! f(x || y);   //两个char、byte、short、int、long类型不能进行这种运算!!!

 //! boolean b = (boolean)x;   //char类型不能造型为Boolean(其他比Boolean类型大的亦然)

    char c = (char)x;

    byte B = (byte)x;

    short s = (short)x;

    int i = (int)x;

    long l = (long)x;

    float f = (float)x;      //x为double类型可以进行的造型

 

 

    x = (char)(x * y);

    x = (char)(x / y);

    x = (char)(x % y);

    x = (char)(x + y);

    x = (char)(x - y);

    x= (char)~y;

    x = (char)(x & y);

    x  = (char)(x | y);

    x = (char)(x ^ y);

    x = (char)(x << 1);

    x = (char)(x >> 1);

    x = (char)(x >>> 1)

在 char,byte 和 short 中,我们可看到算术运算符的“转型”效果。对这 些类型的任何一个进行算术运算,都会获得一个 int 结果。必须将其明确“造型” 回原来的类型(缩小转换会造成信息的丢失),以便将值赋回那个类型。(以上为char为例)

 

它用到了 Math 库里的 static(静态)方法 random()。该方法的作用是产生 0 和 1 之间(包括0,但不包括 1)的一个 double 值