Java 8 แนะนำคุณสมบัติภาษาใหม่ที่สำคัญเช่นการแสดงออกแลมบ์ดา
การเปลี่ยนแปลงเหล่านี้ในภาษานั้นมาพร้อมกับการเปลี่ยนแปลงที่สำคัญเช่นนั้นในโค้ดไบต์ที่คอมไพล์ซึ่งจะป้องกันไม่ให้รันบนเครื่องเสมือน Java 7 โดยไม่ต้องใช้ตัวแปลงสัญญาณซ้ำบางตัวหรือไม่?
Java 8 แนะนำคุณสมบัติภาษาใหม่ที่สำคัญเช่นการแสดงออกแลมบ์ดา
การเปลี่ยนแปลงเหล่านี้ในภาษานั้นมาพร้อมกับการเปลี่ยนแปลงที่สำคัญเช่นนั้นในโค้ดไบต์ที่คอมไพล์ซึ่งจะป้องกันไม่ให้รันบนเครื่องเสมือน Java 7 โดยไม่ต้องใช้ตัวแปลงสัญญาณซ้ำบางตัวหรือไม่?
คำตอบ:
ไม่การใช้คุณสมบัติ 1.8 ในซอร์สโค้ดของคุณต้องการให้คุณกำหนดเป้าหมาย 1.8 VM ฉันเพิ่งลอง Java 8 รีลีสใหม่และลองคอมไพล์ด้วย-target 1.7 -source 1.8
และคอมไพเลอร์ปฏิเสธ:
$ javac Test -source 1.8 -target 1.7
javac: source release 1.8 requires target release 1.8
วิธีการเริ่มต้นต้องมีการเปลี่ยนแปลงเช่น bytecode และ JVM ที่พวกเขาจะเป็นไปไม่ได้ที่จะทำบน Java 7 ตัวตรวจสอบ bytecode ของ Java 7 และด้านล่างจะปฏิเสธการเชื่อมต่อกับวิธีร่างกาย (ยกเว้นวิธีการเริ่มต้นคงที่) พยายามเลียนแบบวิธีการเริ่มต้นด้วยวิธีการแบบคงที่ทางด้านผู้โทรจะไม่ให้ผลลัพธ์เดียวกันเพราะวิธีการเริ่มต้นสามารถถูกแทนที่ในชั้นเรียนย่อย Retrolambdaมีการสนับสนุนที่ จำกัด สำหรับวิธีการเริ่มต้นย้อนกลับ แต่มันไม่สามารถย้อนกลับได้อย่างสมบูรณ์เพราะต้องใช้คุณสมบัติ JVM ใหม่อย่างแท้จริง
แลมบ์ดาสามารถเรียกใช้บน Java 7 ตามสภาพถ้าคลาส API ที่จำเป็นมีอยู่จริง คำสั่ง invokedynamic มีอยู่บน Java 7 แต่มันเป็นไปได้ที่จะนำ lambdas มาใช้เพื่อสร้างคลาส lambda ในเวลาคอมไพล์ (JDK 8 รุ่นแรกสร้างแบบนั้น) ในกรณีนี้มันจะทำงานบน Java เวอร์ชันใดก็ได้ (Oracle ตัดสินใจใช้ invokedynamic สำหรับ lambdas สำหรับการพิสูจน์ในอนาคตบางทีวันหนึ่ง JVM จะมีฟังก์ชั่นชั้นหนึ่งดังนั้น invokedynamic สามารถเปลี่ยนเป็นใช้แทนการสร้างคลาสสำหรับ lambda ทุกครั้งซึ่งจะช่วยปรับปรุงประสิทธิภาพ) สิ่งที่ Retrolambda ทำคือ มันประมวลผลคำสั่งที่เรียกใช้แบบซิงโครนัสทั้งหมดและแทนที่ด้วยคลาสแบบไม่ระบุชื่อ เช่นเดียวกับสิ่งที่ Java 8 ทำที่รันไทม์เมื่อ lamdba invokedynamic เรียกว่าเป็นครั้งแรก
คำอธิบายประกอบซ้ำเป็นเพียงน้ำตาลประโยค พวกเขาเป็น bytecode เข้ากันได้กับรุ่นก่อนหน้า ใน Java 7 คุณจะต้องใช้เมธอดตัวช่วย (เช่นgetAnnotationsByType ) ซึ่งจะซ่อนรายละเอียดการนำไปปฏิบัติของคำอธิบายประกอบคอนเทนเนอร์ซึ่งมีคำอธิบายประกอบซ้ำ ๆ
AFAIK, คำอธิบายประกอบประเภทมีอยู่ในเวลารวบรวมเท่านั้นดังนั้นจึงไม่จำเป็นต้องมีการเปลี่ยนแปลง bytecode ดังนั้นเพียงแค่เปลี่ยนหมายเลขเวอร์ชัน bytecode ของคลาสที่คอมไพล์ Java 8 ควรเพียงพอที่จะทำให้มันทำงานบน Java 7
ชื่อพารามิเตอร์เมธอดมีอยู่ใน bytecode ด้วย Java 7 ดังนั้นจึงเข้ากันได้ คุณสามารถเข้าถึงพวกเขาได้โดยการอ่าน bytecode ของวิธีการและดูชื่อตัวแปรท้องถิ่นในข้อมูลการแก้ปัญหาของวิธีการ ตัวอย่างเช่น Spring Framework ทำเช่นนั้นเพื่อนำ@PathVariableมาใช้ดังนั้นอาจมีวิธีการไลบรารีที่คุณสามารถโทรหาได้ เนื่องจากวิธีการอินเทอร์เฟซแบบนามธรรมไม่มีเนื้อความของวิธีการข้อมูลการตรวจแก้จุดบกพร่องนั้นไม่มีอยู่สำหรับวิธีการอินเทอร์เฟซใน Java 7 และ AFAIK ทั้งบน Java 8
คุณสมบัติใหม่อื่น ๆส่วนใหญ่เป็น API ใหม่การปรับปรุง HotSpot และเครื่องมือ APIs ใหม่บางส่วนมีอยู่ในห้องสมุดบุคคลที่สาม (เช่นThreeTen-Backportและstreamsupport )
ในที่สุดสรุป, วิธีการเริ่มต้นต้องมีคุณสมบัติ JVM ใหม่ แต่คุณสมบัติภาษาอื่นไม่ได้ หากคุณต้องการใช้พวกเขาคุณจะต้องรวบรวมรหัสใน Java 8 แล้วแปลง bytecode ด้วยRetrolambdaเป็นรูปแบบ Java 5/6/7 อย่างน้อยรุ่นไบต์จะต้องมีการเปลี่ยนแปลงและ javac ไม่อนุญาต-source 1.8 -target 1.7
ดังนั้นจึงจำเป็นต้องมี retrotranslator
เท่าที่ฉันรู้ว่าการเปลี่ยนแปลงเหล่านี้ใน JDK 8 ไม่จำเป็นต้องมีการเพิ่มไบต์ใหม่ กำลังใช้เครื่องมือแลมบ์ดาอยู่ส่วนหนึ่งinvokeDynamic
(ซึ่งมีอยู่แล้วใน JDK 7) ดังนั้นจากจุดยืนชุดคำสั่ง JVM ไม่ควรมีสิ่งใดที่ทำให้โค้ดเบสเข้ากันไม่ได้ อย่างไรก็ตามมีการเชื่อมโยง API และการปรับปรุงคอมไพเลอร์จำนวนมากซึ่งอาจทำให้โค้ดจาก JDK 8 ยากต่อการคอมไพล์ / รันภายใต้ JDK ก่อนหน้า (แต่ฉันยังไม่ได้ลอง)
บางทีเอกสารอ้างอิงต่อไปนี้สามารถช่วยเสริมสร้างความเข้าใจว่าการเปลี่ยนแปลงที่เกี่ยวข้องกับแลมบ์ดานั้นเป็นอย่างไร
รายละเอียดเหล่านี้อธิบายอย่างละเอียดว่ามีการใช้เครื่องมือต่างๆอย่างไรภายใต้ประทุน บางทีคุณอาจพบคำตอบสำหรับคำถามของคุณที่นั่น
class C extends A with B
ถูกนำมาใช้กับการเชื่อมต่อปกติA
และB
และการเรียนสหายและA$class
B$class
class C
เพียงแค่ส่งต่อเมธอดไปยังคลาสสหายแบบคงที่ ประเภทตัวเองไม่ได้บังคับใช้ทั้งหมด lambdas ถูก transpiled ในเวลารวบรวมเป็นชั้นในนามธรรมดังนั้นการnew D with A with B
แสดงออก การจับคู่รูปแบบเป็นพวงของโครงสร้าง if-else ผลตอบแทนที่ไม่ใช่ท้องถิ่น? ลองจับกลไกจากแลมบ์ดา มีอะไรเหลือ (ที่น่าสนใจ scalac ของฉันบอกว่า 1.6 เป็นค่าเริ่มต้น)
หากคุณยินดีที่จะใช้ "retrotranslator" ลอง Retrolambda ที่ยอดเยี่ยมของ Esko Luontola: https://github.com/orfjackal/retrolambda
คุณสามารถทำได้-source 1.7 -target 1.7
แล้วมันจะรวบรวม แต่มันจะไม่รวบรวมถ้าคุณมีคุณสมบัติเฉพาะของ java 8 เช่น lambdas
-source 1.7
จะไม่บิน