Java的整数运算

四则运算

Java的整数运算与C语言相同,遵循四则运算规则,可以使用任意嵌套的小括号。四则运算规则和初等数学一致。例如:

public class Main {
    public static void main(String[] args) {
        int i = (100 + 200) * (99 - 88);   // 3300
        int n = 7 * (5 + (i - 9));   // 23072
        System.out.println(i);
        System.out.println(n);
    }
}

整数的数值表示不但是精确的,而且整数运算永远是精确的。
即使是除法也是如此,两个整数相除只能得到结果的整数部分:

int x = 12345 / 67;   // 结果为 184

求余运算使用%:

int y = 12345 % 67;   // 12345÷67的余数为 17

特别注意:整数的除法对于除数为0时运行时将报错,但编译不会报错。

溢出

特别注意:整数由于存在范围限制,如果计算结果超出了范围,就会产生溢出,而溢出不会出错,却会得到一个奇怪的结果。

public class Main {
    public static void main(String[] args) {
        int x = 2147483640;
        int y = 15;
        int sum = x + y;
        System.out.println(sum);   //  运算结果 -2147483641
    }
}

对上述结果进行解释,需要把整数2147483640和15换成二进制做加法:

    0111 1111 1111 1111 1111 1111 1000
  + 0000 0000 0000 0000 0000 0000 1111
   ------------------------------------
    1000 0000 0000 0000 0000 0000 0111

由于运算结果最高位为1,因此,加法结果变成了一个负数。

要解决上面的问题,可以把 int 换成更大的数据类型,例如 long 类型,由于 long 可表示的整型范围更大,所以结果就不会溢出:

long x = 2147483640;
long y = 15;
long sum = x + y;
System.out.println(sum);   //  运算结果 2147483655

简写的运算符,即 +=,-=,*=,/=,它们的使用方法如下:

n += 100;   // 相当于 n = n + 100;
n -= 100;   // 相当于 n = n - 100;

自增 / 自减

Java还提供了 ++ 运算和 - - 运算,它们可以对一个整数进行加1和减1的操作:

public class Main {
    public static void main(String[] args) {
        int n = 3300;
        n++;   // 3301, 相当于 n = n + 1;
        n--;   // 3300, 相当于 n = n - 1;
        int y = 100 + (++n);   // 不要这么写
        System.out.println(y);
    }
}

注意 ++ 写在前面和后面计算结果是不同的,++n 表示先加1再引用 nn++ 表示先引用 n 再加1。不建议把 ++ 运算混入到常规运算中,容易自己把自己搞懵了。

移位运算

在计算机中,整数总是以二进制的形式表示。例如,int 类型的整数7使用4字节表示的二进制如下:

00000000 0000000 0000000 00000111

可以对整数进行移位运算。对整数7左移1位将得到整数14,左移两位将得到整数28:

int n = 7;       // 00000000 0000000 0000000 00000111
int a = n << 1;  // 00000000 0000000 0000000 00001110 <= 14
int b = n << 2;  // 00000000 0000000 0000000 00011100 <= 28
int c = n << 28; // 01110000 0000000 0000000 00000000 <= 1879048192
int d = n << 29; // 11100000 0000000 0000000 00000000 <= -536870912

左移29位时,由于最高位变成1,因此结果变成了负数。
类似的,对整数28进行右移,结果如下:

int n = 7;       // 00000000 0000000 0000000 00000111
int a = n >> 1;  // 00000000 0000000 0000000 00000011 <= 3
int b = n >> 2;  // 00000000 0000000 0000000 00000001 <= 1
int c = n >> 3;  // 00000000 0000000 0000000 00000000 <= 0

如果对一个负数进行右移,最高位的1不动,结果仍然是一个负数:

int n = -536870912;
int a = n >> 1;  // 11110000 0000000 0000000 00000000 <= -268435456
int b = n >> 2;  // 10111000 0000000 0000000 00000000 <= -134217728
int c = n >> 28; // 10000000 0000000 0000000 00000001 <= -2
int d = n >> 29; // 10000000 0000000 0000000 00000000 <= -1

还有一种带符号的右移运算,使用>>>,它的特点是符号位跟着动,因此,对一个负数进行>>>右移,它会变成正数,原因是最高位的1变成了0:

int n = -536870912;
int a = n >>> 1;  // 01110000 0000000 0000000 00000000 <= 1879048192
int b = n >>> 2;  // 00111000 0000000 0000000 00000000 <= 939524096
int c = n >>> 29; // 00000000 0000000 0000000 00000111 <= 7
int d = n >>> 31; // 00000000 0000000 0000000 00000001 <= 1

对byte和short类型进行移位时,会首先转换为int再进行位移。

仔细观察可发现,左移实际上就是不断地 ×2 ,右移实际上就是不断地 ÷2

位运算

位运算是按位进行与、或、非和异或的运算。

与运算 的规则是,全1为1,有0为0:

   n = 0 & 0; // 0
   n = 0 & 1; // 0
   n = 1 & 0; // 0
   n = 1 & 1; // 1

或运算 的规则是,有1为1,全0为0:

n = 0 | 0; // 0
n = 0 | 1; // 1
n = 1 | 0; // 1
n = 1 | 1; // 1

非运算 的规则是,0和1互换:

n = ~0; // 1
n = ~1; // 0

异或运算 的规则是,相异为1,相同为0:

n = 0 ^ 0; // 0
n = 0 ^ 1; // 1
n = 1 ^ 0; // 1
n = 1 ^ 1; // 0

对两个整数进行位运算,实际上就是按位对齐,然后依次对每一位进行运算。例如:

public class Main {
    public static void main(String[] args) {
        int i = 167776589; // 00001010 00000000 00010001 01001101
        int n = 167776512; // 00001010 00000000 00010001 00000000
        System.out.println(i & n); // 167776512
    }
}

上述按位与运算实际上可以看作两个整数表示的 IP 地址 10.0.17.7710.0.17.0 ,通过与运算,可以快速判断一个 IP 是否在给定的网段内。

运算优先级

在Java的计算表达式中,运算优先级从高到低依次是:
Java的整数运算_第1张图片
记不住也没关系,只需要加括号就可以保证运算的优先级正确。

类型自动提升与强制转型

在运算过程中,如果参与运算的两个数类型不一致,那么计算结果为较大类型的整型。例如,shortint 计算,结果总是 int,原因是 short 首先自动被转型为 int

public class Main {
    public static void main(String[] args) {
        short s = 1234;
        int i = 123456;
        int x = s + i;    // s自动转型为int
        short y = s + i;  // 编译错误!
    }
}

也可以将结果强制转型,即将大范围的整数转型为小范围的整数。强制转型使用 (类型) ,例如,将 int 强制转型为 short

int i = 12345;
short s = (short) i;    // 12345

要注意,超出范围的强制转型会得到错误的结果,原因是转型时,int的两个高位字节直接被扔掉,仅保留了低位的两个字节:

public class Main {
    public static void main(String[] args) {
        int i1 = 1234567;
        short s1 = (short) i1;    // -10617
        System.out.println(s1);
        int i2 = 12345678;
        short s2 = (short) i2;    // 24910
        System.out.println(s2);
    }
}

因此,强制转型的结果很可能是错的。

你可能感兴趣的:(Java程序设计)