JavaSE笔记——运算符


前言

本文是学习Java编程思想记录的笔记,主要内容介绍在 Java 中运算符相关知识。

运算符接受一个或多个参数并生成新值。这个参数与普通方法调用的形式不同,但效果是相同的。加法 +、减法 -、乘法 *、除法 / 以及赋值 = 在任何编程语言中的工作方式都是类似的。所有运算符都能根据自己的运算对象生成一个值。除此以外,一些运算符可改变运算对象的值,这叫作 “副作用”(Side Effect)。运算符最常见的用途就是修改自己的运算对象,从而产生副作用。但要注意生成的值亦可由没有副作用的运算符生成。几乎所有运算符都只能操作基本类型。唯一的例外是 =、== 和 !=,它们能操作所有对象(这也是令人混淆的一个地方)。除此以外,String 类支持 + 和 +=。


一、优先级

运算符的优先级决定了存在多个运算符时一个表达式各部分的运算顺序。Java 对运算顺序作出了特别的规定。其中,最简单的规则就是乘法和除法在加法和减法之前完成。程序员经常都会忘记其他优先级规则,所以应该用括号明确规定运算顺序。代码示例:

public class Examlple {
    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);
        System.out.println(b);
    }
}

在这里插入图片描述

二、赋值

运算符的赋值是由符号 = 完成的。它代表着获取 = 右边的值并赋给左边的变量。右边可以是任何常量、变量或者可产生一个返回值的表达式。但左边必须是一个明确的、已命名的变量。也就是说,必须要有一个物理的空间来存放右边的值。基本类型的赋值都是直接的,而对象赋予的只是其内存的引用。对一个对象进行操作时,我们实际上操作的是它的引用。所以我们将右边的对象赋予给左边时,赋予的只是该对象的引用。代码示例:

public class Assignment {

    private int level;

    public static void main(String[] args) {
        Assignment a1 = new Assignment();
        Assignment a2 = new Assignment();
        Assignment temp;
        a1.level = 6;
        a2.level = 7;
        System.out.println("a1.level:" + a1.level + ",a2.level:" + a2.level);
        // 赋值交换
        temp = a1;
        a1 = a2;
        a2 = a1;
        System.out.println("a1.level:" + a1.level + ",a2.level:" + a2.level);
    }

}

在这里插入图片描述

三、算术运算符

Java 的基本算术运算符与其他大多编程语言是相同的。其中包括加号 +、减号 -、除号 /、乘号 * 以及取余 %。整数除法会直接砍掉小数,而不是进位。求余过程中:余数的正负号取决于被除数,被除数为正则为正,被除数为负则为负。求模Math.floorMod()过程中:模的正负号取决于除数,除数为正则为正,除数为负则为负。

public class Operator {
    public static void main(String[] args) {
        int i, j, k;
        j = 7;
        System.out.println("j : " + j);
        k = 8;
        System.out.println("k : " + k);
        i = j + k;
        System.out.println("j + k : " + i);
        i = j - k;
        System.out.println("j - k : " + i);
        i = k / j;
        System.out.println("k / j : " + i);
        i = k * j;
        System.out.println("k * j : " + i);
        i = k % j;
        System.out.println("k % j : " + i);
        j %= k;
        System.out.println("j %= k : " + j);
        // 浮点运算测试、double一样适用
        float u, v, w;
        v = 0.7f;
        System.out.println("v : " + v);
        w = 0.8f;
        System.out.println("w : " + w);
        u = v + w;
        System.out.println("v + w : " + u);
        u = v - w;
        System.out.println("v - w : " + u);
        u = v * w;
        System.out.println("v * w : " + u);
        u = v / w;
        System.out.println("v / w : " + u);
        u += v;
        System.out.println("u += v : " + u);
        u -= v;
        System.out.println("u -= v : " + u);
        u *= v;
        System.out.println("u *= v : " + u);
        u /= v;
        System.out.println("u /= v : " + u);
        u %= v;
        System.out.println("u %= v : " + u);

    }
}

在这里插入图片描述

float和double进行算术运算时,会造成精度损失,如需要请用BigDecimal

一元加减运算符

一元加 + 减 - 运算符的操作和二元是相同的。编译器可自动识别使用何种方式解析运算,如下代码示例

j = j + (-k);

四、递增和递减

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

public class AutoInc {
    public static void main(String[] args) {
        int i = 1;
        System.out.println("i: " + i);
        // 前递增
        System.out.println("++i: " + ++i);
        // 后递增
        System.out.println("i++: " + i++);
        System.out.println("i: " + i);

        // 前递减
        System.out.println("--i: " + --i);
        // 后递减
        System.out.println("i--: " + i--);
        System.out.println("i: " + i);
    }
}

在这里插入图片描述

五、关系运算符

关系运算符会通过产生一个布尔(boolean)结果来表示操作数之间的关系。如果关系为真,则结果为 true,如果关系为假,则结果为 false。关系运算符包括小于 <,大于 >,小于或等于 <=,大于或等于 >=,等于 == 和不等于 !=。== 和 != 可用于所有基本类型,但其他运算符不能用于基本类型 boolean,因为布尔值只能表示 true 或 false,所以比较它们之间的 “大于” 或 “小于” 没有意义。

        int a = 1;
        int b = 1;
        System.out.println(a == b);

对象相等判断

== 和 != 比较的是对象引用,equals() 方法比较两个对象的内容相同。

Integer x = 128;
Integer y = 128;
System.out.println(x == y);
System.out.println(x.equals(y));

在这里插入图片描述
对于int类型的数值 x,当 -128 <= x <= 127时候,引用的是cache数组中的同一个数组元素,所以此时 == 比较两个自动装箱的包装类对象是 true.

六、逻辑运算符

每个逻辑运算符 && (AND)、||(OR)和 !(非)根据参数的逻辑关系生成布尔值 true 或 false。代码示例:

public class Bool {
    public static void main(String[] args) {
        int i = 1;
        int j = 2;
        System.out.println(i > 0 && j < 0);
        System.out.println(i > 0 || j < 0);
        System.out.println(!(i > 0));
    }
}

在这里插入图片描述

逻辑运算符支持一种称为 “短路”(short-circuiting)的现象。整个表达式会在运算到可以明确结果时就停止并返回结果这意味着该逻辑表达式的后半部分不会被执行到。

七、字面值常量

当我们向程序中插入一个字面值常量(Literal)时,编译器会确切地识别它的类型。当类型不明确时,必须辅以字面值常量关联来帮助编译器识别。代码示例:

public class Literals {
    public static void main(String[] args) {
        // 16 进制 (小写)
        int i1 = 0x2f;
        System.out.println("i1: " + Integer.toBinaryString(i1));
        // 16 进制 (大写)
        int i2 = 0X2F;
        System.out.println("i2: " + Integer.toBinaryString(i2));
        // 8 进制 (前导 0)
        int i3 = 0177;
        System.out.println("i3: " + Integer.toBinaryString(i3));
        // 最大 char 型 16 进制值
        char c = 0xffff;
        System.out.println("c: " + Integer.toBinaryString(c));
        // 最大 byte 型 16 进制值;
        byte b = 0x7f;
        System.out.println("b: " + Integer.toBinaryString(b));
        // 最大 short 型 16 进制值
        short s = 0x7fff;
        System.out.println("s: " + Integer.toBinaryString(s));
        // long 型后缀
        long n1 = 200L;
        // long 型后缀 (容易与数值 1 混淆)
        long n2 = 200l;
        long n3 = 200;

        // Java 7 二进制字面值常量:
        byte blb = (byte) 0b00110101;
        System.out.println("blb: " + Integer.toBinaryString(blb));
        short bls = (short) 0B0010111110101111;
        System.out.println("bls: " + Integer.toBinaryString(bls));
        int bli = 0b00101111101011111010111110101111;
        System.out.println("bli: " + Integer.toBinaryString(bli));
        long bll = 0b00101111101011111010111110101111;
        System.out.println("bll: " + Long.toBinaryString(bll));

        float f1 = 1;
        // float 型后缀
        float f2 = 1F;
        // float 型后缀
        float f3 = 1f;
        // double 型后缀
        double d1 = 1d;
        // double 型后缀
        double d2 = 1D;
        // (long 型的字面值同样适用于十六进制和 8 进制 )

    }
}

在这里插入图片描述

使用整型数值类型时,显示其二进制形式会很有用。在 Long 型和 Integer 型中这很容易实现,调用其静态的 toBinaryString() 方法即可。但是请注意,若将较小的类型传递给 Integer.tobinarystring() 时,类型将自动转换为 int。

下划线

Java 7 中有一个深思熟虑的补充:我们可以在数字字面量中包含下划线 _,以使结果更清晰。这对于大数值的分组特别有用。代码示例:

public class Underscores {
    public static void main(String[] args) {
        double d = 341_435_936.445_667;
        System.out.println(d);
        int bin = 0b0010_1111_1010_1111_1010_1111_1010_1111;
        System.out.println(Integer.toBinaryString(bin));
        System.out.println(bin); // [1]
        long hex = 0x7f_e9_b7_aa;
        System.out.println(hex);
    }
}

在这里插入图片描述
下面是合理使用的规则:

  1. 仅限单 _,不能多条相连。
  2. 数值开头和结尾不允许出现 _。
  3. F、D 和 L 的前后禁止出现 _。
  4. 二进制前导 b 和十六进制 x 前后禁止出现 _。

指数计数法

指数采用一种不直观的记号方法( "e" 表示 10 的几次幂):

public class Exponents {
    public static void main(String[] args) {
        // 大写 E 和小写 e 的效果相同:
        float expFloat = 1.39E-43f;
        System.out.println(expFloat);
        // 'd' 是可选的
        double expDouble = 47e47d;
        // 自动转换为 double
        double expDouble2 = 47e47;
        System.out.println(expDouble);
    }
}

在这里插入图片描述
在 Java 中类似 “1.39e-43f” 这样的表达式时,它真正的含义是 “1.39 × 10 的 -43 次方”。

八、进制介绍

对于整数,有四种表示方式:

  1. 二进制:0,1,满2进1,以0b或0B开头
  2. 十进制:0-9,满10进1
  3. 八进制:0-7,满8进1,以数字0开头表示
  4. 十六进制:0-9及A(10)-F(15),满16进1,以0X或0x开头表示,此处的A-F不区分大小写

十进制转换为其他进制

转换原理:除以需要转换的进制数字,反向取余数,直到商为0终止。二进制例子如下,其他进制类似
在这里插入图片描述

其他进制转换为十进制

公式:a*xy-1 + a*xy-2 + … + a*x1 + a*x0

  • a:代表其他进制对应位置上面的数字(比如二进制1001,分别就代表1,0,0,1)
  • x:代表其他进制数字(比如二进制进制,x就为2)
  • y:代表其他进制有多少位(比如二进制1001,就为4)

二进制1001转为十进制如下:
1×23 + 0×22 + 0×21 + 1×20 = 9

二进制转换成八进制数、十六进制数

  1. 二进制转换成八进制,原理:“三合一” 取二进制数中的三位(转为十进制)合为八进制数的一位
  2. 二进制转换成十六进制,原理:“四合一” 取二进制数中的四位(转为十进制)合为十六进制数的一位

转八进制:100101 → 45
转为十六进制:00100101 → 25

八进制、十六进制转换成二进制

  1. 八进制数转换成二进制原理:八进制数的一位是二进制数的三位
  2. 十六进制数转换成二进制原理:十六进制数的一位是二进制数的四位

转换过程就是上面的相反过程

八进制与十六进制之间的转换

这两者之间的转换可以借助十进制或者二进制完成,可以先将八进制转换成十进制或二进制,再转换成十六进制。通过间接转换来实现。

九、位运算符

位运算符允许我们操作一个整型数字中的单个二进制位。位运算符会对两个整数对应的位执行布尔代数,从而产生结果。

Java中支持的位运算

  1. 位与(&):二元运算符,两个为1时结果为1,否则为0
  2. 位或(|):二元运算符,两个其中有一个为1时结果就为1,否则为0
  3. 位异或(^):二元运算符,两个数同时为1或0时结果为1,否则为0
  4. 位取非(~):一元运算符,取反操作
  5. 左移(<<):一元运算符,按位左移一定的位置。符号位不变,高位溢出截断,低位补零。
  6. 右移(>>):一元运算符,按位右移一定的位置。符号位不变,低位溢出截断,高位用符号位填充。
  7. 无符号右移(>>>):一元运算符,符号位(即最高位)保留,其它位置向右移动,高位补零,低位溢出。

运算规则

Java数值运算过程中都是先将十进制转换为二进制然后再进行运算,再把二进制数据转换为十进制展现给用户。二进制运算规则如下:
对于有符号的而言:

  • 最高位为符号位,0表示正数,1表示负数
  • 正数的原码,反码和补码都一样,三码合一
  • 负数的反码:符号位保持不限,其他位取反
  • 负数的补码:补码 + 1
  • 0的反码和补码都是0
  • 计算机的运算的时候,都是将原码转成补码进行运算的

下面以 -1 为例子展示原码、反码和补码的转换关系:
在这里插入图片描述

运算流程

以 4 & -5 = 0为例子,其他运算类似:

  1. 因为4为正数,所以原码和补码相同,即4的补码为:00000000 0000000 00000000 00000100
  2. 因为-5为负数,所以需要进行原码 >>> 反码 >>> 补码的转换
    原码:10000000 00000000 00000000 00000101
    反码:11111111 11111111 11111111 11111010
    补码:11111111 11111111 11111111 11111011
  3. 将4和-5的补码进行 & 运算,得到结果:00000000 00000000 00000000 00000000。所以结果为0

十、三元运算符

三元运算符,也称为条件运算符。这种运算符比较罕见,因为它有三个运算对象。但它确实属于运算符的一种,因为它最终也会生成一个值。表达式格式:

表达式? 值 1 : 值 2
public class TernaryIfElse {
    public static void main(String[] args) {
        System.out.println(2 < 10 ? 100 : 10);
    }
}

在这里插入图片描述

十一、类型转换

“类型转换”(Casting)的作用是 “与一个模型匹配”。在适当的时候,Java 会将一种数据类型自动转换成另一种。例如,假设我们为 float 变量赋值一个整数值,计算机会将 int 自动转换成 float。我们可以在程序未自动转换时显式、强制地使此类型发生转换。
要执行强制转换,需要将所需的数据类型放在任何值左侧的括号内,例子如下:

int i = 200;
long lng = (long)i

因为编译器会在必要时自动提升 int 型数据为 long 型,上例这种做法是多余的。对于“向上转换(Widening conversion),不必进行显式的类型转换,因为较大类型的数据肯定能容纳较小类型的数据,不会造成任何信息的丢失。将数据类型进行“向下转换”(Narrowing Conversion)的操作(将容量较大的数据类型转换成容量较小的类型),可能会发生信息丢失的危险,此时,编译器会强迫我们进行转型。


总结

以上就是本文要讲的内容,本文仅仅是作者自己的学习笔记,其中记录关于java中的运算相关知识。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值