java移位运算符以及其他运算符的操作

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移位运算:

Java的位运算(bitwise operators)直接对整数类型的位进行操作,这些整数类型包括long、int、short、char和 byte,位运算符具体如下表:

运算符

说明

<< 

左移位,在低位处补0

>> 

右移位,若为正数则高位补0,若为负数则高位补1

>>> 

无符号右移位,无论正负都在高位补0

&

与(AND),对两个整型操作数中对应位执行布尔代数,两个位都为1时输出1,否则0。

|

或(OR),对两个整型操作数中对应位执行布尔代数,两个位都为0时输出0,否则1。

~

非(NOT),一元运算符。

^

异或(XOR),对两个整型操作数中对应位执行布尔代数,两个位相等0,不等1。

<<=

左移位赋值。

>>=

右移位赋值。

>>>=

无符号右移位赋值。

&=

按位与赋值。

|=

按位或赋值。

^=

按位异或赋值。

左移位(<<)

程序:

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中的基本数据类型的相关知识。

数据类型

大小

最小值

最大值

boolean

byte

8-bit

-128

+127

char

16-bit

Unicode 0

Unicode 216-1

short

16-bit

-215

+215-1

int

32-bit

-231

+231-1

float

32-bit

IEEE754

IEEE754

long

64-bit

-263

263-1

double

64-bit

IEEE754

IEEE754

void

这里包括了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

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值