Câu hỏi Thay đổi hành vi để có thể mất chính xác


Trong Java, khi bạn làm

int b = 0;
b = b + 1.0;

Bạn nhận được một lỗi có thể có của lỗi chính xác. Nhưng tại sao nếu bạn làm

int b = 0;
b += 1.0;

Không có lỗi gì?


30
2018-04-23 07:08


gốc


Có lẽ, và chỉ có thể là vì trước đây nó chuyển đổi b thành dấu phẩy động, sau đó thêm, sau đó chuyển nó trở về số nguyên? Và sau này nó có thể được chuyển đổi 1.0 để số nguyên thay vào đó, và làm bổ sung số nguyên? Chỉ là một đoán mặc dù. - Francisco Soto


Các câu trả lời:


Đó là bởi vì b += 1.0; tương đương với b = (int) ((b) + (1.0));. Các thu hẹp chuyển đổi nguyên thủy (JLS 5.1.3) được ẩn trong thao tác gán ký tự.

JLS 15.26.2 Toán tử chuyển nhượng hợp chất (JLS Phiên bản thứ ba):

Biểu thức gán phức hợp của biểu mẫu E1 op = E2 tương đương với E1 = (T) ((E1) op (E2)), Ở đâu T là loại E1, ngoại trừ việc E1 chỉ được đánh giá một lần.

Ví dụ, mã sau đây là chính xác:

short x = 3;
x += 4.6;

và kết quả trong x có giá trị 7 bởi vì nó tương đương với:

short x = 3;
x = (short)(x + 4.6);

Điều này cũng giải thích tại sao mã sau đây biên dịch:

byte b = 1;
int x = 5;
b += x; // compiles fine!

Nhưng điều này không:

byte b = 1;
int x = 5;
b = b + x; // DOESN'T COMPILE!

Bạn cần phải cast rõ ràng trong trường hợp này:

byte b = 1;
int x = 5;
b = (byte) (b + x); // now it compiles fine!

Cần lưu ý rằng diễn viên tiềm ẩn trong các bài tập ghép là chủ đề của Câu đố 9: Tweedledum từ cuốn sách tuyệt vời Trình gỡ rối Java. Dưới đây là một số trích đoạn từ cuốn sách (hơi chỉnh sửa cho ngắn gọn):

Nhiều lập trình viên nghĩ rằng x += i; chỉ đơn giản là viết tắt của x = x + i;. Điều này không hoàn toàn đúng: nếu loại kết quả rộng hơn biến đó, toán tử gán ký tự thực hiện chuyển đổi nguyên thủy thu hẹp im lặng.

Để tránh những điều bất ngờ khó chịu, không sử dụng toán tử gán phức hợp trên các biến kiểu  byte, short, hoặc là char. Khi sử dụng toán tử gán ghép trên các biến kiểu int, đảm bảo rằng biểu thức ở phía bên tay phải không thuộc loại long, float, hoặc là double. Khi sử dụng toán tử gán ghép trên các biến kiểu float, đảm bảo rằng biểu thức ở phía bên tay phải không thuộc loại double. Những quy tắc này là đủ để ngăn trình biên dịch tạo ra các phôi thu hẹp nguy hiểm.

Đối với các nhà thiết kế ngôn ngữ, có thể là một sai lầm đối với các toán tử gán phức để tạo ra các phôi vô hình; các phép gán phức hợp trong đó biến có loại hẹp hơn kết quả của phép tính có lẽ là bất hợp pháp.

Đoạn cuối cùng đáng chú ý: C # nghiêm ngặt hơn nhiều về vấn đề này (xem Đặc tả ngôn ngữ C # 7.13.2 Phân công hợp chất).


34
2018-04-23 07:12



Cảm ơn. Thật khó để tìm kiếm tài liệu khi từ khóa bạn muốn sử dụng giống như "+ =". : P - szupie
Tất cả các op= các toán tử được gọi là "phân bổ hợp chất" trong Java. Nhưng có, tôi nghĩ rằng truy vấn cho các biểu tượng thay vì từ khóa là khó khăn trong hầu hết các công cụ tìm kiếm. - polygenelubricants
Có ai ở đây không? Tôi muốn một hộp tìm kiếm cũng đưa vào các biểu tượng tài khoản như + = <và> :) - extraneon
Vâng, tôi muốn có một cách để sử dụng google thường xuyên với các biểu thức thông thường như trong tìm kiếm mã google. Nhưng sau đó một lần nữa, họ sẽ cần phải thay đổi toàn bộ hệ thống lập chỉ mục của họ. - szupie
Tôi vừa bị bắt bởi hành vi này, và đang băn khoăn tại sao Các nhà thiết kế Java đã thêm chuyển đổi ngầm này? Lợi ích của việc làm theo cách này là gì? Có vẻ quá lạ để chủ động thêm vào hành vi phụ mà không có lộn ngược ... - mallardz