เหตุใด Java API จึงใช้งานint
เมื่อshort
ใดถึงbyte
จะเพียงพอ
ตัวอย่าง: DAY_OF_WEEK
ข้อมูลในระดับการใช้งานCalendar
int
หากความแตกต่างน้อยเกินไปทำไมประเภทข้อมูลเหล่านั้น ( short
, int
) จึงมีอยู่ทั้งหมด
เหตุใด Java API จึงใช้งานint
เมื่อshort
ใดถึงbyte
จะเพียงพอ
ตัวอย่าง: DAY_OF_WEEK
ข้อมูลในระดับการใช้งานCalendar
int
หากความแตกต่างน้อยเกินไปทำไมประเภทข้อมูลเหล่านั้น ( short
, int
) จึงมีอยู่ทั้งหมด
คำตอบ:
เหตุผลบางประการได้รับการชี้ให้เห็นแล้ว ตัวอย่างเช่นความจริงที่ว่า"... (เกือบ) การดำเนินงานทั้งหมดในไบต์สั้นจะส่งเสริมพื้นฐานเหล่านี้เพื่อ 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 เพียงที่เหมาะสมสำหรับ int
32bit (การดำเนินการที่เกี่ยวข้องกับlong
ค่า64 บิตถูกนำมาใช้เป็นกรณีพิเศษ)
(หมายเหตุ: ย่อหน้าสุดท้ายเป็นบิตที่เกินความจริงโดยคำนึงถึง vectorization ที่เป็นไปได้ แต่ควรให้แนวคิดพื้นฐานโดยไม่ต้องดำลึกเข้าไปในหัวข้อการออกแบบตัวประมวลผล)
แก้ไข: ภาคผนวกสั้นโดยเพ่งความสนใจไปที่ตัวอย่างจากคำถาม แต่โดยทั่วไปแล้วเราอาจถามว่ามันจะไม่เป็นประโยชน์ในการจัดเก็บสาขาโดยใช้ประเภทที่มีขนาดเล็กลงหรือไม่ ตัวอย่างเช่นหนึ่งอาจจะคิดว่าหน่วยความจำที่จะถูกบันทึกไว้โดยการจัดเก็บเป็นCalendar.DAY_OF_WEEK
byte
แต่ที่นี่รูปแบบไฟล์ Java Class มาพร้อมเล่น: ฟิลด์ทั้งหมดในไฟล์คลาสครอบครอง "สล็อต" อย่างน้อยหนึ่งช่องซึ่งมีขนาดเท่ากับหนึ่งint
(32 บิต) (ฟิลด์ "wide" double
และlong
ใช้สองช่อง) ดังนั้นการประกาศเขตข้อมูลอย่างชัดเจนshort
หรือbyte
จะไม่บันทึกหน่วยความจำใด ๆ
int
จะรักษาค่าว่ามีอย่างน้อยขนาดของ หากคุณมีการอ้างอิงถึงการใช้งานอื่นฉันจะอัปเดตคำตอบและใส่ลิงค์ตาม
(เกือบ) การดำเนินงานทั้งหมดใน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()
จากนั้นคุณจะสังเกตเห็นความแตกต่างด้านประสิทธิภาพ
เพราะการคำนวณทางคณิตศาสตร์นั้นง่ายกว่าเมื่อใช้จำนวนเต็มเปรียบเทียบกับกางเกงขาสั้น สมมติว่าค่าคงที่ถูกจำลองตามshort
ค่าจริง ๆ จากนั้นคุณจะต้องใช้ API ในลักษณะนี้:
short month = Calendar.JUNE;
month = month + (short) 1; // is july
สังเกตเห็นการคัดเลือกนักแสดงที่ชัดเจน ค่าสั้น ๆ จะได้รับการส่งเสริมโดยนัยกับint
ค่าเมื่อใช้ในการดำเนินการทางคณิตศาสตร์ (บนตัวถูกดำเนินการกางเกงขาสั้นจะแสดงแม้เป็น ints.) มันจะค่อนข้างยุ่งยากในการใช้ซึ่งเป็นเหตุผลที่int
ค่านิยมมักจะเป็นค่าคงที่
เมื่อเปรียบเทียบกับประสิทธิภาพในการจัดเก็บข้อมูลมีน้อยที่สุดเนื่องจากมีค่าคงที่จำนวนคงที่ เรากำลังพูดถึงค่าคงที่ 40 ค่า การเปลี่ยนการจัดเก็บข้อมูลของพวกเขาจากint
ไปหากว่าคุณปลอดภัยshort
40 * 16 bit = 80 byte
ดูคำตอบนี้สำหรับการอ้างอิงเพิ่มเติม
หากคุณใช้ปรัชญาที่ค่าคงที่อินทิกรัลถูกเก็บไว้ในประเภทที่เล็กที่สุดที่พวกมันเข้ากันแล้ว Java จะมีปัญหาร้ายแรง: เมื่อโปรแกรมเมอร์เขียนโค้ดโดยใช้ค่าคงที่อินทิกรัลพวกเขาต้องระวังโค้ดของพวกเขา ค่าคงที่มีความสำคัญและหากเป็นเช่นนั้นให้ค้นหาประเภทในเอกสารประกอบและ / หรือดำเนินการแปลงประเภทใดก็ตามที่จำเป็น
ดังนั้นเมื่อเราสรุปปัญหาร้ายแรงแล้วคุณคาดหวังว่าจะได้ประโยชน์อะไรจากปรัชญานั้น ฉันจะ unsurprised ถ้าเพียงผลรันไทม์ที่สังเกตของการเปลี่ยนแปลงที่จะเป็นสิ่งที่พิมพ์ที่คุณได้รับเมื่อคุณมองไปคงขึ้นผ่านการสะท้อน (และแน่นอนว่าข้อผิดพลาดใด ๆ ที่ถูกแนะนำโดยโปรแกรมเมอร์ที่ขี้เกียจ / ไม่เจตนานั้นไม่ถูกต้องสำหรับประเภทของค่าคงที่)
การชั่งน้ำหนักข้อดีและข้อเสียนั้นง่ายมาก: มันเป็นปรัชญาที่ไม่ดี
ความซับซ้อนในการออกแบบของเครื่องเสมือนเป็นฟังก์ชั่นของการทำงานที่สามารถทำได้ การมีคำแนะนำการใช้งานสี่อย่างเช่น "ทวีคูณ" ง่ายขึ้นแต่ละอันสำหรับจำนวนเต็ม 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 ไบต์ เนื่องจากแต่ละอาเรย์แต่ละประเภทต้องการสนับสนุนการดำเนินการเพียงไม่กี่อย่าง (โดยเฉพาะอย่างยิ่งการอ่านหนึ่งไอเท็มเก็บหนึ่งไอเท็มคัดลอกช่วงของไอเท็มภายในอาเรย์หรือคัดลอกช่วงของไอเท็มจากหนึ่งอาเรย์หนึ่งไปยังอีก) ประเภทอาเรย์ไม่รุนแรงเท่าความซับซ้อนของการมีค่าตัวเลขที่ไม่ต่อเนื่องที่สามารถใช้งานได้โดยตรงมากขึ้น
ที่จริงแล้วมีข้อได้เปรียบเล็กน้อย หากคุณมี
class MyTimeAndDayOfWeek {
byte dayOfWeek;
byte hour;
byte minute;
byte second;
}
แล้วใน JVM int
ทั่วไปจะต้องเป็นพื้นที่มากเป็นชั้นที่มีเพียงหนึ่งเดียว ปริมาณการใช้หน่วยความจำจะถูกปัดเศษเป็นทวีคูณถัดไปของ 8 หรือ 16 ไบต์ (IIRC ที่สามารถกำหนดค่าได้) ดังนั้นกรณีที่เมื่อมีการบันทึกจริงจะค่อนข้างหายาก
ชั้นนี้จะง่ายขึ้นเล็กน้อยที่จะใช้ถ้าสอดคล้องกันวิธีการส่งกลับCalendar
byte
แต่ไม่มีCalendar
วิธีการดังกล่าวเท่านั้นget(int)
ซึ่งจะต้องส่งคืนint
เนื่องจากเขตข้อมูลอื่น แต่ละการดำเนินการกับประเภทที่เล็กลงจะส่งเสริมint
ดังนั้นคุณจึงจำเป็นต้องมีการคัดเลือกนักแสดงจำนวนมาก
ส่วนใหญ่คุณจะยอมแพ้และเปลี่ยนเป็นint
setters หรือเขียนเช่น
void setDayOfWeek(int dayOfWeek) {
this.dayOfWeek = checkedCastToByte(dayOfWeek);
}
จากนั้นประเภทของDAY_OF_WEEK
ไม่สำคัญ