由于公司既有软件的产品开发团队也有硬件的产品开发团队,所以难免会有一些软硬结合的项目,这种项目一般都是C/S模式的一般都是用C++或者C#搞定,我也有幸参与了几个C/S配套软件的编写,但是这次是使用Java去开发一个Web管理系统用于控制电源的通断电。还是比较痛苦的。你问为啥?我觉得有以下几点吧:
1、Java里面没有无符号数据类型;
2、Java的跨平台牺牲了直接调用Windows API的特性;
a、可以使用JNI调用C++编写的dll去实现串口的数据读取发送
b、可以使用jCommon提供的jar实现,其实也是如方法a一样,只是不需要自己去写dll以及调用的方法
3、对“位操作符”,“大小端”等知识点的不了解 。
针对以上我工作中遇到的问题,我将我学习到的以及理解的整理如下:
1、关于有符号和无符号数据类型
如果你不知道什么是有符号数据类型和无符号数据类型,那么请你先去了解一下补码的知识吧。
虽然说无符号数据类型有符号数据类型在计算机中的的存储是一样的 如:
/*
* (由于Java中都是有符号的数据类型,所以byte取值范围为 -128到127,
* 如果想存放大于127的值则需要强转)
*
* byte类型为1个字节8位
* 在计算机中存储为:
* 11111111
* 与无符号byte数据类型的255存储形式是一样的
*/
byte a = (byte) 0xFF;
但是,Java在输出的时候是-1,我们这时需要显示的是正数255该如何实现呢
①定义一个比byte大的数据类型(short,int,long),并使用“&”(位与)运算符
byte a = (byte) 0xFF;
/**
* 1、 因为Java是无符号类型,所以-1要在任何int下short下也表现为-1
* 就需要把最高位(符号位)一直带着
* 2、"&"就是将a中的11111111 & 00000000 11111111
* 目的就是将最高位的符号位去掉,取到正值
* 3、也可写作(a & 0xFF)但是为了看着清晰我还是喜欢写作0x00FF
* 4、位操作符就是针对于int类型的 所以需要强转
*/
short tmp = (short)(a & 0x00FF);
int tmp2 = a & 0x000000FF;
System.out.println(a);
System.out.println(tmp);
System.out.println(tmp2);
②在输出的时候直接使用“&”(位与)运算符
byte a = (byte) 0xFF;
System.out.println(a & 0x00FF);
2、Java中的位位运算符"<<"、">>"、">>>"、 "&" 、"|" 、"^"
①“<<”左移位运算符
public static void main(String[] args)
{
/**
* 系统中补码显示为
* 0111 1111
*/
byte a = 0x7F; //127
/*
* a << 2 为 1111 1100
* 如果是无符号类型,应该显示252,结果却显示为508
* 所以可见Java将容量扩大到4个字节
* 如果想显示出正确的数值 请记得&0xFF
*
*/
System.out.println("a << 2:" + (a << 2));
System.out.println("(a << 2) & 0xFF:" + ((a << 2) & 0xFF));
System.out.println("=======================");
System.out.println("a << 8:" + (a << 8));
System.out.println("(a << 8) & 0xFF:" + ((a << 8) & 0xFF));
System.out.println("=======================");
/**
* 系统中补码显示为
* 1111 1111
*/
byte b = (byte) 0xFF;//255
System.out.println("b << 2:" + (b << 2));
System.out.println("(b << 2) & 0xFF:" + ((b << 2) & 0xFF));
System.out.println("=======================");
System.out.println("b << 8:" + (b << 8));
System.out.println("(b << 8) & 0xFF:" + ((b << 8) & 0xFF));
}
控制台信息:
②“>>”右移位运算符与无符号右移位运算符">>>"
public static void main(String[] args)
{
/**
* 系统中补码显示为
* 0111 1111
*/
byte a = 0x7F; //127
/*
* a >> 2 为 1111 1100
* 如果没有超过127那么>>符号不存在任何问题
*
*/
System.out.println("a >> 2:" + (a >> 2));
System.out.println("(a >> 2) & 0xFF:" + ((a >> 2) & 0xFF));
System.out.println("=======================");
System.out.println("a >> 8:" + (a >> 8));
System.out.println("(a >> 8) & 0xFF:" + ((a >> 8) & 0xFF));
System.out.println("=======================");
/**
* 系统中补码显示为
* 1111 1111
*
* Java这个>>符号 我一直没弄明白 为什么超过了
* 最大的正整数大小后,怎么右移都是-1呢???
* 看来得研究一下 Java中的负数时怎么存的了,
* 应该是为了避免你将一个byte类型存储的-1转换成int类型后出现255而做了特殊处理!?
*
* 在这儿就推荐使用Java的无符号右移吧“>>>”
*/
byte b = (byte) 0xFF;//255
System.out.println("b >> 2:" + (b >> 2));
System.out.println("(b >> 2) & 0xFF:" + ((b >> 2) & 0xFF));
System.out.println("=======================");
System.out.println("b >> 8:" + (b >> 8));
System.out.println("(b >> 8) & 0xFF:" + ((b >> 8) & 0xFF));
System.out.println("==========>>>===========");
System.out.println("b >>> 2:" + (b >>> 2));
/**
* 这儿的 b & 0xFF 就是为了将Java擅自扩大的int类型的高24位都置为0
* Java将b扩大位int类型 为了显示-1 则需要存储为11111111 11111111 11111111 11111111
* b & 0xFF:11111111 11111111 11111111 11111111 & 00000000 00000000 00000000 11111111
* 步步是坑 得小心呀
*/
System.out.println("(b >>> 2) & 0xFF:" + ((b & 0xFF >>> 2) & 0xFF));
System.out.println("=======================");
System.out.println("b >>> 8:" + (b >>> 8));
System.out.println("(b >>> 8) & 0xFF:" + ((b & 0xFF >>> 8) & 0xFF));
}
控制台信息:
3、什么是“大端模式”、“小端模式”;“高位”、“低位”;“高地址”、“低地址”?
①高地址、低地址:
如在Java中定义一个byte类型的数组:byte[] buffer = new byte[10];那么buffer[0]相对于buffer[1]来说就是低地址,而buffer[1]相对于buffer[0]则是高地址;
②高位、低位:
如在Java中定义一个byte类型的变量a的值为55(计算机中的存储形式为:01010101),那么从左往右,左边是高位 为低位 如:最右边的1则为最低位,最右边的0相当对于最右边的1来说 是高位
③大小端模式:
大端模式就是在低地址中存放高位,而高地址中存放低位
如定义一个int类型的变量a = 0x7FFFFFFF;而在与硬件通信的时候,要求需要使用大端模式发送数据,
则在字节数组中如下操作:
byte[] bt = new byte[4];
bt[0] = 0x7F; //数组中的低地址 0x7F a变量中的高8位
bt[1] = 0xFF;
bt[2] = 0xFF;
bt[3] = 0xFF;
小端模式就是在低地址中存放低位,而高地址中存放高位
如定义一个int类型的变量a = 0x7FFFFFFF;而在与硬件通信的时候,要求需要使用小端模式发送数据,
则在字节数组中如下操作:
byte[] bt = new byte[4];
bt[0] = 0xFF;
bt[1] = 0xFF;
bt[2] = 0xFF;
bt[3] = 0x7F; //数组中的高地址 0x7F a变量中的高8位
如有什么写的不对的地方 还请大家指出 谢谢!