java中移位操作总是看了忘,再此做个笔记,找了很多资料这个比较容易记住: byte是-127~128,在此处说一个对象的问题: “ 我被下面的代码搞晕了,为什么它们会返回不同的值?” System.out.println(Integer.valueOf("127")==Integer.valueOf("127")); System.out.println(Integer.valueOf("128")==Integer.valueOf("128")); System.out.println(Integer.parseInt("128")==Integer.valueOf("128")); 输出是: true false true 回答1: Integer.valueOf(String) 确有一个不同寻常的行为。 valueOf会返回一个Integer(整型)对象,当被处理的字符串在-128和127(包含边界)之间时,返回的对象是预先缓存的。这就是为什么第一行的调用会返回true。-127这个整型对象是被缓存的(所以两次valueOf返回的是同一个对象)——第二行的调用返回false是因为128没有被缓存,所以每次调用,都会生成一个新的整型对象,因此两个128整型对象是不同的对象。 重要的是你要知道在上面的比较中,你实际进行比较的是integer.valueOf返回的对象引用,所以当你比较缓存外的整型对象时,相等的判断不会返回true,就算你传个valueOf的值是相等的也没用。(就像第二行中Integer.valueOf(128)==Integer.valueOf(128))。想让这个判断返回true,你需要使用equals()方法。 parseInt()返回的不是整型对象,而是一个int型基础元素。这就是为什么最后一个判断会返回true,第三行的判断中,在判断相等时,实际比较的是128 == 128,所以它必然是相等的。 再来说说第三种比较中的一点区别,使得它的结果与第二种比较不一样了: 一个unboxing conversion(一种比较时的转换,把对对象的引用转换为其对应的原子类型)在第三行的比较中发生了。因为比较操作符使用了==同时等号的两边存在一个int型和一个Integer对象的引用。这样的话,等号右边返回的Integer对象被进一步转换成了int数值,才与左边进行相等判断。 所以在转换完成后,你实际比较的是两个原子整型数值。这种转换正是你在比较两个原子类型时所期待看到的那样,所以你最终比较了128等于128。 回答2: Integer类有一个静态缓存,存储了256个特殊的Integer对象——每个对象分别对应`-128 和127之间的一个值。 有了这个概念,就可以知道上面三行代码之间的区别。 new Integer(123); 显示创建了一个新的Integer对象。 Integer.parseInt("123"); 解析完字符串后返回一个int值。 Integer.valueOf("123"); 这种情况比其他的要更复杂一些。首先进行了字符串解析,然后如果解析的值位于-128和127之间,就会从静态缓存中返回对象。如果超出了这个范围,就会调用Integer()方法并将解析的值作为参数传入,得到一个新的对象。 现在,让我们看一下问题中的3个表达式。 Integer.valueOf("127")==Integer.valueOf("127"); 上面的表达式返回true,因为Integer的值从静态缓存中取了2次,表达式返回了对象与自己比较的结果。因为只有一个Integer对象,所以返回结果为true。 Integer.valueOf("128")==Integer.valueOf("128"); 上面的表达式返回false,因为128没有存在静态缓冲区。所以每次在判断相等时等式两边都会创建新的Integer对象。由于两个Integer对象不同,所以==只有等式两边代表同一个对象时才会返回true。因此,上面的等式返回false。 Integer.parseInt("128")==Integer.valueOf("128"); 上面的表达式比较的是左边的原始int值128与右边新创建的Integer对象。但是因为int和Integer之间比较是没有意义的,所以Java在进行比较前会将Integer自动拆箱,所以最后进行的是int和int值之间的比较。由于128和自己相等,所以返回true。 Java的位运算(bitwise operators)直接对整数类型的位进行操作,这些整数类型包括long、int、short、char和 byte,位运算符具体如下表:
程序: public class LeftMoving{ public static void main(String[] args){ System.out.println("5<<3="+(5<<3)); } } 输出结果: 5<<3=40 计算过程: 0000 0000 0000 0000 0000 0000 0000 0101 ? 5 0000 0000 0000 0000 0000 0000 0010 1000 ? 40 程序: public class PlusRightMoving{ public static void main(String[] args){ System.out.println("5>>1="+(5>>1)); } } 输出结果: 5>>1=2 计算过程: 0000 0000 0000 0000 0000 0000 0000 0101 ? 5 0000 0000 0000 0000 0000 0000 0000 0010 ? 2 程序: public class NegativeRightMoving{ public static void main(String[] args){ System.out.println("-5>>1="+(-5>>1)); } } 输出结果: -5>>1=-3 计算过程: 1111 1111 1111 1111 1111 1111 1111 1011 ? -5 1111 1111 1111 1111 1111 1111 1111 1101 ? -3 程序: public class UnsignedRightMoving{ public static void main(String[] args){ System.out.println("-5>>>1="+(-5>>>1)); } } 输出结果: -5>>>1=2147483645 计算过程: 1111 1111 1111 1111 1111 1111 1111 1011 ? -5 0111 1111 1111 1111 1111 1111 1111 1101 ? 2147483645 |
首先复习一下Java中的基本数据类型的相关知识。
这里包括了float和double两个浮点型,在本文中对其不予考虑,因为位运算是针对整型的。进行位操作时,除long型外,其他类型会自动转成int型,转换之后,可接受右操作数长度为32。进行位运算时,总是先将短整型和字节型值转换成整型值再进行移位操作的。 程序: [java] view plaincopy 1. public class ByteLeftMoving{ 2. 3. public static void main(String[] args){ 4. 5. byte b = 127; 6. 7. System.out.println("b<<3="+(b<<3)); 8. 9. System.out.println("(byte)(b<<3)="+(byte)(b<<3)); 10. 11. } 12. 13. }
输出结果: b<<3=1016 (byte)(b<<3)=-8 程序:
[java] view plaincopy 1. public class CharLeftMoving{ 2. 3. public static void main(String[] args){ 4. 5. char c = 'l'; 6. 7. System.out.println("c<<3="+(c<<3)); 8. 9. System.out.println("(char)(c<<3)="+(char)(c<<3)); 10. 11. } 12. 13. }
输出结果: c<<3=864 (char)(c<<3)=? 以上两个例子全部编译通过,由此可以看出,当byte和char进行移位运算时不会发生错误,并且均按照整型进行计算,当计算结果超出byte或是char所能表示的范围时则进行相应的转换(分别输出了结果-8和?)。 |
在进行移位运算时要注意整型和长整型在内存中的位数(整型是32位,长整型是64位),如果移位操作数超出了该位数则取模计算,例如:int型数据是32位的,如果左移35位是什么结果? 程序: [java] view plaincopy 1. public class LeftMoving{ 2. 3. public static void main(String[] args){ 4. 5. System.out.println("5<<35="+(5<<35)); 6. 7. } 8. 9. }
输出结果: 5<<35=40 该结果与5<<3完全相同。 无论正数、负数,它们的右移、左移、无符号右移 32位都是其本身,比如 -5<<32=-5、-5>>32=-5、-5>>>32=-5。 一个有趣的现象是,把 1 左移 31 位再右移 31位,其结果为 -1。 计算过程如下: 0000 0000 0000 0000 0000 0000 0000 0001 1000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111 1111 1111 1111 1111 位运算要求操作数为整数,操作数不能是字符串也不能是小数。 如下列程序: [java] view plaincopy 1. public class BitMath{ 2. 3. public static void main(String[] args){ 4. 5. String s = "Hello"; 6. 7. long l = 99; 8. 9. double d = 1.11; 10. 11. int i = 1; 12. 13. int j = 0; 14. 15. 16. System.out.println("j<<s="+j<<s); //编译错误语句 17. 18. System.out.println("j<<d="+j<<d); //编译错误语句 19. 20. System.out.println("i<<j="+i<<j); //编译可以通过 21. 22. System.out.println("i<<l="+i<<l); //编译可以通过 23. 24. } 25. 26. }
|
由于位运算是二进制运算,不要与一些八进制数搞混,java中二进制数没有具体的表示方法。 public class BitMath{ public static void main(String[] args){ System.out.println("010|4="+(010|4)); } } 输出结果: 010|4=12 计算过程: 0000 0000 0000 0000 0000 0000 0000 1000 ?8 0000 0000 0000 0000 0000 0000 0000 0100 ?4 进行“或”计算结果为: 0000 0000 0000 0000 0000 0000 0000 1100 ?12 当位运算中遇见负数,必须把它转成补码(不知道什么是补码的补习功课去)再进行计算,而不是使用原码。 程序: public class BitMath{ public static void main(String[] args){ try { int x = -7; System.out.println("x>>1="+(x>>1)); } catch(Exception e) { System.out.println("Exception"); } } } 输出结果: x>>1=-4 计算过程: 1111 1111 1111 1111 1111 1111 1111 1001 ?-7 1111 1111 1111 1111 1111 1111 1111 1100 ?-4 [java] view plaincopy 1. public class BitMath{ 2. 3. public static void main(String[] args){ 4. 5. int i = 1; 6. 7. int j = -1; 8. 9. System.out.println("1>>>31="+(i>>>31)); 10. 11. System.out.println("-1>>31="+(j>>31)); 12. 13. } 14. 15. }
输出结果: 1>>>31=0 -1>>31=-1 程序: [java] view plaincopy 1. public class BitMath{ 2. 3. public static void main(String[] args){ 4. 5. int a = 1; 6. 7. a <<= 31; 8. 9. a >>= 31; 10. 11. a >>= 1; 12. 13. System.out.println("a="+a); 14. 15. 16. int b = 1; 17. 18. b <<= 31; 19. 20. b >>= 31; 21. 22. System.out.println("b="+b); 23. 24. 25. int c = 1; 26. 27. c >>= 31; 28. 29. c <<= 31; 30. 31. System.out.println("c="+c); 32. 33. } 34. 35. } 输出结果: a=-1 b=-1 c=0 计算过程: 0000 0000 0000 0000 0000 0000 0000 0001 ?a=1 1000 0000 0000 0000 0000 0000 0000 0000 ?a=a<<31后,这里被当作是负数 1111 1111 1111 1111 1111 1111 1111 1111 ?a=a>>31后,结果为-1 1111 1111 1111 1111 1111 1111 1111 1111 ?a=a>>1后,结果仍为-1 0000 0000 0000 0000 0000 0000 0000 0001 ?c=1 0000 0000 0000 0000 0000 0000 0000 0000 ?c=c>>31后为0 0000 0000 0000 0000 0000 0000 0000 0000 ?0左移31位仍为0 |