Câu hỏi Tại sao các toán tử gán + =, - =, * =, / = của Java không yêu cầu truyền?


Cho đến hôm nay, tôi nghĩ rằng ví dụ:

i += j;

chỉ là một phím tắt cho:

i = i + j;

Nhưng nếu chúng ta thử điều này:

int i = 5;
long j = 8;

Sau đó i = i + j; sẽ không biên dịch nhưng i += j; sẽ biên dịch tốt.

Nó có nghĩa là trên thực tế i += j; là một phím tắt cho một cái gì đó như thế này i = (type of i) (i + j)?


3286
2018-01-03 10:10


gốc


Tôi ngạc nhiên Java cho phép điều này, là một ngôn ngữ chặt chẽ hơn so với người tiền nhiệm của nó. Lỗi trong quá trình truyền có thể dẫn đến hỏng hóc nghiêm trọng, như trường hợp với Ariane5 Flight 501, trong đó một phao nổi 64 bit với số nguyên 16 bit dẫn đến sự cố. - SQLDiver
Trong một hệ thống điều khiển bay được viết bằng Java, điều này sẽ là ít lo lắng nhất của bạn @SQLDiver - Ross Drew
Có thể trùng lặp Sự khác biệt giữa + = 10 và a = a + 10 trong java? - phuclv
Thực ra i+=(long)j; thậm chí sẽ biên dịch tốt. - Tharindu
Tôi nghĩ rằng Douglas Crockford thắng cuộc tranh luận sau khi tất cả ... Hành vi này là khủng khiếp và rất nhiều ngôn ngữ có vấn đề tương tự xung quanh chuyển đổi. - Aluan Haddad


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


Như thường lệ với những câu hỏi này, JLS giữ câu trả lời. Trong trường hợp này §15.26.2 Nhà điều hành hợp nhất. Trích:

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.

Một ví dụ được trích dẫn từ §15.26.2

[...] đoạn mã sau là đúng:

short x = 3;
x += 4.6;

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

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

Nói cách khác, giả định của bạn là chính xác.


2212
2018-01-03 10:15



Vì thế i+=j biên dịch như tôi đã kiểm tra bản thân mình, nhưng nó sẽ dẫn đến mất quyền chính xác? Nếu đó là trường hợp, tại sao nó không cho phép nó xảy ra trong i = i + j? Tại sao lỗi chúng ta ở đó? - bad_keypoints
@ronnieaka: Tôi đoán rằng các nhà thiết kế ngôn ngữ cảm thấy rằng trong một trường hợp (i += j), nó là an toàn hơn để giả định rằng sự mất chính xác là mong muốn như trái ngược với trường hợp khác (i = i + j) - Lukas Eder
Không, ngay tại đó, trước mặt tôi! Xin lỗi tôi đã không nhận thấy nó trước đó. Như trong câu trả lời của bạn, E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)), do đó, đó là loại giống như tiềm ẩn xuống typecasting (xuống từ dài đến int). Trong khi i = i + j, chúng ta phải làm điều đó một cách rõ ràng, tức là, cung cấp (T) một phần trong E1 = ((E1) op (E2)) Phải không? - bad_keypoints
Tôi cho rằng điều này được sử dụng để tránh một diễn viên rõ ràng và / hoặc f postfix trong tình huống thêm một chữ kép vào một đoạn ngắn? - Andrey Akhmetov
Một lý do có thể giải thích tại sao trình biên dịch Java thêm một kiểu định kiểu là vì nếu bạn đang cố gắng thực hiện số học trên các kiểu không tương thích, không có cách nào để thực hiện việc định kiểu kết quả bằng cách sử dụng biểu mẫu hợp đồng. Một kết quả đánh máy của kết quả nói chung chính xác hơn là một định dạng của đối số có vấn đề. Không có typecast sẽ làm cho sự co rút vô ích khi sử dụng các loại không tương thích, vì nó sẽ luôn luôn gây ra trình biên dịch để ném ra một lỗi. - ThePyroEagle


Một ví dụ điển hình về việc truyền này đang sử dụng * = hoặc / =

byte b = 10;
b *= 5.7;
System.out.println(b); // prints 57

hoặc là

byte b = 100;
b /= 2.5;
System.out.println(b); // prints 40

hoặc là

char ch = '0';
ch *= 1.1;
System.out.println(ch); // prints '4'

hoặc là

char ch = 'A';
ch *= 1.5;
System.out.println(ch); // prints 'a'

442
2018-01-03 10:20



@SajalDutta Tôi không nhận được tài liệu tham khảo đó. Tâm giải thích? - Akshat Agarwal
@AkshatAgarwal ch là một char. 65 * 1.5 = 97.5 -> OK? - Sajal Dutta
Vâng, nhưng tôi chỉ có thể thấy một số người mới bắt đầu đến đây, đọc này, và đi xa nghĩ rằng bạn có thể chuyển đổi bất kỳ ký tự nào từ chữ hoa sang chữ thường bằng cách nhân nó với 1,5. - Dawood ibn Kareem
@DavidWallace Bất kỳ nhân vật nào miễn là nó A ;) - Peter Lawrey
@PeterLawrey & @DavidWallace Tôi sẽ tiết lộ bí mật- - ch += 32  = D - Minhas Kamal


Câu hỏi rất hay. Các Đặc tả ngôn ngữ Java xác nhận đề xuất của bạ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 vì nó tương đương với:

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

223
2018-01-03 10:17



Hoặc vui hơn: "int x = 33333333; x + = 1.0f;". - supercat


Vâng,

về cơ bản khi chúng ta viết

i += l; 

trình biên dịch chuyển đổi thành

i = (int)(i + l);

Tôi vừa kiểm tra .class mã tệp.

Thực sự là một điều tốt để biết


163
2018-01-03 10:19



Bạn có thể cho tôi biết classfile này là gì không? - Andrey Akhmetov
@hexafraction: những gì bạn có nghĩa là bởi tập tin lớp học? nếu bạn hỏi về tệp lớp tôi đã đề cập trong bài đăng của tôi thì đó là phiên bản tuân thủ của lớp java của bạn - Umesh Awasthi
Oh, bạn đã đề cập đến "mã" lớp tập tin, dẫn tôi đến tin rằng một classfile cụ thể đã được tham gia. Tôi hiểu ý của bạn bây giờ. - Andrey Akhmetov
Trong tất cả các chữ cái, bạn thực sự đã chọn "l" (chữ thường L) ... - Bogdan Alexandru
@glglgl Tôi không đồng ý rằng người ta nên dựa vào phông chữ để phân biệt trong những trường hợp đó ... nhưng mọi người đều có quyền tự do lựa chọn những gì tốt nhất. - Bogdan Alexandru


bạn cần truyền từ long đến int  explicitly trong trường hợp i = i + l  sau đó nó sẽ biên dịch và cung cấp cho đầu ra chính xác. như

i = i + (int)l;

hoặc là

i = (int)((long)i + l); // this is what happens in case of += , dont need (long) casting since upper casting is done implicitly.

nhưng trong trường hợp += nó chỉ hoạt động tốt bởi vì các nhà điều hành ngầm hoàn toàn không loại đúc từ loại biến bên phải để loại biến trái nên không cần phải đúc một cách rõ ràng.


85
2018-01-03 10:15



Trong trường hợp này, "dàn diễn viên tiềm ẩn" có thể bị mất. Trong thực tế, như @LukasEder nói trong câu trả lời của mình, dàn diễn viên int được thực hiện sau các +. Trình biên dịch sẽ (nên?) Ném một cảnh báo nếu nó thực sự đã bỏ long đến int. - Romain


Vấn đề ở đây liên quan đến việc nhập kiểu.

Khi bạn thêm int và dài,

  1. Các đối tượng int được đúc lâu & cả hai được thêm vào và bạn nhận được đối tượng dài.
  2. nhưng đối tượng dài không thể được ngầm đúc vào int. Vì vậy, bạn phải làm điều đó một cách rõ ràng.

Nhưng += được mã hóa theo cách nó tạo kiểu đúc. i=(int)(i+m)


56
2018-01-03 10:20





Trong các chuyển đổi kiểu Java được thực hiện tự động khi loại biểu thức ở phía bên tay phải của một phép gán có thể được quảng bá một cách an toàn đến kiểu biến ở phía bên tay trái của phép gán. Do đó chúng tôi có thể phân công an toàn:

 byte -> short -> int -> long -> float -> double. 

Điều tương tự cũng không hoạt động theo cách khác. Ví dụ, chúng tôi không thể tự động chuyển đổi một dài thành một int bởi vì đầu tiên yêu cầu lưu trữ nhiều hơn thứ hai và do đó thông tin có thể bị mất. Để ép buộc một chuyển đổi như vậy, chúng ta phải thực hiện một chuyển đổi rõ ràng.
Loại - Chuyển đổi


47
2018-01-23 05:50



Này, nhưng long lớn gấp 2 lần float. - Sarge Borsch
A float không thể giữ mọi thứ có thể int giá trị và double không thể giữ mọi thứ có thể long giá trị. - Alex MDC
Bạn có ý nghĩa gì bởi "chuyển đổi một cách an toàn"? Từ phần sau của câu trả lời tôi có thể suy ra rằng bạn có nghĩa là chuyển đổi tự động (diễn viên ngầm) mà tất nhiên là không đúng trong trường hợp nổi -> dài. float pi = 3,14f; dài b = pi; sẽ dẫn đến lỗi trình biên dịch. - Luke
Bạn sẽ tốt hơn khi phân biệt các kiểu nguyên thủy dấu chấm động với các kiểu số nguyên nguyên thủy. Chúng không giống nhau. - ThePyroEagle
Java có các quy tắc chuyển đổi đơn giản yêu cầu sử dụng các phôi trong nhiều mẫu mà hành vi không có phôi sẽ phù hợp với kỳ vọng, nhưng không yêu cầu phôi trong nhiều mẫu thường sai. Ví dụ, trình biên dịch sẽ chấp nhận double d=33333333+1.0f; mà không có khiếu nại, mặc dù kết quả 33333332.0 có thể sẽ không phải là những gì đã được dự định (ngẫu nhiên, câu trả lời theo số học chính xác của 33333334.0f sẽ được thể hiện như một trong hai float hoặc là int). - supercat


Đôi khi, một câu hỏi như vậy có thể được hỏi tại một cuộc phỏng vấn.

Ví dụ, khi bạn viết:

int a = 2;
long b = 3;
a = a + b;

không có tự động in ấn. Trong C ++ sẽ không có bất kỳ lỗi nào khi biên dịch mã trên, nhưng trong Java bạn sẽ nhận được một cái gì đó như Incompatible type exception.

Vì vậy, để tránh nó, bạn phải viết mã của bạn như thế này:

int a = 2;
long b = 3;
a += b;// No compilation error or any exception due to the auto typecasting

37
2017-12-02 10:40



Cảm ơn sự thấu hiểu về sự so sánh của op sử dụng trong C ++ để sử dụng nó trong Java. Tôi luôn thích nhìn thấy những mẩu thông tin này và tôi nghĩ họ đóng góp một cái gì đó vào cuộc trò chuyện thường có thể bị bỏ quên. - Thomas
Tuy nhiên bản thân câu hỏi Là thú vị, hỏi điều này trong một cuộc phỏng vấn là ngu ngốc. Nó không chứng minh rằng người đó có thể tạo ra một mã chất lượng tốt - nó chỉ chứng minh rằng anh ta có đủ kiên nhẫn để chuẩn bị cho một kỳ thi chứng chỉ Oracle. Và "tránh" các loại không tương thích bằng cách sử dụng chuyển đổi tự động nguy hiểm và do đó ẩn các lỗi tràn có thể xảy ra, thậm chí có thể chứng minh rằng người đó không thể sản xuất một mã có chất lượng tốt có thể xảy ra. Chết tiệt các tác giả Java cho tất cả các chuyển đổi tự động và tự động đấm bốc và tất cả! - Honza Zidek


Sự khác biệt chính là với a = a + b, không có typecasting đang diễn ra, và do đó trình biên dịch tức giận với bạn vì không phải typecasting. Nhưng vơi a += b, những gì nó thực sự làm là typecasting b đến một loại tương thích với a. Vì vậy, nếu bạn làm

int a=5;
long b=10;
a+=b;
System.out.println(a);

Những gì bạn đang thực sự làm là:

int a=5;
long b=10;
a=a+(int)b;
System.out.println(a);

18
2018-06-07 23:27



Các toán tử gán nhiệm vụ thực hiện một chuyển đổi thu hẹp kết quả của phép toán nhị phân, chứ không phải toán hạng bên phải. Vì vậy, trong ví dụ của bạn, 'a + = b' không tương đương với 'a = a + (int) b' nhưng, như được giải thích bởi các câu trả lời khác ở đây, để 'a = (int) (a + b)'. - Lew Bloch