ทำไม Java API จึงใช้ int แทนที่จะเป็น short หรือ byte


137

เหตุใด Java API จึงใช้งานintเมื่อshortใดถึงbyteจะเพียงพอ

ตัวอย่าง: DAY_OF_WEEKข้อมูลในระดับการใช้งานCalendarint

หากความแตกต่างน้อยเกินไปทำไมประเภทข้อมูลเหล่านั้น ( short, int) จึงมีอยู่ทั้งหมด

คำตอบ:


166

เหตุผลบางประการได้รับการชี้ให้เห็นแล้ว ตัวอย่างเช่นความจริงที่ว่า"... (เกือบ) การดำเนินงานทั้งหมดในไบต์สั้นจะส่งเสริมพื้นฐานเหล่านี้เพื่อ int" อย่างไรก็ตามคำถามต่อไปอย่างเห็นได้ชัดจะเป็น: ทำไมจะประเภทนี้การเลื่อนตำแหน่งให้int?

ดังนั้นหากต้องการลึกลงไปอีกระดับ: คำตอบอาจเกี่ยวข้องกับชุดคำสั่ง Java Virtual Machine ดังสรุปในตารางใน Java เครื่องเสมือนข้อมูลจำเพาะ , ทั้งหมดดำเนินการทางคณิตศาสตร์ที่สำคัญเช่นการเพิ่มการแบ่งและคนอื่น ๆ จะมีให้เฉพาะสำหรับชนิดintและชนิดlongและไม่ได้สำหรับชนิดที่มีขนาดเล็ก

(กัน: ประเภทที่เล็กกว่า ( byteและshort) มีไว้สำหรับอาร์เรย์เท่านั้นอาร์เรย์เช่นnew byte[1000]จะใช้เวลา 1,000 ไบต์และอาร์เรย์new int[1000]จะมีขนาด 4000 ไบต์)

แน่นอนตอนนี้ใคร ๆ ก็สามารถพูดได้ว่า"... คำถามต่อไปที่เห็นได้ชัดคือ: ทำไมมีคำแนะนำเหล่านี้สำหรับint(และlong) เท่านั้น?" .

เหตุผลหนึ่งที่กล่าวถึงใน JVM Spec ที่กล่าวถึงข้างต้น:

หากคำสั่งที่พิมพ์แต่ละตัวรองรับชนิดข้อมูลรันไทม์ของ Java Virtual Machine ทั้งหมดจะมีคำแนะนำมากกว่าที่จะแสดงเป็นไบต์

นอกจากนี้ Java Virtual Machine ถือได้ว่าเป็นนามธรรมของโปรเซสเซอร์จริง และการแนะนำหน่วยคำนวณทางคณิตศาสตร์เฉพาะสำหรับประเภทขนาดเล็กจะไม่คุ้มค่ากับความพยายาม: มันจะต้องมีทรานซิสเตอร์เพิ่มเติม แต่ก็ยังสามารถทำได้เพียงหนึ่งการเพิ่มในรอบนาฬิกาเดียว สถาปัตยกรรมที่โดดเด่นเมื่อ JVM ได้รับการออกแบบเป็น 32bits เพียงที่เหมาะสมสำหรับ int32bit (การดำเนินการที่เกี่ยวข้องกับlongค่า64 บิตถูกนำมาใช้เป็นกรณีพิเศษ)

(หมายเหตุ: ย่อหน้าสุดท้ายเป็นบิตที่เกินความจริงโดยคำนึงถึง vectorization ที่เป็นไปได้ แต่ควรให้แนวคิดพื้นฐานโดยไม่ต้องดำลึกเข้าไปในหัวข้อการออกแบบตัวประมวลผล)


แก้ไข: ภาคผนวกสั้นโดยเพ่งความสนใจไปที่ตัวอย่างจากคำถาม แต่โดยทั่วไปแล้วเราอาจถามว่ามันจะไม่เป็นประโยชน์ในการจัดเก็บสาขาโดยใช้ประเภทที่มีขนาดเล็กลงหรือไม่ ตัวอย่างเช่นหนึ่งอาจจะคิดว่าหน่วยความจำที่จะถูกบันทึกไว้โดยการจัดเก็บเป็นCalendar.DAY_OF_WEEK byteแต่ที่นี่รูปแบบไฟล์ Java Class มาพร้อมเล่น: ฟิลด์ทั้งหมดในไฟล์คลาสครอบครอง "สล็อต" อย่างน้อยหนึ่งช่องซึ่งมีขนาดเท่ากับหนึ่งint(32 บิต) (ฟิลด์ "wide" doubleและlongใช้สองช่อง) ดังนั้นการประกาศเขตข้อมูลอย่างชัดเจนshortหรือbyteจะไม่บันทึกหน่วยความจำใด ๆ


ฉันเดาว่าเหตุผลที่ว่าทำไมตัวถูกดำเนินการที่ได้รับการเลื่อนตำแหน่งเป็น int นั้นเกี่ยวข้องกับเหตุผลที่ใช้ในC และ C ++
Shafik Yaghmour

@ Marco13 "ดังนั้นการประกาศเขตข้อมูลอย่างชัดเจนว่าสั้นหรือไบต์จะไม่บันทึกหน่วยความจำใด ๆ " มันเป็นเรื่องจริงเหรอ? ฉันไม่คิดว่าถูกต้อง
ACV

@ACV พูดอย่างเคร่งครัดการดำเนินการสามารถเลือกที่จะเก็บรูปแบบกะทัดรัดมากขึ้น แต่รูปแบบที่มีการเปิดเผย "ความจริง" (กล่าวคือโดยเครื่องเสมือน) intจะรักษาค่าว่ามีอย่างน้อยขนาดของ หากคุณมีการอ้างอิงถึงการใช้งานอื่นฉันจะอัปเดตคำตอบและใส่ลิงค์ตาม
Marco13

40

(เกือบ) การดำเนินงานทั้งหมดในbyte, shortจะส่งเสริมให้พวกเขาintตัวอย่างเช่นคุณไม่สามารถเขียน:

short x = 1;
short y = 2;

short z = x + y; //error

การคิดเลขทำได้ง่ายและตรงไปตรงมาเมื่อใช้intงานไม่จำเป็นต้องร่าย

ในแง่ของพื้นที่มันสร้างความแตกต่างน้อยมาก byteและshortจะทำให้สิ่งต่าง ๆ ยุ่งยากฉันไม่คิดว่าการเพิ่มประสิทธิภาพขนาดเล็กนี้จะคุ้มค่าเพราะเรากำลังพูดถึงตัวแปรจำนวนคงที่

byteมีความเกี่ยวข้องและมีประโยชน์เมื่อคุณตั้งโปรแกรมสำหรับอุปกรณ์ฝังตัวหรือจัดการกับไฟล์ / เครือข่าย ดึกดำบรรพ์เหล่านี้มี จำกัด หากการคำนวณอาจเกินขีด จำกัด ในอนาคต ลองนึกถึงส่วนขยายสำหรับCalendarชั้นเรียนที่อาจมีจำนวนมากขึ้น

นอกจากนี้ยังทราบว่าในการประมวลผล 64 บิตที่ชาวบ้านจะได้รับการบันทึกไว้ในการลงทะเบียนและจะไม่ใช้ทรัพยากรใด ๆ เพื่อให้ใช้int, shortและวิทยาการอื่น ๆ จะไม่สร้างความแตกต่างใด ๆ เลย ยิ่งไปกว่านั้นการใช้งานจาวาจำนวนมากจัดตัวแปร* (และวัตถุ)


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

ในทางกลับกันในอาร์เรย์byteใช้เวลา 1 ไบต์shortใช้เวลา 2 ไบต์และintใช้เวลาสี่ไบต์เพราะในอาร์เรย์เพียงการเริ่มต้นและอาจจะสิ้นสุดของการจัดตำแหน่ง สิ่งนี้จะสร้างความแตกต่างในกรณีที่คุณต้องการใช้ตัวอย่างเช่นSystem.arraycopy()จากนั้นคุณจะสังเกตเห็นความแตกต่างด้านประสิทธิภาพ


1
ข้อเท็จจริงที่สนุกสนาน: หากคุณใช้ตัวดัดแปลงสุดท้ายสำหรับทั้งสองค่ามันจะทำงาน :)
alexander

7

เพราะการคำนวณทางคณิตศาสตร์นั้นง่ายกว่าเมื่อใช้จำนวนเต็มเปรียบเทียบกับกางเกงขาสั้น สมมติว่าค่าคงที่ถูกจำลองตามshortค่าจริง ๆ จากนั้นคุณจะต้องใช้ API ในลักษณะนี้:

short month = Calendar.JUNE;
month = month + (short) 1; // is july

สังเกตเห็นการคัดเลือกนักแสดงที่ชัดเจน ค่าสั้น ๆ จะได้รับการส่งเสริมโดยนัยกับintค่าเมื่อใช้ในการดำเนินการทางคณิตศาสตร์ (บนตัวถูกดำเนินการกางเกงขาสั้นจะแสดงแม้เป็น ints.) มันจะค่อนข้างยุ่งยากในการใช้ซึ่งเป็นเหตุผลที่intค่านิยมมักจะเป็นค่าคงที่

เมื่อเปรียบเทียบกับประสิทธิภาพในการจัดเก็บข้อมูลมีน้อยที่สุดเนื่องจากมีค่าคงที่จำนวนคงที่ เรากำลังพูดถึงค่าคงที่ 40 ค่า การเปลี่ยนการจัดเก็บข้อมูลของพวกเขาจากintไปหากว่าคุณปลอดภัยshort 40 * 16 bit = 80 byteดูคำตอบนี้สำหรับการอ้างอิงเพิ่มเติม


5

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

ดังนั้นเมื่อเราสรุปปัญหาร้ายแรงแล้วคุณคาดหวังว่าจะได้ประโยชน์อะไรจากปรัชญานั้น ฉันจะ unsurprised ถ้าเพียงผลรันไทม์ที่สังเกตของการเปลี่ยนแปลงที่จะเป็นสิ่งที่พิมพ์ที่คุณได้รับเมื่อคุณมองไปคงขึ้นผ่านการสะท้อน (และแน่นอนว่าข้อผิดพลาดใด ๆ ที่ถูกแนะนำโดยโปรแกรมเมอร์ที่ขี้เกียจ / ไม่เจตนานั้นไม่ถูกต้องสำหรับประเภทของค่าคงที่)

การชั่งน้ำหนักข้อดีและข้อเสียนั้นง่ายมาก: มันเป็นปรัชญาที่ไม่ดี


4

ความซับซ้อนในการออกแบบของเครื่องเสมือนเป็นฟังก์ชั่นของการทำงานที่สามารถทำได้ การมีคำแนะนำการใช้งานสี่อย่างเช่น "ทวีคูณ" ง่ายขึ้นแต่ละอันสำหรับจำนวนเต็ม 32 บิต, จำนวนเต็ม 64 บิต, ทศนิยม 32 บิต, และลอยตัว 64 บิตมากกว่าที่จะมี ข้างต้นเวอร์ชันสำหรับประเภทตัวเลขที่เล็กลงเช่นกัน คำถามการออกแบบที่น่าสนใจมากขึ้นคือสาเหตุที่ควรมีสี่ประเภทแทนที่จะน้อยกว่า (ดำเนินการคำนวณจำนวนเต็มทั้งหมดด้วยจำนวนเต็ม 64 บิตและ / หรือทำการคำนวณจุดลอยตัวทั้งหมดด้วยค่าจุดลอยตัว 64 บิต) เหตุผลในการใช้จำนวนเต็ม 32- บิตคือ Java คาดว่าจะทำงานบนแพลตฟอร์มจำนวนมากซึ่งประเภท 32 บิตสามารถดำเนินการได้เร็วเท่ากับชนิด 16 บิตหรือ 8 บิต แต่การดำเนินการกับประเภท 64 บิตจะเห็นได้ชัด ช้าลงเพียง แต่มีชนิด 32 บิต

สำหรับการคำนวณจุดลอยตัวบนค่า 32- บิตข้อดีมีความชัดเจนน้อยลง มีบางแพลตฟอร์มที่มีการคำนวณเช่นนี้float a=b+c+d;สามารถดำเนินการได้อย่างรวดเร็วที่สุดโดยการแปลงตัวถูกดำเนินการทั้งหมดให้เป็นประเภทที่มีความแม่นยำสูงกว่าเพิ่มจากนั้นแปลงผลลัพธ์กลับไปเป็นตัวเลขทศนิยมแบบ 32 บิตสำหรับการจัดเก็บ มีแพลตฟอร์มอื่น ๆ ที่จะมีประสิทธิภาพมากขึ้นในการคำนวณทั้งหมดโดยใช้ค่าทศนิยม 32 บิต ผู้สร้างของ Java ตัดสินใจว่าทุกแพลตฟอร์มควรทำสิ่งเดียวกันและควรสนับสนุนแพลตฟอร์มฮาร์ดแวร์ที่การคำนวณจุดลอยตัวแบบ 32 บิตนั้นเร็วกว่าพีซีทั่วไปแม้ว่าพีซีเครื่องนี้จะลดความเร็วลงอย่างรุนแรง และความแม่นยำของคณิตศาสตร์เลขทศนิยมบนพีซีทั่วไปรวมถึงเครื่องจักรหลายเครื่องที่ไม่มีหน่วยทศนิยม หมายเหตุ btw ซึ่งขึ้นอยู่กับค่าของ b, c และ d โดยใช้การคำนวณระดับกลางที่มีความแม่นยำสูงกว่าเมื่อคำนวณนิพจน์เช่นที่กล่าวไว้ข้างต้นfloat a=b+c+d;บางครั้งจะให้ผลลัพธ์ที่มีความแม่นยำมากกว่าที่จะเป็นจริงของตัวถูกดำเนินการระดับกลางทั้งหมดถูกคำนวณด้วยfloatความแม่นยำ แต่บางครั้งจะให้ค่าซึ่งมีความแม่นยำน้อยกว่าเล็กน้อย ไม่ว่าในกรณีใดซันตัดสินใจทำทุกอย่างด้วยวิธีเดียวกันและเลือกที่จะใช้floatค่าที่มีความแม่นยำน้อยที่สุด

โปรดทราบว่าข้อได้เปรียบหลักของชนิดข้อมูลขนาดเล็กจะปรากฏขึ้นเมื่อเก็บข้อมูลจำนวนมากไว้ด้วยกันในอาร์เรย์ แม้ว่าจะไม่มีข้อได้เปรียบในการมีตัวแปรแต่ละตัวที่มีขนาดเล็กกว่า 64 บิต แต่ก็คุ้มค่าที่จะมีอาร์เรย์ซึ่งสามารถเก็บค่าที่เล็กลงให้กะทัดรัดกว่าได้ การมีตัวแปรโลคัลเป็นbyteมากกว่าการlongบันทึกเจ็ดไบต์ มีอาร์เรย์ 1,000,000 หมายเลขถือแต่ละหมายเลขเป็นbyteมากกว่าlongคลื่น 7,000,000 ไบต์ เนื่องจากแต่ละอาเรย์แต่ละประเภทต้องการสนับสนุนการดำเนินการเพียงไม่กี่อย่าง (โดยเฉพาะอย่างยิ่งการอ่านหนึ่งไอเท็มเก็บหนึ่งไอเท็มคัดลอกช่วงของไอเท็มภายในอาเรย์หรือคัดลอกช่วงของไอเท็มจากหนึ่งอาเรย์หนึ่งไปยังอีก) ประเภทอาเรย์ไม่รุนแรงเท่าความซับซ้อนของการมีค่าตัวเลขที่ไม่ต่อเนื่องที่สามารถใช้งานได้โดยตรงมากขึ้น


2

ที่จริงแล้วมีข้อได้เปรียบเล็กน้อย หากคุณมี

class MyTimeAndDayOfWeek {
    byte dayOfWeek;
    byte hour;
    byte minute;
    byte second;
}

แล้วใน JVM intทั่วไปจะต้องเป็นพื้นที่มากเป็นชั้นที่มีเพียงหนึ่งเดียว ปริมาณการใช้หน่วยความจำจะถูกปัดเศษเป็นทวีคูณถัดไปของ 8 หรือ 16 ไบต์ (IIRC ที่สามารถกำหนดค่าได้) ดังนั้นกรณีที่เมื่อมีการบันทึกจริงจะค่อนข้างหายาก

ชั้นนี้จะง่ายขึ้นเล็กน้อยที่จะใช้ถ้าสอดคล้องกันวิธีการส่งกลับCalendar byteแต่ไม่มีCalendarวิธีการดังกล่าวเท่านั้นget(int)ซึ่งจะต้องส่งคืนintเนื่องจากเขตข้อมูลอื่น แต่ละการดำเนินการกับประเภทที่เล็กลงจะส่งเสริมintดังนั้นคุณจึงจำเป็นต้องมีการคัดเลือกนักแสดงจำนวนมาก

ส่วนใหญ่คุณจะยอมแพ้และเปลี่ยนเป็นintsetters หรือเขียนเช่น

void setDayOfWeek(int dayOfWeek) {
    this.dayOfWeek = checkedCastToByte(dayOfWeek);
}

จากนั้นประเภทของDAY_OF_WEEKไม่สำคัญ

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