Java解惑(1)-- 表达式谜题

Java解惑(1)-- 表达式谜题

1 判断奇数

static boolean isOdd(int i) {
    //错误解法,如果是负数则不是1
    //return i % 2 == 1;
    return i % 2 != 0;
}

2 浮点数的精确表示

//1 使用大整数  
//2 使用BigDecimal,并使用基于String的构造函数
static void money() {
    System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10")));
}

3 长整除

static void longDivision() {
    //乘数必须有个long类型,否则结果是用int计算,再转成了long,可能溢出
    long a = 24L * 60 * 60 * 1000 * 1000;
    long b = 24L * 60 * 60 * 1000;
    System.out.println(a);
    System.out.println(b);
    System.out.println(a / b);
}

4 L与l

//初级问题,注意l与1的区别,long字面值应该只使用L
static void elementary() {
    System.out.println(12345 + 5432l);
}

5 十六进制(略)

6 多重类型转化

static void multicast() {
    System.out.println(Integer.SIZE);
    System.out.println(Character.SIZE);
    System.out.println(Byte.SIZE);
    System.out.println("-----");
    System.out.println((byte)-1);               //0xff
    System.out.println(0xff);
    System.out.println((char) (byte) -1);       //0xffff 有符号扩展
    System.out.println(0xffff);
    System.out.println((int) (char) (byte) -1); //0x0000ffff char类型执行无符号扩展
    System.out.println(0x0000ffff);
}

7 变量交换

C语言中有一种利用异或操作符的性质(x ^ y ^ x) == y实现变量交换的办法,而无需使用中间变量

x = x ^ y;
y = y ^ x;
x = y ^ x;

C语言中,计算表达式x^=expr时,会先计算expr的值再提取x的值。但是在Java中是不行的,以下代码无法实现x、y的变量交换

static void cleverSwap() {
    int x = 1894;   //0x7c0
    int y = 2001;   //0x7d1
    x ^= y ^= x ^= y;
    System.out.println(x);      //x=0
    System.out.println(y);      //y=1894
}

Java中操作符的操作数是从左向右的求值的,对表达式x^=expr求值时,x的值在计算expr之前就被提取了。以上代码中的x ^= y ^= x ^= y;,x值提取了两次,但是两次都发生在赋值操作之前。以上代码等价于

int tmp1 = x; //tmp1表示x的初始值
int tmp2 = y; //tmp2表示y的初始值
int tmp3 = x ^ y;   //计算x ^ y,记为tmp1^tmp2
x = tmp3;   //最右边赋值,x = tmp1^tmp2
y = tmp2 ^ tmp3;    //中间赋值,y = tmp2 ^ tmp1 ^ tmp2,即 y = tmp1
x = tmp1 ^ y;   //最左边赋值,x = tmp1 ^ tmp1,即 x = 0;

建议做法是,不要在单个表达式中对相同变量赋值两次

8 条件表达式

确定条件表达式结果的类型:

  1. 如果第二个和第三个操作数具有相同的类型,那么它就是条件表达式的类型。
  2. 如果一个操作数的类型是T,T表示byte、short或char,而另一个操作数是一个int类型的常量表达式,它的值是可以用类型T表示的,那么条件表达式的类型就是T。
  3. 否则,将对操作数类型运用二进制数字提升,而条件表达式的类型就是第二个和第三个操作数被提升之后的类型。

    static void dosEquis() {
        char x = 'X';
        int i = 0;
        System.out.println(true ? x : 0);       //输出X,运用规则2
        System.out.println(false ? i : x);      //输出88,运用规则3,x被提升为int,即88
    }

建议做法是,条件表达式的第二和第三操作数使用相同的类型

9 复合赋值(1)

x+=i并不总是等价于x = x+i
复合赋值表达式自动地将它们所执行的计算的结果转型为其左侧变量的类型

short x = 0;
int a = 123456;
x += a;                 //包含了隐式类型转换,但编译器不会提示
System.out.println(x);  //int 123456被隐式转换为了short -7646
x = x + a;              //如果不使用复合赋值,编译器会提示incompatible types

建议:在使用复合赋值表达式时,要注意可能发生的隐式类型转换

10 复合赋值(2)(Java8不适用)

x+=i并不总是等价于x = x+i
复合赋值操作符要求左右操作数是基本类型或其对应的装箱类型。但是对于+=,如果左侧操作数是String,右侧可以是任何类型,此时+=执行字符串拼接操作。
而简单赋值操作符中,左操作数可以是任何类型。

Object x = "Buy ";
String y = "Effective Java";
x += y;         //非法的
System.out.println(x);
x = x + y;      //合法的

注意: 以上是《Java解惑》一书的内容,书中使用的Java版本为Java5,在我使用的Java8中应该已经修复这个问题,即上文中的x+=y是合法的

posted @ 2020-02-09 18:35  filozofio  阅读(196)  评论(0编辑  收藏  举报