Java中有没有办法使用像(My)SQL中的无符号数字?
例如:我想使用一个 8 位变量 ( byte
),其范围如下:0
... 256
; 而不是-128
……127
Java中有没有办法使用像(My)SQL中的无符号数字?
例如:我想使用一个 8 位变量 ( byte
),其范围如下:0
... 256
; 而不是-128
……127
不,Java 没有任何无符号原始类型char
(有效值为 0-65535)。这是一种痛苦(尤其是对于byte
),但事实就是如此。
通常,您要么坚持使用相同的大小,并将“高”数字溢出为负数,要么使用更广泛的类型(例如short
for byte
)并处理额外的内存需求。
您可以使用类来模拟无符号数。例如
public class UInt8 implements Comparable<UInt8>,Serializable
{
public static final short MAX_VALUE=255;
public static final short MIN_VALUE=0;
private short storage;//internal storage in a int 16
public UInt8(short value)
{
if(value<MIN_VALUE || value>MAX_VALUE) throw new IllegalArgumentException();
this.storage=value;
}
public byte toByte()
{
//play with the shift operator ! <<
}
//etc...
}
大多数情况下,您可以像使用无符号数一样使用有符号数。大多数操作保持不变,有些需要修改。看到这个帖子。
在内部,您不应该使用较小的值——只需使用 int。据我了解,使用较小的单位只会减慢速度。它不会节省内存,因为 Java 在内部使用系统的字大小来存储所有存储(它不会打包字)。
但是,如果您使用较小尺寸的存储单元,则必须为每个操作屏蔽它们或进行范围检查或其他操作。
有没有注意到 char(任何操作)char 会产生一个 int?他们只是真的不希望您使用这些其他类型。
例外是数组(我相信它们会被打包)和 I/O,您可能会发现使用较小的类型很有用……但屏蔽也可以。
不,你不能改变它。如果您需要大于 127 的内容,请选择大于一个字节的内容。
如果您需要优化存储(例如大型矩阵),您可以使用负数编码更大的正数,以节省空间。然后,您必须在需要时移动数值以获得实际值。例如,我只想处理短的正数。这在 Java 中是如何实现的:
short n = 32767;
n = (short) (n + 10);
System.out.println(n);
int m = (int) (n>=0?n:n+65536);
System.out.println(m);
所以当一个短整数超出范围时,它变成负数。但是,至少您可以将此数字存储在 16 位中,并通过添加移位值(可以编码的不同值的数量)来恢复其正确值。该值应该以更大的类型(在我们的例子中为 int)恢复。这可能不是很方便,但我发现在我的情况下是如此。
我对 Java 和编程很陌生。然而,我最近遇到了同样的情况,需要无符号值。
我花了大约两周的时间来编写我想到的所有东西,但我完全是个菜鸟,所以你可以花更少的钱。
总体思路是创建接口,我将其命名为:并在实现抽象类UnsignedNumber<Base, Shifted>
的同时扩展 Number.class 。AbstractUnsigned<Base, Shifted, Impl extends AbstractUnsigned<Base, Shifted, Impl>>
因此,Base 参数化类型代表基本类型,Shifted 代表实际 Java 类型。Impl 是实现这个抽象类的快捷方式。
大多数时间消耗 Java 8 Lambda 的样板文件和内部私有类和安全程序。重要的是当减法或负加法等数学运算产生零极限时实现无符号行为:向后溢出有符号上限。
最后,又花了几天时间编写工厂代码和实现子类。
到目前为止,我已经知道:UByte 和 MUByte UShort 和 MUShort UInt 和 MUInt ... 等等。
它们是 AbstractUnsigned 的后代:UByte 或 MUByte extendAbstractUnsigned<Byte, Short, UByte>
或AbstractUnsigned<Byte, Short, MUByte>
UShort 或 MUshort extendAbstractUnsigned<Short, Integer, UShort>
或AbstractUnsigned<Short, Integer, MUShort>
...等。
一般的想法是将无符号上限作为移位(强制转换)类型和负值的代码转置,因为它们不是来自零,而是来自无符号上限。
更新:(感谢Ajeans友善和礼貌的指示)
/**
* Adds value to the current number and returns either
* new or this {@linkplain UnsignedNumber} instance based on
* {@linkplain #isImmutable()}
*
* @param value value to add to the current value
* @return new or same instance
* @see #isImmutable()
*/
public Impl plus(N value) {
return updater(number.plus(convert(value)));
}
这是AbstractUnsigned<N, Shifted, Impl>
(或如前所述AbstractUnsigned<Base, Shifted, Impl>
)的外部可访问方法;现在,到引擎盖下的工作:
private Impl updater(Shifted invalidated){
if(mutable){
number.setShifted(invalidated);
return caster.apply(this);
} else {
return shiftedConstructor.apply(invalidated);
}
}
在上面的私有方法mutable
中是private final boolean
一个AbstractUnsigned
。number
是负责转换为的内部私有类之一,Base
反之亦然Shifted
。与之前的“我去年夏天所做的部分”相对应的是两个内部对象:caster
和shiftedConstructor
:
final private Function<UnsignedNumber<N, Shifted>, Impl> caster;
final private Function<Shifted, Impl> shiftedConstructor;
如果 的当前实现实例是不可变的,则这些是要转换N
(或Base
)到Shifted
或创建新实例的参数化函数。Impl
AbstractUnsigned<>
Shifted plus(Shifted value){
return spawnBelowZero.apply(summing.apply(shifted, value));
}
在这个片段中显示了number
对象的添加方法。这个想法是始终在Shifted
内部使用,因为不确定何时会产生“原始”类型的正限制。shifted
是一个内部参数化字段,它具有整体的值AbstractUnsigned<>
。其他两个Function<>
派生对象如下:
final private BinaryOperator<Shifted> summing;
final private UnaryOperator<Shifted> spawnBelowZero;
前者执行两个Shifted
值的加法。后者在零转置以下执行产卵。
现在有一个来自工厂样板“地狱”的例子,AbstractUnsigned<Byte, Short>
专门针对前面提到的spawnBelowZero
UnaryOperator<Shifted>
:
...,
v-> v >= 0
? v
: (short) (Math.abs(Byte.MIN_VALUE) + Byte.MAX_VALUE + 2 + v),
...
如果Shifted v
为正,则实际上没有任何反应,并且正在返回原始值。否则:需要计算Base
类型的上限 isByte
并加起来为负值v
。如果,比方说,v == -8
那么Math.abs(Byte.MIN_VALUE)
将产生并将128
产生Byte.MAX_VALUE
+ 1 以获得被符号位削减的原始上限,正如我所知道的那样,并且如此理想就在这个地方。但第一个负值实际上是这就是为什么再次或完全如此。最后,这是给和127
255
256
256
+1
+2
255 + 2 + v
-8
255 + 2 + (-8)
249
或者以更直观的方式:
0 1 2 3 ... 245 246 247 248 249 250 251 252 253 254 255 256
-8 -7 -6 -5 -4 -3 -2 -1
并最终确定所有这些:这绝对不会减轻您的工作或节省内存字节,但在需要时您有一个非常理想的行为。您几乎可以将这种行为与任何其他Number.class
子类一起使用。AbstractUnsigned
作为Number.class
自身的子类提供了与其他“本机”子类类似的所有便利方法和常量Number.class
,包括MIN_VALUE
andMAX_VALUE
以及更多,例如,我为可变子类编写了便利方法,调用makeDivisibileBy(Number n)
它执行最简单的value - (value % n)
.
我最初的努力是证明即使是像我这样的菜鸟也可以编写代码。在编写该类代码时,我最初的努力是获得方便的多功能工具以供持续使用。