ก่อนที่จะเริ่มข้อความหลักของบทความนี้ลองดูที่รหัสต่อไปนี้:
บทบาทของ Integercache ของคลาสจำนวนเต็มใน Java
ชื่อแพ็คเกจ: java.lang
ชื่อไฟล์: integer.java
ชื่อวิธี: IntegerCache
รหัสของวิธีนี้มีดังนี้:
InteegerCache คลาสส่วนตัวแบบคงที่ {คงที่ระดับสูง int สูง; แคชจำนวนเต็มสุดท้ายคงที่ []; คงที่ {สุดท้าย int low = -128; // ค่าสูงอาจถูกกำหนดค่าโดยคุณสมบัติ int h = 127; ถ้า (IntegerCachehighPropValue! = null) {// ใช้ long.decode ที่นี่เพื่อหลีกเลี่ยงวิธีการเรียกใช้ที่ // ต้องการแคช autoboxing ของจำนวนเต็มเพื่อเริ่มต้น int i = long.decode (integercachehighpropvalue) i = math.max (i, 127); // ขนาดอาร์เรย์สูงสุดคือจำนวนเต็ม max_value h = math.min (i, integer.max_value - -low); } สูง = h; แคช = จำนวนเต็มใหม่ [(สูง - ต่ำ) + 1]; int j = ต่ำ; สำหรับ (int k = 0; k <cache.length; k ++) แคช [k] = จำนวนเต็มใหม่ (j ++); } Private IntegerCache () {}}เราเห็นในรหัสที่ต่ำคือ -128 และสูงคือ 127 ด้วยวิธีนี้ในการเขียนโปรแกรม Java หากคุณต้องการใช้วัตถุในช่วงเวลา -128-127 คุณจะใช้วัตถุโดยตรงในแคชนี้
ข้างต้นเป็นการแนะนำสั้น ๆ เพื่อช่วยให้ทุกคนเข้าใจ Integercache ต่อไปนี้เป็นข้อความหลักของบทความนี้:
การแนะนำ
5 ปีที่แล้วฉันโพสต์โพสต์เกี่ยวกับฮังการีเกี่ยวกับวิธีการเปลี่ยน Integercache ใน JDK วิธีการนี้จริง ๆ แล้วจะลึกเข้าไปใน Java Runtime และไม่ได้ใช้จริงในสถานการณ์ เมื่อคุณพัฒนารหัสการวิจัยนี้คุณสามารถเข้าใจได้ดีขึ้นว่าการไตร่ตรองทำงานอย่างไรและคลาสจำนวนเต็มใช้งานได้อย่างไร
คลาสจำนวนเต็มมีชื่อ Integercache ซ้อนกันส่วนตัวซึ่งมีวัตถุจำนวนเต็มที่มีค่าตั้งแต่ -127 ถึง 128
เมื่อรหัสจำเป็นต้องถูกล้อมรอบจากประเภท int ลงในวัตถุจำนวนเต็มและค่าอยู่ในช่วงนี้รันไทม์ Java จะใช้แคชนี้แทนที่จะสร้างวัตถุจำนวนเต็มใหม่ นี่เป็นส่วนใหญ่สำหรับการพิจารณาการเพิ่มประสิทธิภาพประสิทธิภาพ เราต้องจำไว้ว่าค่า int จำนวนมากมักจะอยู่ในช่วงนี้ในโปรแกรม (เช่นดัชนีตัวห้อยของอาร์เรย์)
ผลข้างเคียงของสิ่งนี้คือหลายครั้งเมื่อใช้ตัวดำเนินการสัญญาณเท่ากันเพื่อเปรียบเทียบวัตถุจำนวนเต็มสองชิ้นตราบใดที่ค่าอยู่ในช่วงนั้นจะถูกต้อง นี่เป็นเรื่องปกติในการทดสอบหน่วย ในโหมดเรียกใช้เมื่อค่ามากกว่า 128 การดำเนินการรหัสจะล้มเหลว
การใช้การสะท้อนกลับเพื่อเข้าถึงคลาส Integercache อาจทำให้เกิดผลข้างเคียงที่แปลกประหลาดโปรดทราบว่าสิ่งนี้มีผลต่อ JVM ทั้งหมด หาก Servlet กำหนดค่าแคชจำนวนเต็มขนาดเล็ก Servlets อื่น ๆ ทั้งหมดที่ทำงานภายใต้ Tomcat เดียวกันพบปัญหาเดียวกัน
มีบทความอื่น ๆ ข้างต้นใน Lukas Eder และ SitePoint
ตอนนี้ฉันกำลังเล่นกับรุ่นแรก ๆ ของ Java 9 สิ่งที่ฉันต้องทำในใจของฉันคือการทดลองกับเวอร์ชัน Java ใหม่ ก่อนที่เราจะเริ่มลองดูวิธีการทำใน Java 8
ในบทความของ Lukas ฉันโพสต์รหัสตัวอย่างของเขาที่นี่:
นำเข้า java.lang.reflect.field; นำเข้า java.util.random; เอนโทรปีระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) โยนข้อยกเว้น {// แยก Integercache ผ่านคลาสสะท้อนกลับ <<? > clazz = class.forname ("java.lang.integer $ integercache"); ฟิลด์ฟิลด์ = clazz.getDeclaredField ("แคช"); field.setAccessible (จริง); จำนวนเต็ม [] แคช = (จำนวนเต็ม []) ฟิลด์ get (clazz); // เขียนแคชจำนวนเต็มใหม่สำหรับ (int i = 0; i <cache.length; i ++) {cache [i] = ใหม่จำนวนเต็ม (ใหม่สุ่ม (). nextint (cache.length)); } // พิสูจน์การสุ่มสำหรับ (int i = 0; i <10; i ++) {system.out.println ((จำนวนเต็ม) i); -รหัสนี้เข้าถึง Integercache ผ่านการสะท้อนกลับจากนั้นใช้ค่าสุ่มเพื่อเติมแคช (ซน!)
เราพยายามเรียกใช้รหัสเดียวกันใน Java 9 อย่าคาดหวังว่าจะสนุก เมื่อมีคนพยายามละเมิดมันจะพบว่า Java 9 มีข้อ จำกัด มากกว่า
ข้อยกเว้นในเธรด "Main" java.lang.reflect.inaccessibleObjectException: ไม่สามารถทำให้ฟิลด์คงที่สุดท้าย java.lang.integer [] java.lang.integer $ integercache.cache เข้าถึงได้: โมดูล java.base ไม่ได้
โปรแกรมโยนข้อยกเว้นซึ่งจะไม่เกิดขึ้นใน Java 8 มันเทียบเท่ากับการบอกว่าวัตถุไม่ได้ใช้แบบจำลอง เนื่องจากโมดูล java.base นี่เป็นส่วนสำคัญของ JDK มันจะถูกนำเข้าโดยอัตโนมัติเมื่อแต่ละโปรแกรม Java เริ่มต้นและโมดูลที่ไม่มีชื่อไม่ได้รับอนุญาตให้เปิด ข้อยกเว้นนี้ถูกโยนทิ้งเมื่อเราพยายามตั้งค่าคุณสมบัติที่เข้าถึงได้ของฟิลด์
วัตถุที่เราสามารถเข้าถึงได้อย่างง่ายดายใน Java 8 ไม่สามารถเข้าถึงได้ใน Java 9 เนื่องจากระบบโมดูลใหม่ปกป้องสิ่งนี้ รหัสสามารถเข้าถึงฟิลด์วิธีการและข้อมูลอื่น ๆ ที่สามารถเข้าถึงได้โดยการสะท้อนกลับเฉพาะในกรณีที่คลาสอยู่ในโมดูลเดียวกันหรือโมดูลมีแพ็คเกจเปิดสำหรับการเข้าถึงการสะท้อน สิ่งนี้สามารถนำไปใช้ได้ผ่านไฟล์นิยามโมดูลโมดูล -info.java:
โมดูล mymodule {ส่งออก com.javax0.module.demo; เปิด com.javax0.module.demo;} โมดูล Java.base นี้ไม่จำเป็นต้องเปิดด้วยตัวเองเพื่อการเข้าถึงการสะท้อนโดยเฉพาะอย่างยิ่งสำหรับโมดูลที่ไม่มีชื่อ หากเราสร้างโมดูลและตั้งชื่อข้อความแสดงข้อผิดพลาดจะมีชื่อของโมดูล
เราสามารถเปิดโมดูลในโปรแกรมได้หรือไม่? โมดูล java.lang.reflect.Module มีวิธีการ addopens ที่สามารถทำได้
เป็นไปได้หรือไม่?
ข่าวร้ายสำหรับนักพัฒนาคือ: มันเป็นไปไม่ได้ สามารถเปิดแพ็คเกจในโมดูลในโมดูลอื่นเท่านั้นและแพ็คเกจได้เปิดในโมดูลนั้นโดยเรียกวิธีนี้ วิธีนี้สามารถอนุญาตให้โมดูลถูกส่งผ่านไปยังสิทธิ์โมดูลอื่นได้เท่านั้นหากโมดูลอื่นได้เปิดแพ็คเกจเดียวกันในบางวิธีและไม่สามารถเปิดแพ็คเกจที่ยังไม่ได้เปิด (หมายเหตุของนักแปล: มันยากที่จะเข้าใจใช่มั้ย)
แต่ในเวลาเดียวกันข่าวดีก็คือ: Java 9 ไม่ใช่เรื่องง่ายที่จะแตกเหมือน Java 8 อย่างน้อยช่องโหว่นี้ปิด ดูเหมือนว่า Java กำลังเริ่มพัฒนาไปสู่ระดับมืออาชีพไม่ใช่แค่ของเล่น (หมายเหตุของนักแปล: ใครบอกว่า Java เป็นของเล่น?) ในอนาคตอันใกล้คุณสามารถโยกย้ายโครงการใน RPG และภาษาโคบอลไปยัง Java อย่างจริงจัง (ขออภัยฉันล้อเล่น)
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com
บทความนี้แปลจาก: https://dzone.com/articles/hacking-the-integercache-in-java-9