ทำไม“ สั้นสามสิบ = 3 * 10” จึงเป็นการมอบหมายงานตามกฎหมาย


103

หากshortได้รับการเลื่อนตำแหน่งโดยอัตโนมัติintในการคำนวณทางคณิตศาสตร์เหตุใดจึงเป็น:

short thirty = 10 * 3;

การมอบหมายทางกฎหมายให้กับshortตัวแปรthirty?

ในทางกลับกันสิ่งนี้:

short ten = 10;
short three = 3;
short thirty = ten * three; // DOES NOT COMPILE AS EXPECTED

เช่นเดียวกับสิ่งนี้:

int ten = 10;
int three = 3;
short thirty = ten * three; // DOES NOT COMPILE AS EXPECTED

คอมไพล์ไม่ได้เนื่องจากไม่อนุญาตให้กำหนดintค่าให้กับ a shortโดยไม่แคสต์ตามที่คาดไว้

มีอะไรพิเศษเกี่ยวกับตัวอักษรตัวเลขหรือไม่?


23
short thirty = 10 * 3;ส่วนใหญ่อาจถูกแทนที่ด้วยshort thirty = 30;คอมไพเลอร์ซึ่งเป็นคำสั่งที่ถูกต้อง (ฉันต้องค้นหาส่วน JLS ที่เกี่ยวข้อง)
Thomas

คอมไพลเลอร์จะคำนวณ10 * 3และเริ่มต้นตัวแปรด้วยผลลัพธ์ ในตัวอย่างที่ไม่ทำงานของคุณการคำนวณจะเกิดขึ้นที่รันไทม์โดยที่ JVM ร่ายสั้น
Felix

ผมคิดว่านี่เป็นซ้ำของstackoverflow.com/questions/30346587/java-char-to-byte-castingหรือstackoverflow.com/questions/9379983/... อย่างไรก็ตาม: โปรดทราบว่าfinal int ten = 10; final int three = 3; short thirty = ten * three;คอมไพล์ได้ดี
Marco13

7
If short is automatically promoted to int in arithmetic operations- ไม่เกี่ยวข้อง ทั้ง10มิได้3เป็นกางเกงขาสั้นหรือพวกเขาเลื่อนตำแหน่งที่พวกเขากำลังอักษร
Matthew อ่าน

@MatthewRead: แต่ถึงแม้จะเป็นตัวอักษรพวกเขาก็ต้องได้รับการประเมินเป็นประเภทข้อมูลโดยเฉพาะใช่ไหม? ดังนั้นจึงเป็นความจริง10และ3ถูกประเมินintโดยคอมไพเลอร์หรือไม่?
LarsH

คำตอบ:


139

เนื่องจากคอมไพเลอร์แทนที่10*3ด้วย 30 ในเวลาคอมไพล์นั่นเอง ดังนั้นอย่างมีประสิทธิภาพ: short thirty = 10 * 3คำนวณในเวลาคอมไพล์

ลองเปลี่ยนtenและthreeเป็นfinal short(ทำให้รวบรวมค่าคงที่ของเวลา) แล้วดูว่าจะเกิดอะไรขึ้น: P

ตรวจสอบไบต์โค้ดโดยใช้javap -v สำหรับการตรวจสอบทั้งสอง ( 10*3และfinal short) คุณจะสามารถเห็นได้ว่ามีความแตกต่างเพียงเล็กน้อย

โอเคนี่คือความแตกต่างของรหัสไบต์สำหรับกรณีต่างๆ

กรณีที่ -1:

รหัส Java: main () {short s = 10 * 3; }

รหัสไบต์:

stack=1, locals=2, args_size=1
         0: bipush        30  // directly push 30 into "s"
         2: istore_1      
         3: return   

กรณีที่ -2:

public static void main(String arf[])  {
   final short s1= 10;
   final short s2 = 3;
   short s = s1*s2;
}

รหัสไบต์:

  stack=1, locals=4, args_size=1
         0: bipush        10
         2: istore_1      
         3: iconst_3      
         4: istore_2      
         5: bipush        30 // AGAIN, push 30 directly into "s"
         7: istore_3      
         8: return   

กรณีที่ -3:

public static void main(String arf[]) throws Exception {
     short s1= 10;
     short s2 = 3;
     int s = s1*s2;
}

ไบต์รหัส:

stack=2, locals=4, args_size=1
         0: bipush        10  // push constant 10
         2: istore_1      
         3: iconst_3        // use constant 3 
         4: istore_2      
         5: iload_1       
         6: iload_2       
         7: imul          
         8: istore_3      
         9: return 

ในกรณีข้างต้น10และ3นำมาจากตัวแปรโลคัลs1และs2


17
ชอบTry changing ten and three to final shortออกกำลังกาย :)
Sergey Pauk

1
@SergeyPauk - นั่นสำคัญมากในการทำความเข้าใจค่าคงที่ของเวลาในการคอมไพล์ .. ใช้ได้กับดั้งเดิมทั้งหมด (สตริงด้วย .. ) :)
TheLostMind

1
@TheLostMind ฉันขอแนะนำให้ใช้ถ้อยคำที่ดีกว่าyou will see that there's no difference (between those two lines in the decompiled code)นี้ไม่ใช่ประเด็นของคุณหรือ
Sergey Pauk

4
น่าขบขันนี่ก็หมายความว่าcase 10*3:และสิ่งที่คล้ายกันนั้นถูกกฎหมายในโครงสร้างสวิตช์
เพดานตุ๊กแก

5
และในทำนองเดียวกันในโครงสร้าง enum ในความเป็นจริงการใช้สิ่งต่างๆเช่น 1 << 5 สำหรับค่าคงที่ bitfield enum เป็นสำนวน
Bathsheba

18

ใช่มีบางอย่างพิเศษเกิดขึ้นกับกรณีตามตัวอักษร: 10 * 3จะได้รับการประเมินในเวลาคอมไพล์ ดังนั้นคุณไม่จำเป็นต้องมี(short)การแปลงอย่างชัดเจนสำหรับตัวอักษรคูณ

ten * three ไม่สามารถประเมินเวลาคอมไพล์ได้ดังนั้นจึงจำเป็นต้องมีการแปลงอย่างชัดเจน

มันจะเป็นเรื่องที่แตกต่างกันถ้าtenและถูกทำเครื่องหมายthreefinal


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