java 不规则 拼图
总览
当您在Java中执行一元或二进制运算时,标准行为是使用最宽的操作数(或对于byte
, short
和char
,使用更大的操作数)。 这很容易理解,但是如果考虑最佳类型可能会造成混淆。
乘法
当执行乘法时,您得到的数值通常比单个数值大得多。 即| a * b | >> | a | 和| a * b | >> | b | 通常是这种情况。 对于小型字体,这可以按预期工作。
考虑以下程序:
public static void main(String[] args) throws IOException {System.out.println(is(Byte.MAX_VALUE * Byte.MAX_VALUE));System.out.println(is(Short.MAX_VALUE * Short.MAX_VALUE));System.out.println(is(Character.MAX_VALUE * Character.MAX_VALUE));System.out.println(is(Integer.MAX_VALUE * Integer.MAX_VALUE));System.out.println(is(Long.MAX_VALUE * Long.MAX_VALUE));
}static String is(byte b) {return "byte: " + b;
}static String is(char ch) {return "char: " + ch;
}static String is(short i) {return "short: " + i;
}static String is(int i) {return "int: " + i;
}static String is(long l) {return "long: " + l;
}
打印:
int: 16129
int: 1073676289
int: -131071
int: 1
long: 1
只有byte * byte
和short * short
不会溢出,因为它们已被扩展。 char * char
即使允许,也不是有意义的操作。 但是int * int
确实会溢出,即使我们有一个长类型也可以存储此值而不会溢出。 byte
和short
都隐式加宽,但不是int
。 应该真正地将long
扩展,但是我们没有一个更宽泛的基本类型,这曾经是有意义的,但是如今64位基本类型看起来并不那么长。
师
从除数可以扩大结果的意义上讲,除法有些奇怪。 除数比分子宽并不意味着结果会更大(但通常会更小)
System.out.println(is(Byte.MAX_VALUE / (byte) 1));
System.out.println(is(Byte.MAX_VALUE / (short) 1));
System.out.println(is(Byte.MAX_VALUE / (char) 1));
System.out.println(is(Byte.MAX_VALUE / (int) 1));
System.out.println(is(Byte.MAX_VALUE/ (long) 1));
版画
int: 127
int: 127
int: 127
int: 127
long: 127
当你把一个byte/byte
你会得到一个int
即使你不能得到比一个大的值byte
。 (除非您将Byte.MIN_VALUE除以-1(在这种情况下, short
会这样做),并且如果将byte/long
除以byte/long
即使值仍然不能大于byte
您也会得到long
。
模量
当执行模数a % b
,结果不能大于b
。 但是模数会扩大结果而不是减少结果。
System.out.println(is(Byte.MAX_VALUE % Byte.MAX_VALUE));
System.out.println(is(Byte.MAX_VALUE % Short.MAX_VALUE));
System.out.println(is(Byte.MAX_VALUE % Character.MAX_VALUE));
System.out.println(is(Byte.MAX_VALUE % Integer.MAX_VALUE));
System.out.println(is(Byte.MAX_VALUE % Long.MAX_VALUE));System.out.println(is(Byte.MAX_VALUE % (byte) 2));
System.out.println(is(Short.MAX_VALUE % (byte) 2));
System.out.println(is(Character.MAX_VALUE % (byte) 2));
System.out.println(is(Integer.MAX_VALUE % (byte) 2));
System.out.println(is(Long.MAX_VALUE % (byte) 2));
版画
int: 0
int: 127
int: 127
int: 127
long: 127
int: 1
int: 1
int: 1
int: 1
long: 1
如果将X
乘以一个数字,结果将不会比X
宽/大,只能变小。 但是,捷豹路虎say
必须扩大范围。 如果将X
乘以一个byte
,则结果只能在一个byte
的范围内。
我还提到了一元运算,也许最简单的是一元减号。
System.out.println(is(-Byte.MIN_VALUE));
System.out.println(is(-Short.MIN_VALUE));
System.out.println(is(-Character.MIN_VALUE));
System.out.println(is(-Integer.MIN_VALUE));
System.out.println(is(-Long.MIN_VALUE));
版画
int: 128
int: 32768
int: 0
int: -2147483648
long: -9223372036854775808
在前三种情况下,类型扩大了。 一个byte
可以扩大到short
,但是作为一个int
是正确的。 但是对于int
和long
,它并没有扩大,您可能会遇到罕见的溢出。
一元奇数是一元加号,它不会更改值(因此无法更改其范围),但可以扩大值。
System.out.println(is(+Byte.MIN_VALUE));
System.out.println(is(+Short.MIN_VALUE));
System.out.println(is(+Character.MIN_VALUE));
System.out.println(is(+Integer.MIN_VALUE));
System.out.println(is(+Long.MIN_VALUE));
版画
int: -128
int: -32768
int: 0
int: -2147483648
long: -9223372036854775808
我们可以解决这个问题吗?
不幸的是没有。 有太多代码依赖于此逻辑。 例如说你写这样的东西。
long i = ...
byte b = ...
long l = i % b + Integer.MAX_VALUE;
如果i%b要从long
变为byte
,则此表达式可能会溢出。
结论
Java可以在需要时扩展某些值,但也不能扩展某些int
操作,这实际上应该很long
。 即使这可能更合乎逻辑,它也永远不会给出更窄的结果。
我们需要做的是了解边缘情况,尤其是int * int
,并在看到这样的操作时知道自己扩大它们。 例如
long l = (long) a * b;
除非我们确信a * b
将适合int
值。
翻译自: https://www.javacodegeeks.com/2015/02/inconsistent-operation-widen-rules-java.html
java 不规则 拼图