【发布时间】:2009-10-08 19:43:55
【问题描述】:
在 Java 中有没有办法像在 (My)SQL 中一样使用无符号数?
例如:我想使用一个 8 位变量 (byte),其范围如下:0 ... 256;而不是-128 ... 127。
【问题讨论】:
标签: java unsigned primitive-types
在 Java 中有没有办法像在 (My)SQL 中一样使用无符号数?
例如:我想使用一个 8 位变量 (byte),其范围如下:0 ... 256;而不是-128 ... 127。
【问题讨论】:
标签: java unsigned primitive-types
不,除了char(有效值为 0-65535)之外,Java 没有任何无符号原始类型。这很痛苦(尤其是byte),但就是这样。
通常,您要么坚持使用相同的大小,然后将“高”数字溢出为负数,或者使用更宽的类型(例如,byte 使用更宽的类型(例如,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...
}
【讨论】:
大多数情况下,您可以像使用无符号数一样使用有符号数。大多数操作保持不变,有些需要修改。见this post。
【讨论】:
在内部,您不应该使用较小的值 - 只需使用 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>,并在实现抽象 AbstractUnsigned<Base, Shifted, Impl extends AbstractUnsigned<Base, Shifted, Impl>> 类的同时扩展 Number.class。
所以,Base 参数化类型代表基本类型,Shifted 代表实际 Java 类型。 Impl 是实现这个抽象类的快捷方式。
大部分时间都消耗 Java 8 Lambda 的样板文件以及内部私有类和安全程序。重要的是在减法或负加法等数学运算产生零极限时实现无符号行为:向后溢出有符号上限。
最后,又花了几天时间编写工厂和实现子类。
到目前为止,我知道: UByte 和 MUByte UShort 和 MUShort UInt 和 MUInt ...等
它们是 AbstractUnsigned 的后代:
UByte 或 MUByte 扩展 AbstractUnsigned<Byte, Short, UByte> 或 AbstractUnsigned<Byte, Short, MUByte>
UShort 或 MUShort 扩展 AbstractUnsigned<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 是AbstractUnsigned 的private final boolean。 number 是负责将Base 转换为Shifted 的内部私有类之一,反之亦然。
与之前的“我去年夏天所做的部分”相对应的重要事项
是两个内部对象:caster 和shiftedConstructor:
final private Function<UnsignedNumber<N, Shifted>, Impl> caster;
final private Function<Shifted, Impl> shiftedConstructor;
如果AbstractUnsigned<> 的当前实现实例不可变,这些是将N(或Base)转换为Shifted 或创建新的Impl 实例的参数化函数。
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 类型的上限Byte,并将该值加起来为负v。如果,比方说,v == -8,那么Math.abs(Byte.MIN_VALUE) 将产生128 和Byte.MAX_VALUE 将产生127,它给出255 + 1 来获得被符号位削减的原始上限,因为我明白了,那么令人向往的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 和MAX_VALUE 等等,例如,我为可变子类编写了便捷方法makeDivisibileBy(Number n),它执行value - (value % n) 的最简单操作。
我最初的努力是为了证明即使是像我这样的菜鸟也可以编写代码。在编写该类代码时,我最初的努力是获得方便的多功能工具以供持续使用。
【讨论】: