为什么字节和短除法在Java中会导致int?
在Java中,如果我们将为什么字节和短除法在Java中会导致int?,java,integer,division,integer-division,Java,Integer,Division,Integer Division,在Java中,如果我们将bytes、shorts或ints分开,我们总是得到int。如果其中一个操作数是long,我们将得到long 我的问题是,byte或short除法为什么不产生byte或short?为什么总是int 显然,我不是在寻找“因为JLS这么说”的答案,我是在问Java语言中这个设计决策的技术原理 考虑以下代码示例: byte byteA = 127; byte byteB = -128; short shortA = 32767; short sh
byte
s、short
s或int
s分开,我们总是得到int
。如果其中一个操作数是long
,我们将得到long
我的问题是,byte
或short
除法为什么不产生byte
或short
?为什么总是int
显然,我不是在寻找“因为JLS这么说”的答案,我是在问Java语言中这个设计决策的技术原理
考虑以下代码示例:
byte byteA = 127;
byte byteB = -128;
short shortA = 32767;
short shortB = -32768;
int intA = 2147483647;
int intB = - -2147483648;
long longA = 9223372036854775807L;
long longB = -9223372036854775808L;
int byteAByteB = byteA/byteB;
int byteAShortB = byteA/shortB;
int byteAIntB = byteA/intB;
long byteALongB = byteA/longB;
int shortAByteB = shortA/byteB;
int shortAShortB = shortA/shortB;
int shortAIntB = shortA/intB;
long shortALongB = shortA/longB;
int intAByteB = intA/byteB;
int intAShortB = intA/shortB;
int intAIntB = intA/intB;
long intALongB = intA/longB;
long longAByteB = longA/byteB;
long longAShortB = longA/shortB;
long longAIntB = longA/intB;
long longALongB = longA/longB;
byteA
除以byteB
只能是一个字节,不是吗?那么为什么
byteAByteB
必须是int
?为什么shortALongB
不能short
?为什么
intALongB
必须是long
,结果总是符合int
,不是吗
更新
正如@Eran所指出的,(byte)-128/(byte)-1
导致128
,这与字节不匹配。那么为什么不缩短呢
更新2
接下来,正如@Eran(再次)指出的,(int)-2147483648/(int)-1
也不适合int
,但结果是int
,而不是long
byteA除以byteB只能是一个字节,对吗
它可以不是字节:
byteA = -128;
byteB = -1;
int div = byteA/byteB; // == 128, not a byte
我猜这是从C中得到的,可能是通过C++。< /P>
在这些语言中,如果一个或多个参数的类型比int
的类型窄,则它们总是升级为int
。这在计算表达式之前发生。由于生成的操作被转换为它所指定的类型,因此它经常被忽略,如果没有副作用,编译器可以很好地优化所有中间步骤
在Java中,虽然它不是太有害。(在C和C++中它可以让你知道:两个大的<代码>未签名的短s的乘法可以溢出<代码> int <代码>,其行为未定义。< /P>
请注意,如果其中一个参数大于int
,则表达式的类型是参数类型中最大的。我认为理由是简单规则产生的惊喜最少。结果总是两种类型中较宽的(最小值为int
),它不依赖于操作
更好的方法可能是总是加宽+
,*
,-
,除非显式(或隐式)缩小。i、 除非使用石膏,否则不要做溢流或下溢<例如,代码>/
可以始终是一个double
或long
操作,除非进行了铸造
但是C和Java并没有做到这一点
简而言之,它有一个简单的规则来处理这个问题,不管是好是坏
请参见此处的“我的rant”主要原因是机器通常只为其本机整数类型(和浮点)添加指令。这就是为什么对于许多语言来说,算术表达式中使用最少的类型是
int
(通常是以某种方式与基本机器整数类型相对应的类型)
例如,i386规范说明:
ADD执行两个操作数(DEST和SRC)的整数相加。
加法的结果分配给第一个操作数(DEST),
并相应地设置标志。将立即数字节添加到
一个字或双字操作数,立即数值符号扩展为
字或双字操作数的大小
这意味着在内部,任何字节值都扩展为整数(或类似值)。毕竟,这是合理的,因为处理器是32/64位,然后执行这些大小的任何算术。如果可以用字节进行算术运算,通常认为这是没有用的
JVM规范说(作为补充)您有:
iadd
,ladd
,fadd
,dadd
。这仅仅反映了一个事实,即底层机器通常表现出这样的行为。任何其他选择都是可能的,可能是以性能降低为代价的。每当定义byte类型的变量时,无论您在其中键入什么,都应该是byte类型的变量
这意味着它只能是一个字节(-128到127)范围内的数字
但是,当您键入表达式时,例如,byteA/byteB,这与键入文字时不同。例如,数字127
这就是Java的本质-整数是用于整数的默认数据类型
默认情况下,在对表达式进行赋值时,Java会将其转换为默认数据类型(整数),尽管表达式的结果可能是字节的有效值
因此,当您定义一个字节并指定一个表达式作为该字节的值时,Java需要将其转换为整数:
int byteAByteB = byteA / byteB;
但是,您可以通过强制转换指定的表达式,从而放弃Java将其视为字节来解决这个问题
byte byteAByteB = (byte) (byteA / byteB);
这样,您告诉Java将其视为一个字节。(也可以用short等方式完成)注意要点。那为什么不短一点呢?
一个字节也不短。。因为它没有无符号的概念。。128在其他支持unsigned的语言中仍然只是一个字节(char
),请注意,char
在Java中是一种16位无符号类型。很好。@lexicore你说得对,我的例子用Integer.MIN_值除以-1不起作用(因为操作数不会提升为long,所以会出现int溢出)。@Eran-2147483648/-1
导致-2147483648
。酷。打破了我今天的逻辑。你确定这是两种更广泛的类型吗?我的理解是