java位运算基础与实例

继续最近想更的东西很多,也对以前的知识有了新的看法,PS最近看了几部像吃了shi一样的电影推荐给大家,《消失的爱人》 《月球》

最近新起项目,从底层搭建,在写一个发送信息或短信的接口,正好用到了Java的位运算,写博客保存,也是装逼的好方法。

以前了解到位运算,但是实际确很少碰到,这次也是一个特别简单的方法,先上示例:
PS:int 的实际大小是32bit,文中为了方便基本上使用16bit代替
一、java位运算中按位与 实例
public static void main(String[] args) {
	sendMessage("","",7);
}

/**
 * 发送信息的对外接口
 * 发送短信flag : 1
 * 发送邮件flag : 2
 * 发送微信flag : 4
 * 同时发送多种 flag : 和(发送短信和邮件就是3)
 */
private static final int SMS = 1;
private static final int MAIL = 2;
private static final int WECHAT = 4;
public static void sendMessage(String title,String content,int flag){
	if((flag & SMS) == 1){
		System.out.println("调用发送短信接口");
	}
	if((flag & MAIL) == 2){
		System.out.println("调用发送邮件接口");
	}
	if((flag & WECHAT) == 4){
		System.out.println("调用发送微信接口");
	}
}

这个方法是比较简单的,使用java的安位与运算能够使逻辑更简洁和明朗。

二、java位运算

1.按位与 &
描述:两位全是1,结果才为1: 0&0=0; 0&1=0; 1&0=0; 1&1=1;
用途:
①清零:把一个数变为0,只要和0进行与运算。50&0=0;
②取一个数中制定位置:想取哪位,哪位置为1,其余为0;
      设 x = 1010 1110 想要取得x的低4位

               1010 1110
        &    0000 1111
       ————————————————————
               0000 1110

2.按位或 |
描述:只要有一个为1,结果就为1: 0|0=0; 0|1=1; 1|0=1; 1|1=1;
用途:
对一个数的某一位 置1:想要把哪位置1,哪位就是1,其余是0;
        设 x = 1010 0000  低4位置1
             
             1010 0000
         |   0000 1111
        ————————————————————
               1010 1111

3.按位异或 ^
描述:两个位的值为“异”(值不同),该位结果为1,值相同为0
     0^0=0; 0^1=1; 1^0=1; 1^1=0;
用途:
①使特定位翻转:想要翻转的位为1,其余为0;
       设 x = 1010 1110  低4翻转   
         
             1010 1110
         ^   0000 1111
        ————————————————————
               1010 0001
②与0异或保留原值
       设 x = 1010 1110  保留原值   
         
               1010 1110
         ^   0000 0000
        ————————————————————
               1010 1110
③两个值进行交换:比较高效的方法

void swap(int x , int y)
{
 x ^= y;
 y ^= x;
 x ^= y;
}


4.取反运算 ~

   ~1 = 0;  ~0 = 1;

5.左移运算 <<
描述:将一个运算对象的各二进制位全部左移若干位(左边二进制丢弃,右边补0)

      若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2。
      2<<1=4;
     0000 0010 左移1位 0000 0100 为4; => 2*2=4;

6.右移运算 >>
描述:将一个运算对象的各二进制位全部右移若干位( 正数左补0,负数左补1,右边丢弃
    
     每右移一位,相当于该数除以2;
     4>>2=1;
     0000 0100 右移两位 0000 0001 为1; => 4/2/2=1;

7.无符号右移运算 >>>
描述:各个位向右移制定位数(左边补0,右边丢弃)

8.负数移位举例
负数是以其正值的补码形式来表示的
原码:一个正数按照绝对值大小转化成的二进制数称为原码
     14原码: 0000 0000  0000 0000  0000 0000  0000 1110
反码:将原码按位取反,所得二进制称为原二进制的反码
     14反码: 1111 1111  1111 1111  1111 1111  1111 0001
补码:反码加1称为补码
     14补码: 1111 1111  1111 1111  1111 1111  1111 0010  =>即-14的二进制表示

求-14<<2
1111 1111 1111 1111 1111 1111 1111 0010 左移两位,右边补0
1111 1111 1111 1111 1111 1111 1100 1000 然后这个二进制的十进制是多少呢?肯定是一个负数,所以需要按照上面顺序反向求出该二进制的十进制。

先减一:
1111 1111 1111 1111 1111 1111 1100 0111
取反:
0000 0000 0000 0000 0000 0000 0011 1000  =>56

所以 -14<<2 = -56;

以上是负数的取反的分析过程。
从网上找到一个位运算的口诀:

清零取数要用与,某位置一可用或
若要取反和交换,轻轻松松用异或

三、java进制转换
1.进制转换API
//十进制到十六进制
Integer.toHexString(int i);
//十进制到八进制
Integer.toOctalString(int i);
//十进制到二进制
Integer.toBinaryString(int i);
//十六进制到十进制
Integer.parseInt("0xff", 16);
//八进制到十进制
Integer.parseInt("0123", 8);
//二进制到十进制
Integer.parseInt("1010", 2);


2.Java基本数据类型
byte : 8bit;
short : 16bit;
int : 32bit;
long : 64bit;
float : 32bit;
double : 64bit;
char : unicode字符16bit;

3.java数据类型转换为字节的底层实现原理([color=red]就是使用位运算哦)[/color]
例:8143(00000000 00000000 00011111 11001111)转化为字节数组为:
    byte[] b = [-49,31,0,0]
实现:
①低8位: 8143>>0*8 & 0xff; 8143右移0位 和十六进制0xff进行 & 运算。
  0xff:11111111 功能就是屏蔽掉前面24位取得最后8位。
  结果为:11001111 十进制:207 或者 -49;
②第二低8位: 8143 >> 1*8 & 0xff; 8143右移1位 和十六进制0xff进行 & 运算。
  向右移8位,然后与运算屏蔽前面24位取得第二8位。
  结果为:00011111 十进制:31;
③第三低8位: 8143 >> 2*8 & 0xff; 8143右移2位 和十六进制0xff进行 & 运算。
  结果为0;
③第四低8位: 8143 >> 3*8 & 0xff; 8143右移3位 和十六进制0xff进行 & 运算。
  结果为0;

综上,每次进行移位取特定的8位,转化成相应的字节数组,以上的方式是采用小端表示法。

4.javaIO的源码中位运算
java源码中与上面例子十分相似的有一个IO流的writeInt方法。
DataOutputStream中的writeInt()方法:
public final void writeInt(int v) throws IOException {
        out.write((v >>> 24) & 0xFF);
        out.write((v >>> 16) & 0xFF);
        out.write((v >>>  8) & 0xFF);
        out.write((v >>>  0) & 0xFF);
        incCount(4);
    }

java底层的实现很多都用到了位运算,所以掌握好了还是可以帮助查看源码的。

5.大小端
上面举例是采用小端的方式来输出字节数组的。
小端(Little-Endian):低位字节排放到内存的低地址端即该值的起始地址,高位字节排放到内存的高地址端。
大端(Big-Endian):高位字节排放到内存的低地址端即该值的起始地址,低位字节排放到内存的高地址端。

byte b = [-49,31,0,0]
小端
内存地址 0x4000 0x4001 0x4002 0x4003
存放内容 -49   31    0     0


大端
内存地址 0x4000 0x4001 0x4002 0x4003
存放内容 0     0     31    -49



先这些吧,累屎,不过每次自己码完博客,对待问题都会有更新的认识,明天继续JAVA IO流。

猜你喜欢

转载自sunyuqian.iteye.com/blog/2251802
今日推荐