ทำไม“ int i = 2147483647 + 1;” ตกลง แต่“ ไบต์ b = 127 + 1;” คอมไพล์ไม่ได้?


126

ทำไมถึงint i = 2147483647 + 1;ตกลง แต่คอมbyte b = 127 + 1;ไพล์ไม่ได้


16
ฉันก็สงสัยเหมือนกันว่าทำไมbyteประเภทข้อมูลถึงเจ็บปวดขนาดนี้!
BoltClock

9
มันเป็นความผิดพลาดในการออกแบบที่byteเซ็นชื่อแทนการไม่ได้ลงนาม
ปฏิเสธไม่ได้

4
@BoltClock เป็นเพียงความเจ็บปวดเมื่อคุณไม่รู้วิธีใช้อย่างถูกต้อง stackoverflow.com/questions/397867/…
starblue

2
@starblue มีตัวอย่างในชีวิตจริงที่ใช้ประเภท Java byte หรือไม่?
Thorbjørn Ravn Andersen

หากมีข้อมูลที่ระบุเป็นไบต์ให้ใช้ Java byteเพื่อความชัดเจนเช่นในพารามิเตอร์ ในกรณีนี้การที่คุณไม่สามารถกำหนดintค่าได้จะทำให้เกิดข้อบกพร่องบางอย่าง หรือใช้byteเพื่อประหยัดพื้นที่ในอาร์เรย์ ฉันจะไม่ใช้byteสำหรับค่าเดียวที่พอดีกับไบต์
starblue

คำตอบ:


172

ค่าคงที่ได้รับการประเมินเป็น int ดังนั้นจึง2147483647 + 1ล้นและให้ int ใหม่ซึ่งสามารถกำหนดให้intได้ในขณะที่127 + 1ประเมินว่าintเท่ากับ128และไม่สามารถกำหนดให้byteได้


10
อันที่จริงวันนี้ฉันอ่านปริศนาJavaบางส่วนรวมถึงปริศนาเกี่ยวกับเรื่องนั้น ... ดูที่นี่: javapuzzlers.com/java-puzzlers-sampler.pdf - ปริศนา 3
MByD

3
ปัญหาคือประเภทintเนื่องจากการส่งเสริมตัวเลขไบนารีค่า127คือปลาชนิดหนึ่งสีแดง
starblue

ฉันต้องการให้ค่าคงที่ถูกประเมินด้วยความแม่นยำไม่มีที่สิ้นสุดและยังให้ข้อผิดพลาดกับ int i = 2147483647 + 1
Eduardo

@MByD: ตามที่คุณพูด " while 127 + 1 also evaluated as int equals to 128, and it is not assignable to byte." หมายความว่า 50 + 1 จะได้รับการประเมินbyteและด้วยเหตุนี้จึงมอบหมายให้byte?
Bhushan

1
@ 10101010 - ไม่ตรง จะกำหนดให้เป็นไบต์ แต่ก่อนอื่น (ตามมาตรฐาน) จะได้รับการประเมินเป็น int
MByD

35

ลิเทอรัล 127 หมายถึงค่าชนิด int ลิเทอรัล 1 ก็เช่นกันผลรวมของทั้งสองนี้คือจำนวนเต็ม 128 ปัญหาในกรณีที่สองคือคุณกำหนดค่านี้ให้กับตัวแปรชนิดไบต์ ไม่มีอะไรเกี่ยวข้องกับค่าจริงของนิพจน์ มันเกี่ยวข้องกับ Java ที่ไม่สนับสนุนการบังคับ (*) คุณต้องเพิ่มตัวพิมพ์

byte b = (byte)(127 + 1);

จากนั้นจะรวบรวม

(*) อย่างน้อยก็ไม่ใช่ประเภท String-to-integer, float-to-Time, ... Java สนับสนุนการบีบบังคับถ้าเป็นในแง่หนึ่งคือไม่สูญเสีย (Java เรียกสิ่งนี้ว่า "widening")

และไม่คำว่า "บีบบังคับ" ไม่จำเป็นต้องแก้ไข มันถูกเลือกอย่างตั้งใจและถูกต้องในตอนนั้น จากแหล่งข้อมูลที่ใกล้เคียงที่สุด (Wikipedia): "ในภาษาส่วนใหญ่คำว่า coercion ใช้เพื่อแสดงถึงการแปลงโดยนัยไม่ว่าจะในระหว่างการรวบรวมหรือในระหว่างรันไทม์" และ "ในวิทยาการคอมพิวเตอร์การแปลงประเภทการพิมพ์และการบีบบังคับคือวิธีการที่แตกต่างกันทั้งโดยปริยายหรือโดยชัดแจ้งในการเปลี่ยนเอนทิตีของข้อมูลประเภทหนึ่งไปเป็นอีกประเภทหนึ่ง"


ตัวอย่างโค้ดของคุณควรเป็นไบต์ b = (ไบต์) 127 + 1; ซึ่งก็คือ 'Add 1 to a maxed out byte value' ตัวอย่างของคุณจะเปลี่ยนค่า int ของ 128 ให้เป็นค่าไบต์
NKCSS

6
@NKCSS - ฉันคิดว่าคุณไม่ถูกต้องนี่ - (byte)(127 + 1)โยน 128 (จำนวนเต็ม) ไปยังไบต์ในขณะที่สิ่งนี้(byte)127 + 1ส่ง 127 เป็นไบต์ แต่จากนั้นก็เป็น int อีกครั้งเนื่องจากเพิ่มเป็น 1 (int) และคุณ รับ 128 (int) และข้อผิดพลาดยังคงอยู่
MByD

6

เพื่อเป็นหลักฐานในการ @MByD:

รหัสต่อไปนี้รวบรวม:

byte c = (byte)(127 + 1);

เพราะแม้ว่าการแสดงออก(127 + 1)เป็น int และเกินขอบเขตออกประเภทผลที่ได้คือการหล่อbyte การแสดงออกนี้ผลิตbyte-128


3

JLS3 # 5.2 การแปลงการมอบหมาย

(ตัวแปร = นิพจน์)

นอกจากนี้ถ้านิพจน์เป็นนิพจน์คงที่ (§15.28) ของไบต์ชนิดสั้นถ่านหรือ int:

อาจใช้การแปลงแบบดั้งเดิมที่แคบลงหากประเภทของตัวแปรเป็นไบต์สั้นหรืออักขระและค่าของนิพจน์คงที่สามารถแสดงได้ในประเภทของตัวแปร


หากไม่มีข้อนี้เราจะไม่สามารถเขียนได้

byte x = 0;
char c = 0;

แต่เราควรจะทำได้ไหม ฉันไม่คิดอย่างนั้น มีเวทมนตร์บางอย่างที่เกิดขึ้นในการเปลี่ยนใจเลื่อมใสในยุคดึกดำบรรพ์เราต้องระวังให้มาก ฉันจะออกไปจากทางที่จะเขียน

byte x = (byte)0;

สำหรับคำถามที่เราควรจะทำได้ ... ฉันไม่เห็นอะไรผิดปกติbyte x = 0แต่แล้วอีกครั้งฉันเป็นโปรแกรมเมอร์ C
Grady Player

ฉันอาจเห็นอาร์กิวเมนต์เทียบกับ char c = 0 แต่ทำไมไบต์ x = 0 จึงผิด
Michael Burge

มันทำให้เข้าใจผิดสำหรับสายตาที่ไม่ได้รับการฝึกฝนคิดว่าพวกเขากำลังกำหนดไบต์ 0 ให้กับตัวแปรไบต์ ตัวอย่างนี้ไม่ได้รับอันตรายมากนัก แต่โดยทั่วไปการทำงานบน byte / short / char อาจทำให้เกิดความสับสนได้เนื่องจากการแปลงโดยปริยาย มีความซับซ้อนมากกว่าที่ผู้คนจะคิด ฉันต้องการความชัดเจนมากที่สุดในรหัสของฉันอย่าแนะนำความไม่แน่นอนใด ๆ เพื่อประโยชน์ในการประหยัดจังหวะสำคัญบางอย่าง
ปฏิเสธได้

กฎที่คล้ายกันนี้ใช้หรือไม่เมื่อการแปลงแบบดั้งเดิมที่ จำกัด จาก long ไปเป็น int เช่น int i = 1 + 0L เพียงแค่ถามเพราะข้อความที่คุณยกมาทำให้ไม่ชัดเจน
Erwin Smout

@ เออร์วินไม่int i=0Lผิดกฎหมาย
ปฏิเสธไม่ได้
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.