目录
运算符:
Java中的算术运算符:
++ 和 -- 的注意事项总结(以及举例):
Java中的赋值运算符:
Java中的扩展赋值运算符:
扩展赋值运算符注意事项:
Java中的关系运算符:
Java中的instanceof关系运算符:
Java中的逻辑运算符:
逻辑运算符注意事项:
Java中的三元运算符(又称三目运算符,条件运算符):
三元运算符注意事项:
Java中的位运算符(了解,实际开发中极少使用位运算符来开发程序。):
位运算符注意事项:
Java中的扩展赋值位运算符(了解,实际开发中极少使用扩展赋值位运算符来开发程序。):
扩展赋值位运算符注意事项:
Java中的其他符号:
运算符的优先级:
运算符优先级注意事项:
自动类型转换和强制类型转换:
基本类型中的自动类型转换:
引用类型中的自动类型转换:
基本类型中的强制类型转换:
引用类型中的强制类型转换:
运算符:
运算符用于执行程序代码运算,是针对一个以上操作数来进行运算的符号。
Java中的算术运算符:
++ 和 -- 的注意事项总结(以及举例):
- ++ 单独使用的时候,无论 ++ 是放在变量前面还是变量后面,都是变量里存的数值加1操作。
- -- 单独使用的时候,无论 ++ 是放在变量前面还是变量后面,都是变量里存的数值减1操作。
- 如果 ++ , -- 参与到运算中去的话,对运算结果会产生影响。它们的规则是看 ++ 、-- 是在后还是在前:
- 如果 ++ 在后,先运算,”后“!加1,如果 ++ 在前,先加1,后运算。
- 如果 -- 在后,先运算,”后“ 减1,如果 -- 在前,先减1,后运算。
- 比如 byte i = 5; i++ , ++i;等同于 i = (byte) (i + 1);-- 也是一样的,如果不是int类型的数字(一般都是指byte,short,char这三个类型),它底层会先自动转换为int类型,运算完成后再强转为目标类型!如果数据溢出了怎么办?(关于自动类型转换和强制类型转换请看文末最后一个标题的详细细节!)
- 如果是把自增后的值赋值给一个新的变量,这时候就跟它 ++,-- 前后顺序有关系的!因为设计到赋值运算!比如: int a = 9; int b = a++;(注意:这时候的a并没有自增,是先进行赋值运算,后面没有使用了就没有加1了!所以这里的b也是9),如果是 int d = 11;int c = ++a;那么这个时候的c就等于12!,如果是 ++ 在后这个操作,最后一个的++是不会执行的!因为没有再使用! 比如 int s = 2; 如果是 int q = s(2)++(3) + s(3=5) + s(3 = 8)++;(这里的q的结果是 8,最后那个++没有执行了,直接赋值运算就结束了!后面没有再使用了),如果是 int q = s(2)++(3) + s(3=5) + ++s(4 = 9);具体细节请看我的举例!
- 一般 ++ -- 在后 都习惯使用在for,while,do{}while 循环结构中较多!或者只是纯粹的打印 ++ --后的值,且 ++ -- 在前在后都无所谓!这个才叫所谓的单独使用!
++ 参与到运算中
1:如图所示:
2:还有个更复杂的(说明:打<>的里面数字是不容易被看出来的操作,难就是难到了这个点上面)!(打<>后是后加1的操作!)如图所示:
-- 参与到运算中
如图所示:(说明:打<>的里面数字是不容易被看出来的操作,难就是难到了这个点上面)!(打<>后是后加1的操作!)
++,和 -- 都参与到运算中(变态的面试题就有这种题,我就遇到过类似于我写的这种,打{}圈起来就是坑,还有负数,就不能当个人?……)(打<>后是后加1的操作!)
Java中的赋值运算符:
注:实际上 赋值操作就是 字面常量与变量的运算操作!
Java中的扩展赋值运算符:
扩展赋值运算符注意事项:
说明: eao = extend assignment operator(扩展赋值运算符)
- 数据类型 变量 eao 数值or字符or变量or算术表达式;的结果等同于 数值类型 变量 = 算术表达式。比如: int a = 123; a += 3 + 5;等同于 int a = 123 + 3 + 5;
- 扩展赋值运算符的优点:它可以实现隐式强转,即整数类型,小数类型,字符类型在 参与运算的时候 当接收结果的数据类型是比默认的数据类型的数据范围还小的数据类型的时候的就会实现自动隐式强转。 比如 int a = 3;byte b = 7;b += a; 等同于 b = (byte) (b + a); 如图所示:
-
扩展运算符实现的自动强转只对基本类型,即整数类型,浮点数类型,字符类型在 参与运算的时候 当接收结果的数据类型是比默认的数据类型的数据范围还小的数据类型的时候有效(但是不包括boolean类型,boolean类型不能参与运算),不对引用类型有效!包括了基本类型的包装类型!
-
根据上图,一句话概括就是如果接收的数据类型数据范围是比默认的数据类型小的,但是它是它本身的基本数据类型的包装类型那么扩展运算符就不会具有隐式强转的功能了。编译都不会通过!扩展运算符的隐式强转只对基本类型才有效!(关于自动类型转换和强制类型转换请看文末最后一个标题的详细细节!)
基本数据类型从小到大(按取值范围)顺序:
如果对char类型还想了解更多可以看我的另外一篇博文,里面详细的记载了一些关于char的细节!:Java 入门之6:Java中的char类型是怎么存储的以及常见的编码字符集_flagyili的博客-CSDN博客
Java中的关系运算符:
Java中的instanceof关系运算符:
Java中的逻辑运算符:
逻辑运算符注意事项:
- && 和 & ,|| 和 | 的区别;
- && 相对于 & 来说效率较为高一些,&& 运算符如果第一个表达式的结果为false,那么后面的表达式的结果就不用再计算了,最终结果一定为false,如果第一个表达式的结果为true,那么后面的表达式的结果会从左到右依次计算,如果其中有表达式的结果为false,那么最终结果就为false,如果全部表达式的结果都为true,那么最终结果就为true。
- 而 & 运算符是不管第一个表达式的结果是false,还是是true,它会把每个表达式的结果都计算完成之后再计算最终的结果,如果其中有一个表达式为fasle,那么最终结果就是false,如果每个表达式的结果都为true,那么最终结果就为true! && 在实际开发中使用较多!
- || 相对于 | 来说效率较为高一些,|| 运算符如果第一个表达是的结果为true,那么后面的表达式的结果就不用再计算了,最终结果一定为true,如果第一个表达式的结果为false,那么后面的表达式的结果会从左到右依次计算,如果其中有表达式的结果为true,那么最终结果就为true,如果全部表达式的结果都为false,那么最终结果就为false。
- ·而 | 运算符是不管第一个表达式的结果是 true,还是false,它会把每个表达式的结果都计算完成之后再计算最终的记过,如果其中有一个表达式为true,那么最终结果就是true,如果每个表达式的结果都为false,那么最终结果就为false!,|| 在实际开发中使用较多!
Java中的三元运算符(又称三目运算符,条件运算符):
三元运算符注意事项:
- 三元运算符 尽量避免使用“特别复杂”的 嵌套三元运算符,代码可读性差。比如把:写成:
Java中的位运算符(了解,实际开发中极少使用位运算符来开发程序。):
位运算符注意事项:
- &、|、^ 位运算符与 &、|、^ 逻辑运算符的区别就是,逻辑运算符连接的是关系表达式,连接的操作数是boolean类型的true或者false,而位运算符连接的具体的整数数值,不能连接浮点数。
- 单目运算符包括了 ~ 、 ! 、 ++ 、 -- ;
- 一般在Java的源码中 位运算符 使用得比较多,比如 集合,Math类等……,实际开发基本很少使用位运算符!
- 下面是几个位运算符的举例:
- 左移运算符,比如 4 << 2;结果是 16;计算过程如下。 ,其实就相当于 ;
- 有符号右移运算符,比如正数的 6 >> 2; 结果是 1;计算过程如下。,其实就相当于 ,又比如负数的 -6 >> 2;结果是-2;,-6 >> 2其实就相当于 取负数的绝对值6,如果这个绝对值是在2的2次方 和 2的3次方之间(不包括2的3次方的那个数)的数的时候,那么就是 绝对值 除以 次方幂的结果 +1 再把这个数变成负数即可。即 6 除以 4 = 1 , 1 + 1 =2,-6 >> 2 = -2;如果是2的3次方则是, -8 >> 2 ,就是 8 除以 4 = 2,-8 >> 2 = -2, 其他的比如,-9 >> 2 = -3, -7 >> 2 = -2,比如2的4次方16: -16 >> 4 = -1;……。
- 无符号右移运算符:比如 -6 >>> 2,结果是1073741822,计算过程如下:,其实就相当于 取负数的绝对值6,如果这个绝对值是在2的2次方 和 2的3次方之间(不包括2的3次方的那个数)的数的时候,那么就是 绝对值 除以 次方幂的结果 +1 再把这个数变成负数即可。即 6 除以 4 = 1 , 1 + 1 =2,-6 >> 2 = -2;拿到 -2 的绝对值2了之后,则用 当前整数的数据类型的字长次幂减去补齐的位数的结果 再减绝对值,Java默认为int,即 ,-8 >>> 2 和 -6 >>> 2 的结果是相同的,又比如 -9 >>> 3 ,按照上面的规律拿到绝对值则是,9 除以 2的3次方 8 = 1,1+1 =2 ,即-9 >> 3 =-2。绝对值为2,-9 >>> 3 相当于 。再比如特殊的 -9 >>> 1 ,按照上面的规律拿到绝对值则是。9 除以 2 的1次方 2 = 4,(商4余1)所以用绝对值 4 + 余数 1,则是 5,-9 >>> 1 相当于,,-9 >>> 1 和 -10 >>> 1的结果是一样的, -13 >>> 1 和 -14 >>> 1 的结果是一样的。相当于 。
- 注意事项:只有正数的有符号右移和无符号右移是相同的,负数的则大相庭径,完全不一样!
- & 运算符(基本不会使用):比如 10 & 3 = 2,计算过程是:
- 注: 任何整数(正负整数) & 2的n次幂都等于 0 或 2的n次幂本身, 若是结果是 2的n次幂本身, 那被&整数二进制位 必然 2的n次幂的高位 同位的值 必然都为 1 !!!, 若是结果是0,那被&整数的二进制位 必然和 2的 n次幂的高位不同 !!
- | 运算符(基本不会使用):比如 16 | 7 = 23,计算过程是: ,注:任何偶数 | 1,都等同于 这个数 + 1(大于它的最小奇数);任何奇数 | 1,都等同于这个数 * 1. 任何数 | 0 ,都等于这个数本身。
- ^ 运算符(基本不会使用): 比如 13 ^ 9 = 4,计算过程是:,
- 说明:如果一个数值被另一个数值异或两次,那么其值不变,比如: 6 ^ 7 ^ 7 = 6;
- 异或运算可以记成为,二进制的无进位相加。它们的结果就是忽略 二进码的 进位的结果。任何数异或本身都为0。
- 任何奇数 ^ 1,都等同于 这个 数 - 1(小于它的最大偶数)。任何偶数 ^ 1,都等同于这个数 + 1(大于它的最小奇数)。任何数 ^ 0 ,都等于它本身。
- ~ 运算符(基本不会使用):比如 ~18 = -19,计算过程是:,其实就相当于 操作数+1 ,然后再加上 负号就对了,比如 ~20 = -21;
- 关于原反补码的细节说明可以参考我的另一篇文章。计算机中的原码,反码,补码的理解总结_flagyili的博客-CSDN博客
Java中的扩展赋值位运算符(了解,实际开发中极少使用扩展赋值位运算符来开发程序。):
扩展赋值位运算符注意事项:
- 扩展赋值位运算符使用场景特别的少!它和扩展赋值运算符 以及 ++ , -- 一样底层都是已经自动实现了强转的功能。
- 比如: byte b = 3; b <<= 2; 等价于 b = (byte) b << 2; ,底层会先把 3 自动提升 为 int 类型,然后再进行左移两位,然后再强转为byte类型赋值给b;如果数据溢出了怎么办?(关于自动类型转换和强制类型转换请看文末最后一个标题的详细细节!)
- 其实就相当于把两个操作数位运算操作后再进行赋值,如果声明的那个操作数的类型比Java的默认整数类型int,小的话,则会自动提升为 int类型在运算后,在强转类型并赋值为声明的那个操作数的变量。如果声明的那个操作数的类型是long类型,比Java的默认整数类型int,大的话,则直接按照long类型运算并赋值即可!。
Java中的其他符号:
注: Java中的 ... 符号是可变参数的声明格式。int... i 或者 int ...i ,可变参数的本质就是一个可变长的数组。
运算符的优先级:
运算符优先级注意事项:
- 不用刻意去运算符优先级关系
- 它们大概的顺序就是: 括号运算符 () > 单目运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 > 三元运算符 > 赋值运算符 > 扩展赋值运算符
- 实际开发中不会写特别的复杂的表达式,如果要优先算那个表达式,直接使用 () 括起来。 () 的优先级最高,先算()里面的表达式,再算外面的!
- 说明: 三元运算符的 综合性 是 由左向右!!!!! 画图时不小心写错了.
自动类型转换和强制类型转换:
基本类型中的自动类型转换:
就是小的类型直接转换为大的类型,隐式的就自动转换了,比如:,自动类型转换的格式基本类型,则是由小转大,(boolean类型不能自动转换为 数值类型!),如果在运算中,是byte 和 short 和 char 包括int 进行运算时会首先把操作数自动转换为 int类型再进行运算,如果操作数都为byte或者是short或者是char进行运算时也会自动转换为int类型在进行运算!,如果是float和double类型的数值在一起运算,会首先把操作数自动转换为double进行运算。如果操作数都是float类型的,则直接按照float类型进行运算,浮点数就不自动转换为double类型了。如果在运算中其中有任何一个操作数的类型比int还大,则自动转换为最大的类型进行运算。!
引用类型中的自动类型转换:
Java中面向对象的特性之 ——> 多态 可以理解为引用类型自动转换,即父类引用子类实例,比如,注意:此时的实例能使用的方法只能是父类和子类共有的实例方法,如果子类重写了父类的方法,则优先使用父类重写后的那个方法!而子类自己独有的方法,该实例不能使用,本类的私有方法只能由本类引用才能访问!比如:
public class Any {
public static void main(String[] args) {
Any any = new Any();
Object o = new Object();
o = any;
any.method();
System.out.println(o.equals(null));
System.out.println(any);
System.out.println(o);
System.out.println(any.getClass());
System.out.println(o.getClass());
}
public void method() {
System.out.println("本类实例方法");
}
}
两个实例的地址和所属类型都是一样的,但是调用的方法不一样!结果:
基本类型中的强制类型转换:
强制转换符号: ()
完整格式: 数据类型 变量 = (数据类型,与声明的数据类型一致) 变量 or 数值 or 对象。
强制转换:则是自动类型转换的逆操作。基本类型的强制类型转换;即由大转换为小的。
注意事项: 扩展赋值运算符和 ++ -- 它们底层已经实现了自动强制类型转换!
浮点数强转为整数类型一定为造成精度损失: 比如: double b = 3.134; long lo = (long) b; 那么此时的结果就是3,小数位直接砍掉!因为底层存储整数和浮点数的方式不一样!如果感兴趣可以参考我的另外一篇浮点数的存储方式:Java入门之7:Java中的float和double类型的浮点数是怎么按照IEEE 754标准存储的?_flagyili的博客-CSDN博客,如果超出了被强转的数据类型所能表示的数据范围,那么就会产生数据溢出现象。
比如:short sh = 130;byte b = (byte) sh; b = -126;出现了数据溢出。计算过程是:,可以这样计算,如果强转的数值是在被强转的数据类型的表示范围之内的话,那么数值还是原来的数值,如果超出了,则可以这样算。、
如果强转的数值大于被强转数据类型的所能表示的最小值的绝对值的时候,那么就用强转的数值减去最小值的绝对值,然后拿到这个差值,再用最小值加上刚刚操作数减去被强转范围类型所能表示的最小值的绝对值的的差。就是强转过后的数。即 byte by = (byte) 129;则是 129 - 128 = 1; -128 + 1 = -127; 即 by 等于 -127; ,
或者如果强转的数值大于被强转数据类型的所能表示的最小值的绝对值的倍数的时候,如果接近于最近的那个倍数的时候,如果公约数是奇数的情况下,则是用这个接近的倍数减去强转的数值的差,然后再用 最小值的绝对值 - 差值,即可,即:byte by =(byte) 380; 128 * 3 = 384 - 380 = 4; 再用 128 - 4 = 124,即by 等于 124;又举例:byte bt = (byte) 257;128 * 3 = 384 - 257 = 127;再用 128 - 127 = 1,即 bt = 1;
如果强转的数值刚好是最小值的绝对值的倍数且它的公约数是奇数的时候,那么它的结果就是最小值。比如是 byte b1 = (byte) 128,那么b1的结果就等于 128 * 1 = 128,结果就是 -128,还有 128 * 3 = 384,128 * 5 = 640,128 * 7 = 896,……;比如是byte b2 = (byte) 384;byte b3 = (byte) 640;byte b4 = (byte) 896;那么b2,b3,b4的结果都等于 -128 !
或者如果强转的数值大于被强转数据类型的所能表示的最小值的绝对值的倍数的时候,如果接近于最近的那个倍数的时候,如果公约数是偶数的情况下,则是用这个接近的倍数减去强转的数值的差,在把差变成负数即可,即:byte by =(byte) 255; 128 * 2 = 256 - 255 = 1; 1再变成负数,即by 等于 -1;又举例:byte bt = (byte)1020; 128 * 8 = 1024 - 1020 = 4; 4在变成负数即可,即bt = -4;
如果强转的数值刚好是最小值的绝对值的倍数且它的公约数是偶数的时候,那么它的结果就是0。比如是 byte b1 = (byte) 256,那么b1的结果就等于 128 * 2 = 256,结果就是 0,还有 128 * 4 = 512,128 * 6 = 768,128 * 8 = 1024,……;比如是byte b2 = (byte) 512;byte b3 = (byte) 768;byte b4 = (byte) 1024;那么b2,b3,b4的结果都等于 0!
注: 其他整数类型强转一样的!。比如:
浮点数的不一样,比较复杂,极少数情况把double强转为float类型的,一般都会使用双精度的double,float类型基本不会使用。既然要用float类型,直接声明就好了,没有必要转来转去,其实基本类型的强转操作使用得非常的少。基本不会使用。因为会产生精度丢失,或者 数据溢出 现象。
引用类型中的强制类型转换:
- 强转前提:强转的实例的类型与被强转的类型必须是继承或者实现的关系,如果把父类的实例强制转换给子类引用,编译不会报错,但是运行时会出现 ClassCastException异常!引用类型的强制类型转换实际开发中使用较多!
比如:(其实就相当于把 父类引用的子类实例重新赋值给子类,只是这里会强转才能重新赋值给子类!)
如果把父类的实例强制转换给子类引用,编译不会报错,但是运行时会出现 ClassCastException异常!比如: