มีความคิดอย่างไรว่าทำไมฉันต้องใส่ลิเทอรัลจำนวนเต็มเป็น (int) ที่นี่


122

ในตัวอย่างต่อไปนี้

int i = -128;
Integer i2 = (Integer) i; // compiles

Integer i3 = (Integer) -128; /*** Doesn't compile ***/

Integer i4 = (Integer) (int) -128; // compiles
Integer i4 = -128; // compiles
Integer i5 = (int) -128; // compiles
Integer i6 = (Integer) (-128); // compiles
Integer i7 = (Integer) 0-128; // compiles

ฉันไม่สามารถโยน-128ด้วยแต่ฉันสามารถโยน(Integer)(int) -128

ฉันมักจะคิดว่า-128เป็นintประเภทและการหล่อด้วย(int)ควรจะซ้ำซ้อน

ข้อผิดพลาดในบรรทัดi3คือ

cannot find symbol variable Integer

ฉันลองใช้กับ Java 6 update 29 และ Java 7 update 1

แก้ไข: คุณจะได้รับพฤติกรรมเดียวกันกับแทน+128 -128ดูเหมือนจะสับสนระหว่างตัวดำเนินการยูนารีและตัวดำเนินการไบนารี


5
คอมไพเลอร์ของคุณคืออะไร? Integer i = -128;สิ่งนี้ควรรวบรวมแม้ว่า
bestsss

wierd Integer i3 = (Integer) (-128);สอดคล้องแม้ว่า
Eng.Fouad

2
@ Eng Fouad, Peter, สัญลักษณ์ยูนารี (+ -) มีการเชื่อมโยงจากขวาไปซ้ายและบวกลบจากซ้ายไปขวา เอฟเฟกต์ของ -128 จะเหมือนกับ +128 และการใส่ 0 ข้างหน้าควรแก้ไขเช่น 0-128 หรือ 0 + 128 (ไม่สามารถทดสอบ atm ได้ แต่ฉันพนันได้เลย)
bestsss

คำถามที่ดี! โดยส่วนตัวแล้วฉันต้องการดูการอ้างอิง JLS สำหรับความละเอียดของตัวดำเนินการยูนารี / ไบนารีและเมื่อนักแสดงถูกถือว่าเป็นนิพจน์ มิฉะนั้นอาจเป็นไปได้ว่าคอมไพเลอร์อื่นไม่ถือว่าเป็นข้อผิดพลาด!
Bringer128

1
นอกจากนี้ยัง FYI ข้อผิดพลาดที่ฉันได้รับใน IDE ของฉันคือExpression expectedที่Integerเป็น
Bringer128

คำตอบ:


151

คอมไพเลอร์พยายามที่จะลบ128จาก(Integer)แทนการหล่อไป-128 Integerเพิ่ม()เพื่อแก้ไข

Integer i3 = (Integer) -128; // doesn't compile
Integer i3 = (Integer) (-128); // compiles

ตามที่ BoltClock แสดงความคิดเห็นว่านักแสดง intทำงานได้ตามที่ตั้งใจไว้เนื่องจากเป็นคำสงวนจึงไม่สามารถตีความเป็นตัวระบุได้ซึ่งเหมาะสมกับฉัน

และ Bringer128 พบ JLS อ้างอิง15.16

 CastExpression:
    (PrimitiveType Dims opt ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

ที่คุณสามารถดูหล่อเป็นชนิดดั้งเดิมต้องใด ๆในขณะที่หล่อชนิดอ้างอิงต้องใช้UnaryExpression UnaryExpressionNotPlusMinusเหล่านี้จะถูกกำหนดไว้ก่อน CastExpression ที่JLS 15.15


31
ฉันคิดว่าเป็นเพราะintเป็นคีย์เวิร์ดใน Java แต่Integerไม่ใช่ เนื่องจากintเป็นคำหลักคุณจึงไม่สามารถใช้เป็นตัวระบุสำหรับตัวแปรหรือคลาสได้โดยเหลือความเป็นไปได้เดียวที่จะเป็นแบบพิมพ์ นั่นจะอธิบายได้
BoltClock

@BoltClock รวมความคิดเห็นของคุณไว้ในคำตอบ
Jens Schauder

3
เพื่อให้เป็นคำตอบที่ยอดเยี่ยมยิ่งขึ้นคุณต้องการเพิ่มลิงก์ของฉันไปยัง JLS หรือไม่
Bringer128

3
ริ้วรอยที่น่าสนใจ (สำหรับฉัน) ในเรื่องนี้คือวิธีที่เราแก้ปัญหาที่คล้ายคลึงกันใน C # ซึ่งยังมีความคลุมเครือในไวยากรณ์ระหว่าง "นิพจน์ที่อยู่ในวงเล็บเป็นตัวถูกดำเนินการกับตัวดำเนินการลบไบนารี" และ "ตัวดำเนินการ cast ที่ตัวถูกดำเนินการด้านขวาของ cast คือ unary ลบนิพจน์ " ดูส่วน 7.7.6 ของข้อกำหนด C # สำหรับคำอธิบายโดยละเอียดเกี่ยวกับการวิเคราะห์พฤติกรรมที่เราใช้เพื่อพยายามอย่างชาญฉลาดเกี่ยวกับการแก้ไขความกว้าง
Eric Lippert

1
@BillK ทำไมถึงพูดแบบนั้น? ข้อกำหนด C # ไม่ได้อ้างถึงตัวดำเนินการมากเกินไปในส่วน 7.7.6 ดังนั้นจึงไม่ใช่ปัญหาสำหรับพวกเขา
Bringer128

48

ฉันพบข้อมูลอ้างอิง JLS 15.16 น .

 CastExpression:
    (PrimitiveType Dims opt ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

ที่คุณสามารถดูหล่อเป็นชนิดดั้งเดิมต้องใด ๆในขณะที่หล่อชนิดอ้างอิงต้องใช้UnaryExpression UnaryExpressionNotPlusMinusเหล่านี้จะถูกกำหนดไว้ก่อน CastExpression ที่JLS 15.15

คุณต้องเปลี่ยนนักแสดงเป็นประเภทดั้งเดิม:

... (int) -128;

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

... (Integer) (-128);  // Either
... (Integer) 0 - 128; // Or

12

คอมไพเลอร์ตีความ-ว่าเป็นตัวดำเนินการลบสองอาร์กิวเมนต์กล่าวคือพยายามลบ 128 ออกจากหมายเลขอื่นที่ชื่อIntegerแต่ไม่มีตัวแปรดังกล่าวในขอบเขต

สิ่งนี้รวบรวม:

Integer i3 = (Integer) (-128)

คุณสามารถเพิ่มความคิดเห็นว่าเหตุใดจึง(int)สร้างความแตกต่าง
Peter Lawrey

1
มันเกิดจากการทำ autoboxing ไม่ใช่เหรอ?
Brian Roach

9

ซึ่งอาจเกี่ยวข้องกับการแยกวิเคราะห์ไวยากรณ์ สังเกตว่า

Integer i4 = (Integer) (-128); 

ใช้งานได้ดี

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

Integer i6 = Integer.valueOf(-128)

1
cast to Integer คือน้ำตาลสังเคราะห์สำหรับ valueOf
bestsss

4
ใช่ แต่บางครั้งน้ำตาลสังเคราะห์ก็ล้มเหลวอย่างละเอียด ฉันมีปัญหาในการติดตามข้อยกเว้นของตัวชี้ว่างในแอปพลิเคชันขนาดใหญ่เนื่องจากการชกมวยอัตโนมัติ เราไปไกลถึงการปฏิบัติต่อการชกมวยอัตโนมัติเป็นข้อผิดพลาดเพื่อรักษาอาการปวดหัวในอนาคต เวทมนตร์เป็นสิ่งที่ดี แต่เมื่อล้มเหลวหัวก็เจ็บ ฉันคิดว่ามันจะดีกว่าที่จะพูดอย่างชัดเจนและช่วยตัวเองไม่ให้ปวดหัว
Krystian Cybulski

NPE เป็น b1tch w / outboxing จริง กรณี Esp เช่น for (int i in Collection<Integer>)b / c NPE อยู่ในตำแหน่งที่ไม่คาดคิดอย่างแน่นอน ฉันไม่ได้ใช้ Integer w / autoboxing เนื่องจากช่วงแคชมีขนาดเล็ก (แม้ว่าจะสามารถเพิ่มได้ด้วยตัวเลือก XX) แต่มีคลาสที่เรียกว่า IntegerProvider (ตั้งแต่ 1.1) เพื่อทำสิ่งเดียวกัน การใช้แผนที่ (ใดก็ได้จาก java.util) จำนวนเต็ม -> สิ่งใด ๆ มักจะเป็นผลการดำเนินงานเว้นแต่จะใช้ในกรณีเล็กน้อยและมักจะมีทางออกที่ดีกว่า
bestsss

การแคสต์ int เป็นจำนวนเต็มไม่สามารถทำให้เกิดข้อผิดพลาดใด ๆ ยกเว้นฮีปล้นบางที ผกผันไม่เป็นความจริงแม้ว่า
Ingo

@MattBall ฉันไม่ค่อยเข้าใจน้ำตาลสังเคราะห์ถูกใช้กันอย่างแพร่หลาย: eggcorns.lascribe.net/forum/viewtopic.php?id=4400และเสียงสังเคราะห์ที่ดีกว่าสำหรับฉัน
bestsss

9

มันแยกเป็นและไม่ได้หาตัวแปรInteger <minus operator> 128 Integerคุณจะต้องห่อ-128ในวงเล็บ:

Integer i3 = (Integer) (-128);  // compiles

ฉันให้ +1 สำหรับคำตอบอื่น ๆ ทั้งหมดเพราะถูกต้องด้วย :)
โบฮีเมียน


6

บรรทัดที่ 3 ถูกตีความว่าคุณพยายามหัก 128 ออกจากนิพจน์ในวงเล็บและนิพจน์ในวงเล็บไม่ใช่และนิพจน์ประเภท int (ถือว่าตัวดำเนินการ '-' เป็น '-') หากคุณเปลี่ยนนิพจน์เป็น:

Integer i3 = (Integer) (-128);

จากนั้นคอมไพเลอร์จะเข้าใจว่า '-' คือยูนารีลบที่ระบุจำนวนเต็มลบ


3

คอมไพเลอร์ C # มีลักษณะการทำงานเหมือนกัน มันให้คำแนะนำที่ดีกว่าว่าทำไมคอมไพล์ถึงล้มเหลว:

หากต้องการใช้ค่าลบคุณต้องใส่ค่าในวงเล็บ

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