直到今天,我认为例如:
i += j;
只是一个捷径:
i = i + j;
但是如果我们试试这个:
int i = 5;
long j = 8;
然后 i = i + j;
将无法编译,但 i += j;
将正常编译。
这是否意味着实际上 i += j;
是类似 i = (type of i) (i + j)
的快捷方式?
i+=(long)j;
甚至可以正常编译。
i += (int) f;
在加法之前强制转换 f,因此它不等价。 (int) i += f;
在赋值后转换结果,也不等价。没有地方可以放置一个表示您想要在添加之后但在分配之前强制转换值的转换。
与这些问题一样,JLS 给出了答案。在这种情况下 §15.26.2 Compound Assignment Operators。提取物:
E1 op= E2 形式的复合赋值表达式等价于 E1 = (T)((E1) op (E2)),其中 T 是 E1 的类型,除了 E1 只计算一次。
引用自 §15.26.2 的示例
[...] 以下代码是正确的:short x = 3; x += 4.6;并导致 x 的值为 7,因为它等价于:short x = 3; x = (短)(x + 4.6);
换句话说,你的假设是正确的。
这种转换的一个很好的例子是使用 *= 或 /=
byte b = 10;
b *= 5.7;
System.out.println(b); // prints 57
或者
byte b = 100;
b /= 2.5;
System.out.println(b); // prints 40
或者
char ch = '0';
ch *= 1.1;
System.out.println(ch); // prints '4'
或者
char ch = 'A';
ch *= 1.5;
System.out.println(ch); // prints 'a'
A
;)
ch += 32
=D
非常好的问题。 Java Language specification 确认您的建议。
例如下面的代码是正确的:short x = 3; x += 4.6;并导致 x 的值为 7,因为它等价于:short x = 3; x = (短)(x + 4.6);
double->float
视为扩展,因为 float
类型的值识别实数的具体程度低于 double
类型的值。如果将 double
视为完整的邮政地址,将 float
视为 5 位邮政编码,则可以满足对给定完整地址的邮政编码的请求,但无法准确指定完整的邮政编码请求只给出邮政编码的地址。将街道地址转换为邮政编码是一项有损操作,但是...
float->double
转换相当于将美国邮政编码 90210 转换为“US Post Office, Beverly Hills CA 90210”。
是的,
基本上当我们写
i += l;
编译器将其转换为
i = (int)(i + l);
我刚刚检查了 .class
文件代码。
真的很高兴知道
如果是 i = i + l
,您需要从 long
转换为 int
explicitly
,然后它将编译并给出正确的输出。喜欢
i = i + (int)l;
或者
i = (int)((long)i + l); // this is what happens in case of += , dont need (long) casting since upper casting is done implicitly.
但在 +=
的情况下,它工作得很好,因为运算符隐式地将类型转换从右变量的类型转换为左变量的类型,因此不需要显式转换。
int
的强制转换是在 +
之后 执行的。如果确实将 long
转换为 int
,编译器会(应该?)抛出警告。
这里的问题涉及类型转换。
当你添加 int 和 long 时,
int 对象被转换为 long 并且两者都被添加并且你得到 long 对象。但长对象不能隐式转换为 int。所以,你必须明确地这样做。
但是 +=
的编码方式使其可以进行类型转换。 i=(int)(i+m)
在 Java 中,当赋值操作右侧的表达式类型可以安全地提升为赋值左侧变量的类型时,会自动执行类型转换。因此我们可以安全地分配:
byte -> short -> int -> long -> float -> double.
反过来也行不通。例如,我们不能自动将 long 转换为 int,因为第一个比第二个需要更多的存储空间,因此可能会丢失信息。要强制进行此类转换,我们必须执行显式转换。
Type - Conversion
long
比 float
大 2 倍。
float
不能保存所有可能的 int
值,double
不能保存所有可能的 long
值。
double d=33333333+1.0f;
,即使结果 33333332.0 可能不是预期的结果(顺便提一下,33333334.0f 的算术正确答案可以表示为 float
或 int
)。
有时,这样的问题可以在面试中被问到。
例如,当你写:
int a = 2;
long b = 3;
a = a + b;
没有自动类型转换。在 C++ 中编译上述代码不会有任何错误,但在 Java 中您会得到类似 Incompatible type exception
的内容。
因此,为避免这种情况,您必须像这样编写代码:
int a = 2;
long b = 3;
a += b;// No compilation error or any exception due to the auto typecasting
op
使用与 Java 中的使用进行比较的见解。我总是喜欢看到这些琐事,而且我确实认为它们对可能经常被忽略的对话做出了贡献。
主要区别在于,使用 a = a + b
,没有进行类型转换,因此编译器会因为你没有进行类型转换而生气。但是对于 a += b
,它真正做的是将 b
类型转换为与 a
兼容的类型。所以如果你这样做
int a=5;
long b=10;
a+=b;
System.out.println(a);
你真正在做的是:
int a=5;
long b=10;
a=a+(int)b;
System.out.println(a);
微妙的点在这里...
当 j
是 double 且 i
是 int 时,i+j
存在隐式类型转换。 Java ALWAYS 在整数之间存在运算时会将整数转换为双精度数。
为了澄清 i+=j
,其中 i
是整数,j
是双精度可以描述为
i = <int>(<double>i + j)
请参阅:this description of implicit casting
为了清楚起见,在这种情况下,您可能需要将 j
类型转换为 (int)
。
int someInt = 16777217; float someFloat = 0.0f; someInt += someFloat;
。向 someInt
添加零不应影响其值,但将 someInt
提升为 float
可能会更改其值。
这是一个技术性的答案,但您可能想知道为什么会这样。好吧,让我们考虑以下程序。
public class PlusEquals {
public static void main(String[] args) {
byte a = 1;
byte b = 2;
a = a + b;
System.out.println(a);
}
}
这个程序打印什么?
你猜对了3?太糟糕了,这个程序不会编译。为什么?好吧,在 Java is defined to return an int
中添加字节也是如此。我相信这是因为 Java 虚拟机没有定义字节操作来保存字节码(毕竟这些字节码的数量有限),而是使用整数操作是一种语言中公开的实现细节。
但是,如果 a = a + b
不起作用,这意味着如果将 E1 += E2
定义为 E1 = E1 + E2
,则 a += b
将永远无法用于字节。正如前面的例子所示,情况确实如此。作为使 +=
运算符适用于字节和短裤的一种技巧,其中涉及到隐式转换。这并不是什么大问题,但在 Java 1.0 工作期间,重点是从一开始就发布该语言。现在,由于向后兼容,Java 1.0 中引入的这个 hack 无法删除。
不定期副业成功案例分享
i+=j
在我检查自己时编译,但它会导致精度损失,对吧?如果是这样,为什么它不允许它也发生在 i=i+j 中?为什么要在那里打扰我们?i += j
),与另一种情况下(i = i + j
)相比,假设精度损失是需要的更安全