2.运算符
3023字约10分钟
2024-12-02
算术运算符
算术运算符是对数值类型的变量进行运算的,在Java程序中使用的非常多
算术运算符
//加法
int a = 1 + 1; // a = 2
//减法
int a = 1 - 1; // a = 0
//乘法
int a = 1 * 1; // a = 1
//除法
int a = 1 / 1; // a = 1
//取
int a = 1 % 1; // a = 0
//自增
int a = 1;
int b = a++; // b = 1,a = 2;右++,先赋值在自增
int b = ++a; // b = 3,a = 3;左,先自增在赋值
- -和+ +的原理是一样的
+、-、*就是加、减、乘,和 / 除的原理是一样的,就是加减乘除运算法则
关系运算符
// 相等
int a = 2;
int b = 2;
System.out.println(a == b); // a等于b
// 不相等
int a = 1;
int b = 2;
System.out.println(a != b); // a不等于b
// 大于
int a = 2;
int b = 1;
System.out.println(a > b); // a大于b
// 小于
int a = 1;
int b = 2;
System.out.println(a < b); // a小于b
// 大于等于
int a = 3;
int b = 3;
System.out.println(a >= b); // a大于等于b
// 小于等于
int a = 1;
int b = 2;
System.out.println(a <= b); // a小于等于b
// 字符串与字符串之间比较
String name = "hello";
System.out.println("world".equals(name)); // false
==
运算符
==
是一个比较运算符==
既可以判断基本类型(判断基本类型是判断两个基本类型是否相等),也可以判断引用类型(判断引用类型是判断两个引用类型的内存地址是否相等,也就是判断是不是同一个对象)public class judg { public static void main(String[] args) { // 每创建一个对象,不同对象的内存地址就会不一样,就如下面的两个A对象 // 即使都是A类,但是每个A类都创建了一个对象,所以每创建一个新的对象这内存地址就不一样 A a = new A(); A b = new A(); A c = b; A d = c; B a1 = new B(); A b1 = a1; // 因为a、b是相同的类型,但不是相同的对象,所以不相等,对象不相等,也就代表内存地址不相等 System.out.println(a == b); // False // 因为b和c都指向相同的一个对象,所以内存地址相等 System.out.println(c == d); // True System.out.println(b1 == a1); // True } } class A { } class B extends A { }
==
比较的方法,两个新对象比较则为假Integer integer = new Integer(1000); Integer integer1 = new Integer(1000); System.out.println(integer == integer1); // false
两个不同的类型无法进行比较
// 两个不相同的类型不能相互比较,否则会报错 System.out.println("hello" == new java.sql.Date());
在
==
中,只要是有基本数据类型的,那么该判断就是判断两个数值是否相等,而不是判断是不是同一个对象Integer i = 128; int num = 128; System.out.println(i == num); // true
instanceof
比较操作符
用于判断 对象的引用类型 是不是 某类型 或则 某类型的子类型
public class Demo01 {
public static void main(String[] args) {
A a = new A();
Object object = new Object();
// 类型的引用名 instanceof 类型名
// 判断object是A类吗或则是A类的子类吗
// 很明显不是,object是所有类的父类,所以object不是A类的子类,也不是A类
System.out.println(object instanceof A); // false
B b = new B();
// b是A的子类所以成立了
System.out.println(b instanceof A); // true
// b是B类型所以成立
System.out.println(b instanceof B); // true
// str是String类型的,而String又是Object类型的子类,所以成立
String str = "string";
System.out.println(str instanceof Object); // true
}
}
class A {
}
class B extends A {
}
逻辑运算符
常用的逻辑运算符(以下三个逻辑运算符是常用的)
下表列出了逻辑运算符的基本运算,假设布尔变量A为真,变量B为假
操作符 | 描述 | 例子 |
---|---|---|
&& | 称为 短路与 运算符。两个操作数中都为真,条件才为真 | (A && B)为假 |
| | | 称为 短路或 操作符。两个操作数中任何一个为真,条件为真 | (A | | B)为真 |
! | 称为 逻辑非 运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false | ! (A && B)为真 |
^ | 成为 逻辑异或 运算符。逻辑异或就是当a 和 b不同时,则结果为true,否则为false | true ^ false 为真 |
// && 短路与
int a = 0;
int b = 0;
// 两个条件为真时,整体才为真(true),只要有一个为假,则整体为假(false)
// 和逻辑与(&)的区别就是在短路与中的两个条件中,当第一个条件为假时,那么第二个条件就不会继续运行判断;而逻辑与不会
if (a == 0 && b == 0) {
System.out.println("hello");
}
// || 短路或
int a = 0;
int b = 1;
// 两个条件中有一个条件为真时,整体才为真(true),否则为假(false)
// 和逻辑或(|)的区别就是在短路或中的两个条件中,当第一个条件为真时,那么第二个条件就不会继续运行判断;而逻辑或不会
if (a == 1 || b == 1) {
System.out.println("hello");
}
// ! 逻辑非
int a = 0;
int b = 0;
// 逻辑非就是相反值,如果判断结果为真,则输出假;如果判断结果为假,则输出真
System.out.println(!(a == 0 && b == 0)); // 结果为 false
// 逻辑运算符
// 逻辑异或就是当a 和 b不同时,则结果为true,否则为false
// 使用规则:真假为真,真真为假,假假为假
boolean a = true;
boolean b = false;
System.out.println(a ^ b); // 结果为 true
赋值运算符
// 赋值运算符
int a = 2; // 将2赋值给a
三元运算符
int a = 10;
int b = 20;
// a大于b为真,则赋值第一个条件;如果a大于b为假,则赋值第二个条件
int max1 = a > b ? a : b;
System.out.println(max1); // 20
细节
// 三元运算符是一个整体,所以在三元运算符中赋值类型将最大的类型来赋值
// 1是int类型,2.0是double类型
// 该运算符为true,则赋值1,因为2.0是double类型,比int大,所以1会提升类型为1.0
// 这也是接收的数据类型为int会报错的原因
double a = true ? 1 : 2.0;
System.out.println(a); // 输出1.0
运算符的优先级
位运算
计算机在运算的时候为什么都是以补码的方式来运行的?是因为补码可以解决正数和负数的问题,它把正数和负数统一起来了
按位与
两个数都是1,结果才为1(1和1,结果才为1),否则为0(1和0,0和0,其结果都是0)
public class BitOperator {
public static void main(String[] args) {
// 按位与 &
// 按位与的运算方式,首先获得要计算数的补码,但是 补码 要通过 原码 推导成 反码 在推导成 补码
// 因为正数的原码、反码和补码都是一样的
// 又因为 2 和 3 都是int类型,而且int类型占用四个字节,每个字节占八位
// 其次在Java中所有数字都是有符号的(正负号,0表示正,1表示负)
// 所以 2 的原码为 00000000 00000000 00000000 00000010
// 2 的补码为 00000000 00000000 00000000 00000010
// 以此类推
// 3 的原码是 00000000 00000000 00000000 00000011
// 3 的补码是 00000000 00000000 00000000 00000011
// 最后我们的到 2 的补码和 3 的补码
// 按位与的运算方式是,两位全为1,结果才为1,否则为0
// 所以 2 和 3 的按位与的运算结果为
// 2 的补码: 00000000 00000000 00000000 00000010
// 3 的补码: 00000000 00000000 00000000 00000011
// 运算结果 : 00000000 00000000 00000000 00000010(这是运算过后的补码)
// 然后在判断运算结果是正还是负,判断方法:看最左边的数是0还是1,如果是0,则是正数,如果是1,则是负数
// 如果是正数,那么该补码转换为原码则是自己本身,没有变
// 如果是负数,则要先取反码,然后在取补码
// 最后在将转换后的原码转换为十进制
System.out.println(2 & 3); // 所以转换之后的结果就为2,如果补码那里最左边的数是1,则结果将变为-2
}
}
按位或
两位数中只要有1个1,其结果为1(1和0,1和1,其结果都为1),否则为0(0和0,结果为0)
public class BitOperator {
public static void main(String[] args) {
// 按位或 |
/**
* 2的原码: 00000000 00000000 00000000 00000010
* 2的补码: 00000000 00000000 00000000 00000010
* 3的原码: 00000000 00000000 00000000 00000011
* 3的补码: 00000000 00000000 00000000 00000011
* 2的补码与3的补码都知道了,运算2和3的按位或
* 2的补码: 00000000 00000000 00000000 00000010
* 3的补码: 00000000 00000000 00000000 00000011
* 按位或结果: 00000000 0000000 0000000 00000010 (按位或:两位有一个1,结果才为1,否则为0)
* */
System.out.println(2 | 3); // 所以结果为 2
}
}
按位异或
两位数中是一个0加一个1组合的(1和0,结果为1),结果为1,否则为0(1和1,0和0,其结果都为0)
public class BitOperator {
public static void main(String[] args) {
// 按位异或 ^
/**
* 2的原码: 00000000 00000000 00000000 00000010
* 2的补码: 00000000 00000000 00000000 00000010
* 3的原码: 00000000 00000000 00000000 00000011
* 3的补码: 00000000 00000000 00000000 00000011
* 2的补码与3的补码都知道了,运算2和3的按位或
* 2的补码: 00000000 00000000 00000000 00000010
* 3的补码: 00000000 00000000 00000000 00000011
* 按位异或结果: 00000000 0000000 0000000 00000001 (按位异或:一位为1,一位为0,结果才为1,否则为0)
* */
System.out.println(2 ^ 3); // 所以结果为 1
}
}
按位取反
1变0,0变1
public class BitOperator {
public static void main(String[] args) {
// 按位取反 ~
//例子1
/**
* 下面这个式子是求负二的按位取反
* 首先获得 -2 的原码: 10000000 00000000 00000000 00000010(因为是 -2 ,所以最开头的数字为1)
* 然后在求 -2 的反码: 11111111 11111111 11111111 11111101(原码最左边的符号位不变之外,其它位取反)
* -2 的补码: 11111111 11111111 11111111 11111110(在反码的基础上+1)
* 将-2的补码按位取反: 00000000 00000000 00000000 00000001(按位取反,就是1变0,0变1,此时这个就是运算后的补码)
* */
System.out.println(~ -2); //所以~ -2的按位取反的结果是 1
//例子2
/**
* 该式子也是求按位取反,但有些区别
* 首先获得 2 的原码: 00000000 00000000 00000000 00000010
* 然后在获得2的补码: 00000000 00000000 00000000 00000010(因为正数的原码、反码和补码都是一样的)
* 将2的补码按位取反: 11111111 11111111 11111111 11111101(按位取反,就是1变0,0变1,此时这个就是运算后的补码)
* 因为2的补码取反之后的结果为负数,所以要先求出反码,再求原码
* 负数的反码=补码减 1
* 所以2运算后的补码转换为反码的结果为:11111111 11111111 11111111 11111100
* 又因为负数的反码=原码最左边的符号位不变之外,其它位取反;又因为我们已经知道反码了,所以我们可以通过反码反推得到原码
* 所以反码转换为原码的结果为:100000000 00000000 00000000 00000011
* */
System.out.println(~ 2); // 所以~ 2的按位取反的结果为 -3
}
}
算术左右移
// 算术右移
/**
* 3的原码是: 00000011(这里直接简写了)
* 而3 >> 2的本质就相当于 3 / 2 / 2 = 0 (移动多少就除以多少个2)
* */
System.out.println(3 >> 2);
/**
* 1的原码是: 00000001(这里直接简写了)
* 而1 << 3的本质就相当于 1 * 2 * 2 * 2 = 8 (移动多少就乘以多少个2)
* */
System.out.println(1 << 3); // 结果为8 (8的原码: 00001000)