Java 无符号类型各类要点
一.发现场景
在数据库里通过主键的值搜索一条信息,把搜索到的信息封装成一个对象,用反射创建未知对象,并为对象对应的属性赋值。Map 集合储存列名和值。

在使用 MySQL 数据库的时候,把主键的数据类型设置成了 unsigned int (11),而在对象类里,此属性定义的为 int 。
运行语句后抛出异常:
java.lang.IllegalArgumentException: Can not set java.lang.Integer field JDBC2.Student.flowID to java.lang.Long

先是把在对象类中的数据类型改为 Integar,增强封装性。
还是抛出异常。
然后排除 别名的干扰,主键的干扰,自增的干扰,反射的干扰,int 长度改为4。
依然抛出异常。

后来发现是无符号类型的问题=-=

了解一下 Java 特殊的无符号类型吧


二.为什么有无符号?

在 C 和 C++ 这样的语言中,都提供了不同长度的整数类型:char, short, int, long (实际上,char 并不是真正的整数,但是可以把它当成整数来用。在实际应用场景中,很多人在 C 语言中用 char 来存储较小的整数)。

在大部分的 32 位操作系统上,这些类型分别对应 1 字节,2 字节,4 字节和 8 字节。但是需要注意的是,这些整数类型所对应的字节长度在不同的平台上是不一样的。相对而言,由于 Java 是针对跨平台来设计的,所以无论运行在什么平台上,Java 中的 byte 永远是 1 字节,short 是 2 字节,int 是 4 字节,long 是 8 字节。

C 语言中的整数类型都提供了对应的“无符号”版本,但是 Java 中就没有这个特性了。我觉得 Java 不支持无符号类型这个事儿实在是太不爽了,你想想,大量的硬件接口、网络协议以及文件格式都会用到无符号类型!(Java 中提供的 char 类型和 C 中的 char有所不同,在 Java 中,char 是用 2 个字节来表示 Unicode 值,在 C 中,char 是用 1 个字节来表示 ASCII 值。虽然可以在 Java 中把 char 当做无符号短整型来使用,用来表示 0 到 2^16 的整数。但是这样来用可能产生各种诡异的事情,比如当你要打印这个数值的时候,实际上打印出来的是这个数值对应的字符,而不是这个数值本身的字符串表示)。


三.无符号缺失之后怎么弥补?

使用比要用的无符号类型更大的有符号类型。

例如:使用 short 来处理无符号的字节,使用 long 来处理无符号整数等(甚至可以使用 char 来处理无符号短整型)。

确实,这样看起来很浪费,因为你使用了 2 倍的存储空间,但是也没有更好的办法了。另外,需要提醒的是,对于 long 类型变量的访问不是原子性操作,所以,如果在多线程场景中,你得自己去处理同步的问题。


四.如何以无符号形式储存或读取数据?

       首先,把有符号的 byte 提升成 int 类型,然后对这个 int 进行按位与操作,仅保留最后 8 个比特位。因为 Java 中的 byte 是有符号的,所以当一个 byte 的无符号值大于 127 的时候,表示符号的二进制位将被设置为 1(严格来说,这个不能算是符号位,因为在计算机中数字是按照补码方式编码的),对于 Java 来说,这个就是负数。当将负数数值对应的 byte 提升为 int 类型的时候,0 到 7 比特位将会被保留,8 到 31 比特位会被设置为 1。然后将其与 0x000000FF 进行按位与操作来擦除 8 到 31 比特位的 1。上面这句代码可以简短的写作:

xFF & (int)buf[index]

       Java 自动填充 0xFF 的前导的 0 ,并且在 Java 中,位操作符 & 会导致 byte 自动提升为 int

       接下来你看到的是很多的按位左移运算符 <<。 这个操作符会对左操作数按位左移右操作数指定的比特位。所以,如果你有一个 int foo = 0x000000FF,那么 foo << 8 会得到 0x0000FF00foo << 16 会得到 0x00FF0000

       最后是按位或操作符 |。假设你现在把一个无符号短整型的 2 个字节加载到了对应的整数中,你会得到 0x00000012  0x00000034 两个整数。现在你把第一个字节左移 8 位得到 0x00001200  0x00000034,然后你需要把他们再拼合回去。所以需要进行按位或操作。0x00001200 | 0x00000034 会得到 0x00001234,这样就可以存储到 Java 中的 char类型。

       这些都是基础操作。但是对于无符号 int,你需要把它存储到 long 类型中。其他操作和前面类似,只是你需要把 int 提升为 long 然后和 0xFFFFFFFFL 进行按位与操作。最后的 L 用来告诉 Java 请把这个常量视为 long 来处理。


五.异常的处理办法
1.MySQL 数据类型不设置成 unsigned(显然这是不安全的)
2.把需要设置成 unsigned 的数据变量,设置成更大的有符号类型。

Unsigned 类型转换:https://blog.csdn.net/tungkee/article/details/7549028
参考资料:https://www.cnblogs.com/yuanyq/p/java_unsigned_types.html

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

Java 无符号类型各类要点

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭