การสร้างไฟล์คลาส Java ถูกกำหนดหรือไม่?


94

เมื่อใช้JDK เดียวกัน (เช่นjavacปฏิบัติการเดียวกัน) ไฟล์คลาสที่สร้างขึ้นจะเหมือนกันเสมอหรือไม่? อาจมีความแตกต่างขึ้นอยู่กับระบบปฏิบัติการหรือฮาร์ดแวร์หรือไม่? ยกเว้นรุ่น JDK อาจมีปัจจัยอื่นที่ทำให้เกิดความแตกต่างหรือไม่? มีตัวเลือกคอมไพเลอร์เพื่อหลีกเลี่ยงความแตกต่างหรือไม่? ความแตกต่างอาจเป็นไปได้ในทางทฤษฎีเท่านั้นหรือ Oracle javacสร้างไฟล์คลาสที่แตกต่างกันสำหรับตัวเลือกอินพุตและคอมไพเลอร์เดียวกันหรือไม่

อัปเดต 1ฉันสนใจในการสร้างเช่นเอาต์พุตของคอมไพเลอร์ไม่ใช่ว่าไฟล์คลาสสามารถเรียกใช้บนแพลตฟอร์มต่างๆได้หรือไม่

อัปเดต 2โดย 'Same JDK' ฉันยังหมายถึงjavacปฏิบัติการเดียวกัน

อัปเดต 3ความแตกต่างระหว่างความแตกต่างทางทฤษฎีและความแตกต่างในทางปฏิบัติในคอมไพเลอร์ของ Oracle

[แก้ไขเพิ่มคำถามถอดความ]
"อะไรคือสถานการณ์ที่เรียกใช้งาน javac เดียวกันเมื่อรันบนแพลตฟอร์มอื่นจะสร้าง bytecode ที่แตกต่างกัน"


5
@Gamb CORA ไม่ได้หมายความว่ารหัสไบต์จะเหมือนกันทุกประการหากคอมไพล์บนแพลตฟอร์มที่แตกต่างกัน หมายความว่าโค้ดไบต์ที่สร้างขึ้นจะทำสิ่งเดียวกันทุกประการ
Sergey Kalinichenko

11
จะแคร์ทำไม นี้มีกลิ่นเหมือนปัญหา XY
Joachim Sauer

4
@JoachimSauer พิจารณาว่าเวอร์ชันของคุณควบคุมไบนารีของคุณหรือไม่คุณอาจต้องการตรวจจับการเปลี่ยนแปลงเฉพาะในกรณีที่ซอร์สโค้ดมีการเปลี่ยนแปลง แต่คุณจะรู้ว่านี่ไม่ใช่ความคิดที่สมเหตุสมผลหาก JDK สามารถเปลี่ยนไบนารีเอาต์พุตได้โดยพลการ
RB.

7
@RB: คอมไพเลอร์ได้รับอนุญาตให้สร้างรหัสไบต์ที่สอดคล้องซึ่งแสดงถึงรหัสที่คอมไพล์ ในความเป็นจริงการอัปเดตคอมไพเลอร์บางตัวจะแก้ไขข้อบกพร่องที่สร้างรหัสที่แตกต่างกันเล็กน้อย (โดยปกติจะมีลักษณะการทำงานของรันไทม์เหมือนกัน) กล่าวอีกนัยหนึ่ง: หากคุณต้องการตรวจจับการเปลี่ยนแปลงที่มาตรวจสอบการเปลี่ยนแปลงแหล่งที่มา
Joachim Sauer

3
@dasblinkenlight: คุณสมมติว่าคำตอบที่พวกเขาอ้างว่ามีนั้นถูกต้องและเป็นปัจจุบันจริง (สงสัยเนื่องจากคำถามมาจากปี 2546)
โจอาคิมซาวเออร์

คำตอบ:


68

ลองมาดูกัน:

ฉันสามารถสร้างคอมไพเลอร์ Java ที่สอดคล้องกันทั้งหมดที่ไม่เคยสร้างเหมือนกัน .classไฟล์ซ้ำสองครั้งโดยให้.javaไฟล์เดียวกัน

ฉันสามารถทำได้โดยการปรับแต่งโครงสร้าง bytecode ทุกชนิดหรือเพียงแค่เพิ่มแอตทริบิวต์ที่ไม่จำเป็นให้กับวิธีการของฉัน (ซึ่งได้รับอนุญาต)

ระบุว่าข้อกำหนดไม่ได้ต้องการให้คอมไพเลอร์สร้างไฟล์คลาสที่เหมือนกันแบบไบต์ต่อไบต์ฉันจะหลีกเลี่ยงโดยขึ้นอยู่กับ ผลลัพธ์ดังกล่าว

อย่างไรก็ตามไม่กี่ครั้งที่ผมได้ตรวจสอบรวบรวมแฟ้มแหล่งที่มาเดียวกันกับคอมไพเลอร์กับสวิทช์เดียวกัน (และห้องสมุดเดียวกัน!) ได้ผลในแบบเดียวกัน.classไฟล์

อัปเดต:ฉันเพิ่งสะดุดเมื่อเร็ว ๆ นี้โพสต์บล็อกนี้น่าสนใจเกี่ยวกับการดำเนินงานของswitchบนStringใน Java 7 ในบล็อกโพสต์นี้มีบางส่วนที่เกี่ยวข้องซึ่งฉันจะพูดที่นี่ (เน้นของฉัน):

เพื่อที่จะทำให้การส่งออกของคอมไพเลอร์คาดการณ์และทำซ้ำแผนที่และชุดที่ใช้ในโครงสร้างข้อมูลเหล่านี้เป็นLinkedHashMapและLinkedHashSets มากกว่าเพียงและHashMaps ในแง่ของความถูกต้องในการทำงานของโค้ดที่สร้างขึ้นในระหว่างการคอมไพล์ที่กำหนดให้ใช้และจะดี ; ลำดับการทำซ้ำไม่สำคัญ อย่างไรก็ตามเราพบว่าการมีเอาต์พุตไม่แตกต่างกันไปตามรายละเอียดการใช้งานของคลาสระบบเป็นประโยชน์HashSetsHashMapHashSetjavac

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


@GaborSch มันหายไปไหน? "สถานการณ์ใดบ้างที่ไฟล์ปฏิบัติการ javac เดียวกันเมื่อรันบนแพลตฟอร์มอื่นจะสร้าง bytecode ต่างกัน" โดยพื้นฐานแล้วขึ้นอยู่กับความตั้งใจของกลุ่มที่ผลิตคอมไพเลอร์
emory

3
สำหรับฉันนี่คงเป็นเหตุผลที่เพียงพอที่จะไม่ขึ้นอยู่กับมัน: JDK ที่อัปเดตอาจทำลายระบบบิลด์ / ไฟล์เก็บถาวรของฉันได้หากฉันขึ้นอยู่กับข้อเท็จจริงที่ว่าคอมไพเลอร์สร้างรหัสเดียวกันเสมอ
Joachim Sauer

3
@GaborSch: คุณมีตัวอย่างที่ดีของสถานการณ์ดังกล่าวอยู่แล้วดังนั้นมุมมองเพิ่มเติมเกี่ยวกับปัญหาจึงเป็นไปตามลำดับ ไม่มีความรู้สึกในการทำซ้ำงานของคุณ
Joachim Sauer

1
@GaborSch ปัญหาหลักคือเราต้องการใช้ "การอัปเดตออนไลน์" ที่มีประสิทธิภาพของแอปพลิเคชันของเราซึ่งผู้ใช้จะดึงเฉพาะ JAR ที่แก้ไขจากเว็บไซต์เท่านั้น ฉันสามารถสร้าง JAR ที่เหมือนกันโดยมีไฟล์คลาสเหมือนกันเป็นอินพุต แต่คำถามคือไฟล์คลาสจะเหมือนกันเสมอหรือไม่เมื่อคอมไพล์จากไฟล์ต้นฉบับเดียวกัน แนวคิดทั้งหมดของเรายืนหยัดและล้มเหลวด้วยข้อเท็จจริงนี้
mstrap

2
@mstrap: ดังนั้นจึงเป็นปัญหา XY หลังจากทั้งหมด คุณสามารถดูการอัปเดตที่แตกต่างกันของขวดโหลได้ (ดังนั้นความแตกต่างหนึ่งไบต์จะไม่ทำให้ jar ทั้งหมดถูกดาวน์โหลดอีกครั้ง) และคุณควรระบุหมายเลขเวอร์ชันที่ชัดเจนให้กับรุ่นของคุณอยู่ดีดังนั้นในความคิดของฉันจึงเป็นประเด็นที่น่าสงสัย .
Joachim Sauer

39

ไม่มีข้อผูกมัดสำหรับคอมไพเลอร์ในการสร้าง bytecode เดียวกันบนแต่ละแพลตฟอร์ม คุณควรปรึกษาjavacยูทิลิตี้ของผู้ขายรายอื่นเพื่อรับคำตอบที่เฉพาะเจาะจง


ฉันจะแสดงตัวอย่างที่ใช้ได้จริงสำหรับสิ่งนี้พร้อมการสั่งซื้อไฟล์

สมมติว่าเรามีไฟล์ jar 2 ไฟล์: my1.jarและMy2.jar. พวกเขาอยู่ในlibไดเรกทอรีเคียงข้างกัน คอมไพเลอร์พวกเขาอ่านตามลำดับตัวอักษร (ตั้งแต่นี้lib) แต่สั่งซื้อmy1.jar, My2.jarเมื่อระบบไฟล์เป็นกรณีตายและMy2.jar, my1.jarถ้ามันเป็นกรณีที่สำคัญ

my1.jarมีชั้นเรียนA.classที่มีวิธีการ

public class A {
     public static void a(String s) {}
}

My2.jarมีเหมือนกันA.classแต่มีลายเซ็นวิธีที่แตกต่างกัน (รับObject):

public class A {
     public static void a(Object o) {}
}

เป็นที่ชัดเจนว่าหากคุณมีสาย

String s = "x"; 
A.a(s); 

มันจะรวบรวมการเรียกใช้เมธอดที่มีลายเซ็นที่แตกต่างกันในกรณีต่างๆ ดังนั้นขึ้นอยู่กับความละเอียดอ่อนของระบบไฟล์ของคุณคุณจะได้รับคลาสที่แตกต่างกันตามผลลัพธ์


1
1 มีความแตกต่างมากมายระหว่างคอมไพเลอร์ Eclipse และ javac เช่นมีวิธีการก่อสร้างสังเคราะห์จะถูกสร้างขึ้น
Paul Bellora

2
@GaborSch ฉันสนใจว่ารหัสไบต์จะเหมือนกันสำหรับ JDK เดียวกันหรือไม่เช่น javac เดียวกัน ฉันจะทำให้ชัดเจนขึ้น
mstrap

2
@mstrap ฉันเข้าใจคำถามของคุณ แต่คำตอบยังคงเหมือนเดิม: ขึ้นอยู่กับผู้ขาย javacไม่เหมือนกันเพราะคุณมีไบนารีที่แตกต่างกันในแต่ละแพลตฟอร์ม (เช่น Win7, Linux, Solaris, Mac) สำหรับผู้ขายไม่สมเหตุสมผลที่จะมีการนำไปใช้งานที่แตกต่างกัน แต่ปัญหาเฉพาะของแพลตฟอร์มใด ๆ อาจมีผลต่อผลลัพธ์ (เช่นการสั่งซื้อ flie ในไดเร็กทอรี (คิดในlibไดเร็กทอรีของคุณ) endianness ฯลฯ )
gaborsch

1
โดยปกติแล้วส่วนใหญ่javacจะใช้งานใน Java (และjavacเป็นเพียงตัวเรียกใช้แบบเนทีฟธรรมดา ๆ ) ดังนั้นความแตกต่างของแพลตฟอร์มส่วนใหญ่ไม่ควรมีผลกระทบ
Joachim Sauer

2
@mstrap - ประเด็นที่เขากำลังทำก็คือไม่มีข้อกำหนดสำหรับผู้ขายใด ๆ ที่จะทำให้คอมไพเลอร์ของพวกเขาสร้าง bytecode เดียวกันในทุกแพลตฟอร์มเพียงแต่ว่า bytecode ที่เป็นผลลัพธ์จะให้ผลลัพธ์ที่เหมือนกัน เนื่องจากไม่มีมาตรฐาน / ข้อกำหนด / ข้อกำหนดคำตอบสำหรับคำถามของคุณคือ "ขึ้นอยู่กับผู้จำหน่ายคอมไพเลอร์และแพลตฟอร์มที่เฉพาะเจาะจง"
Brian Roach

6

คำตอบสั้น ๆ - ไม่


คำตอบยาว

พวกเขาbytecodeไม่จำเป็นต้องเหมือนกันสำหรับแพลตฟอร์มที่แตกต่างกัน มันคือ JRE (Java Runtime Environment) ซึ่งรู้ว่าจะรัน bytecode อย่างไร

หากคุณทำตามข้อกำหนด Java VMคุณจะรู้ว่าสิ่งนี้ไม่จำเป็นต้องเป็นจริงว่า bytecode นั้นเหมือนกันสำหรับแพลตฟอร์มที่แตกต่างกัน

จะผ่านรูปแบบไฟล์ชั้นก็แสดงให้เห็นโครงสร้างของไฟล์ชั้นเรียนเป็น

ClassFile {
    u4 magic;
    u2 minor_version;
    u2 major_version;
    u2 constant_pool_count;
    cp_info constant_pool[constant_pool_count-1];
    u2 access_flags;
    u2 this_class;
    u2 super_class;
    u2 interfaces_count;
    u2 interfaces[interfaces_count];
    u2 fields_count;
    field_info fields[fields_count];
    u2 methods_count;
    method_info methods[methods_count];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

การตรวจสอบเกี่ยวกับเวอร์ชันรองและเวอร์ชันหลัก

minor_version, major_version

ค่าของไอเท็ม minor_version และ major_version คือหมายเลขเวอร์ชันรองและเวอร์ชันหลักของไฟล์คลาสนี้หมายเลขเวอร์ชันหลักและเวอร์ชันรองจะกำหนดเวอร์ชันของรูปแบบไฟล์คลาสร่วมกัน หากไฟล์คลาสมีหมายเลขเวอร์ชันหลัก M และหมายเลขเวอร์ชันรอง m เราจะระบุเวอร์ชันของรูปแบบไฟล์คลาสเป็น Mm ดังนั้นเวอร์ชันรูปแบบไฟล์คลาสอาจเรียงลำดับตามศัพท์เช่น 1.5 <2.0 <2.1 การใช้งานเครื่องเสมือน Java สามารถรองรับรูปแบบไฟล์คลาสของเวอร์ชัน v ถ้า v อยู่ในช่วง Mi.0 v Mj.m. ที่ต่อเนื่องกัน เฉพาะ Sun เท่านั้นที่สามารถระบุช่วงของเวอร์ชันที่การใช้งานเครื่องเสมือน Java ที่สอดคล้องกับระดับรีลีสที่กำหนดของแพลตฟอร์ม Java ที่อาจรองรับได้ 1

อ่านเพิ่มเติมผ่านเชิงอรรถ

1 การใช้งานเครื่องเสมือน Java ของ JDK รีลีส 1.0.2 ของ Sun รองรับรูปแบบไฟล์คลาสเวอร์ชัน 45.0 ถึง 45.3 JDK ของ Sun เผยแพร่ 1.1.X สามารถรองรับรูปแบบไฟล์คลาสของเวอร์ชันในช่วง 45.0 ถึง 45.65535 การใช้งานแพลตฟอร์ม Java 2 เวอร์ชัน 1.2 สามารถรองรับรูปแบบไฟล์คลาสของเวอร์ชันในช่วง 45.0 ถึง 46.0

ดังนั้นการตรวจสอบทั้งหมดนี้แสดงให้เห็นว่าไฟล์คลาสที่สร้างบนแพลตฟอร์มต่างๆไม่จำเป็นต้องเหมือนกัน


กรุณาให้ลิงค์รายละเอียดเพิ่มเติมได้ไหม
mstrap

ฉันคิดว่าโดย 'แพลตฟอร์ม' พวกเขาอ้างถึงแพลตฟอร์ม Java ไม่ใช่ระบบปฏิบัติการ แน่นอนว่าเมื่อสั่งให้ javac 1.7 สร้างไฟล์คลาสที่เข้ากันได้กับ 1.6 จะมีความแตกต่าง
mstrap

@mtk +1 เพื่อแสดงจำนวนคุณสมบัติที่สร้างขึ้นสำหรับคลาสเดียวในระหว่างการคอมไพล์
gaborsch

3

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

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

ประการที่สามฉันไม่เคยพบความแตกต่างใด ๆ ในการสร้างเนื่องจากแพลตฟอร์มโฮสต์ (นอกเหนือจากที่เป็นผลมาจากความแตกต่างในสิ่งที่อยู่บนคลาสพา ธ ) รหัสซึ่งจะแตกต่างกันไปตามแพลตฟอร์ม (เช่นไลบรารีโค้ดเนทีฟ) ไม่ได้เป็นส่วนหนึ่งของไฟล์คลาสและการสร้างโค้ดเนทีฟจริงจากไบต์โค้ดจะเกิดขึ้นหลังจากโหลดคลาสแล้ว

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


2

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


3
คุณมีข้อมูลอ้างอิงสำหรับสิ่งนี้หรือไม่? ดังที่ฉันได้กล่าวไว้ในความคิดเห็นของคำถามนี่ไม่ใช่กรณีของ C # อย่างแน่นอนดังนั้นอยากเห็นการอ้างอิงที่ระบุว่าเป็นกรณีของ Java ฉันคิดเป็นพิเศษว่าคอมไพลเลอร์แบบมัลติเธรดอาจกำหนดชื่อตัวระบุที่แตกต่างกันในการรันที่ต่างกัน
RB.

1
นี่คือคำตอบสำหรับคำถามของฉันและสิ่งที่ฉันคาดหวังอย่างไรก็ตามฉันเห็นด้วยกับ RB ว่าการอ้างอิงนั้นมีความสำคัญ
mstrap

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

1

โดยรวมแล้วฉันต้องบอกว่าไม่มีการรับประกันว่าแหล่งที่มาเดียวกันจะสร้าง bytecode เดียวกันเมื่อคอมไพล์โดยคอมไพเลอร์เดียวกัน แต่อยู่บนแพลตฟอร์มอื่น

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

มีส่วนในการทำงานร่วมกันในไบนารีคือJava Language ข้อกำหนด

ภายในกรอบของ Release-to-Release Binary Compatibility ใน SOM (Forman, Conner, Danforth และ Raper, Proceedings of OOPSLA '95) ไบนารีการเขียนโปรแกรมภาษา Java เข้ากันได้กับไบนารีภายใต้การแปลงที่เกี่ยวข้องทั้งหมดที่ผู้เขียนระบุ (มีข้อแม้บางประการด้วย เกี่ยวกับการเพิ่มตัวแปรอินสแตนซ์) การใช้โครงร่างของพวกเขานี่คือรายการของการเปลี่ยนแปลงที่เข้ากันได้กับไบนารีที่สำคัญบางอย่างที่ภาษาโปรแกรม Java รองรับ:

•นำวิธีการที่มีอยู่ตัวสร้างและตัวเริ่มต้นกลับมาใช้ใหม่เพื่อปรับปรุงประสิทธิภาพ

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

•การเพิ่มฟิลด์วิธีการหรือตัวสร้างใหม่ในคลาสหรืออินเทอร์เฟซที่มีอยู่

•การลบฟิลด์ส่วนตัววิธีการหรือตัวสร้างของชั้นเรียน

•เมื่ออัปเดตแพ็กเกจทั้งหมดการลบฟิลด์การเข้าถึงค่าเริ่มต้น (เฉพาะแพ็กเกจเท่านั้น) วิธีการหรือตัวสร้างคลาสและอินเทอร์เฟซในแพ็กเกจ

•จัดลำดับฟิลด์วิธีการหรือตัวสร้างใหม่ในการประกาศประเภทที่มีอยู่

•ย้ายวิธีการขึ้นในลำดับชั้นของชั้นเรียน

•จัดลำดับรายการของอินเทอร์เฟซโดยตรงของคลาสหรืออินเทอร์เฟซใหม่

•การแทรกคลาสหรือประเภทอินเทอร์เฟซใหม่ในลำดับชั้นประเภท

บทนี้ระบุมาตรฐานขั้นต่ำสำหรับความเข้ากันได้แบบไบนารีที่รับประกันโดยการใช้งานทั้งหมด ภาษาการเขียนโปรแกรม Java รับประกันความเข้ากันได้เมื่อมีการผสมไบนารีของคลาสและอินเทอร์เฟซที่ไม่ทราบว่ามาจากแหล่งที่มาที่เข้ากันได้ แต่มีการแก้ไขแหล่งที่มาด้วยวิธีที่เข้ากันได้ตามที่อธิบายไว้ที่นี่ โปรดทราบว่าเรากำลังพูดถึงความเข้ากันได้ระหว่างแอปพลิเคชันรุ่นต่างๆ การอภิปรายเกี่ยวกับความเข้ากันได้ระหว่างรุ่นของแพลตฟอร์ม Java SE อยู่นอกเหนือขอบเขตของบทนี้


บทความนั้นกล่าวถึงสิ่งที่อาจเกิดขึ้นได้เมื่อเราเปลี่ยนเวอร์ชัน Java คำถามของ OP คือจะเกิดอะไรขึ้นถ้าเราเปลี่ยนแพลตฟอร์มภายใน Java เวอร์ชันเดียวกัน มิฉะนั้นจะเป็นการจับที่ดี
gaborsch

1
มันใกล้มากที่สุดเท่าที่ฉันจะหาได้ มีช่องว่างระหว่างข้อมูลจำเพาะของภาษาและข้อมูลจำเพาะของ JVM จนถึงตอนนี้ฉันต้องตอบ OP ด้วย 'ไม่มีการรับประกันว่าคอมไพเลอร์ java เดียวกันจะสร้าง bytecode เดียวกันเมื่อรันบนแพลตฟอร์มอื่น'
Kelly S. French

1

Java allows you write/compile code on one platform and run on different platform. AFAIK ; สิ่งนี้จะเป็นไปได้ก็ต่อเมื่อไฟล์คลาสที่สร้างบนแพลตฟอร์มที่แตกต่างกันนั้นเหมือนกันหรือเหมือนกันในทางเทคนิคเช่นเหมือนกัน

แก้ไข

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

ดังนั้นตามข้อกำหนดไฟล์. class ของคลาสบนแพลตฟอร์มที่แตกต่างกันไม่จำเป็นต้องจับคู่ไบต์ต่อไบต์


คำถามของ OP คือไฟล์คลาสเหมือนกันหรือ "เหมือนกันในทางเทคนิค"
bdesham

ฉันสนใจว่ามันเหมือนกันไหม
mstrap

และตอบว่าใช่ สิ่งที่ฉันหมายถึงคือมันอาจไม่เหมือนกันถ้าคุณเปรียบเทียบไบต์ต่อไบต์นั่นคือเหตุผลที่ฉันใช้คำว่าเทคนิคเดียวกัน
rai.skumar

@bdesham เขาอยากรู้ว่ามันเหมือนกันไหม ไม่แน่ใจว่า "ในทางเทคนิคเหมือนกัน" เข้าใจว่าอะไร ... นั่นคือเหตุผลในการโหวตลง
rai.skumar

@ Rai.skumar คำตอบของคุณโดยพื้นฐานแล้วกล่าวว่า "คอมไพเลอร์สองตัวจะสร้างเอาต์พุตที่ทำงานเหมือนกันเสมอ" แน่นอนว่านี่เป็นเรื่องจริง เป็นแรงจูงใจทั้งหมดของแพลตฟอร์ม Java OP ต้องการทราบว่ารหัสที่ปล่อยออกมาเป็นไบต์สำหรับไบต์เหมือนกันหรือไม่ซึ่งคุณไม่ได้ระบุไว้ในคำตอบของคุณ
bdesham

1

สำหรับคำถาม:

"สถานการณ์ใดบ้างที่โปรแกรมปฏิบัติการ javac เดียวกันเมื่อรันบนแพลตฟอร์มอื่นจะสร้าง bytecode ที่แตกต่างกัน"

ตัวอย่างCross-Compilationแสดงให้เห็นว่าเราสามารถใช้ตัวเลือก Javac ได้อย่างไร: -target version

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


0

คำตอบส่วนใหญ่คือ "ใช่" แต่เพื่อให้ได้คำตอบที่แม่นยำเราจำเป็นต้องค้นหาคีย์หรือสร้างแนวทางในระหว่างการรวบรวม

ฉันจำสถานการณ์ที่เกิดขึ้นไม่ได้ ตัวอย่างเช่นการมี ID สำหรับวัตถุประสงค์ในการทำให้เป็นอนุกรมจะถูกเข้ารหัสเช่นที่สร้างโดยโปรแกรมเมอร์หรือ IDE

ปล. JNI ก็มีความสำคัญเช่นกัน

PPS ฉันพบว่าjavacมันเขียนด้วยตัวเองใน java ซึ่งหมายความว่ามันเหมือนกันบนแพลตฟอร์มต่างๆ ดังนั้นมันจะไม่สร้างรหัสที่แตกต่างกันโดยไม่มีเหตุผล ดังนั้นจึงสามารถทำได้เฉพาะกับการโทรแบบเนทีฟ


โปรดทราบว่า Java ไม่ได้ป้องกันคุณจากความแตกต่างของแพลตฟอร์มทั้งหมด ลำดับของไฟล์ที่ส่งคืนเมื่อไม่ได้กำหนดเนื้อหาไดเร็กทอรีและอาจส่งผลกระทบต่อคอมไพเลอร์ได้
Joachim Sauer

0

มีคำถามสองข้อ

Can there be a difference depending on the operating system or hardware? 

นี่เป็นคำถามทางทฤษฎีและคำตอบคืออย่างชัดเจนใช่มีสามารถเป็น ตามที่คนอื่น ๆ กล่าวไว้ข้อกำหนดไม่ต้องการให้คอมไพเลอร์สร้างไฟล์คลาสที่เหมือนกันแบบไบต์ต่อไบต์

แม้ว่าคอมไพเลอร์ทุกตัวที่มีอยู่ในปัจจุบันจะสร้างรหัสไบต์เดียวกันในทุกสถานการณ์ (ฮาร์ดแวร์ที่แตกต่างกัน ฯลฯ ) คำตอบในวันพรุ่งนี้อาจแตกต่างกัน หากคุณไม่เคยวางแผนที่จะอัปเดต javac หรือระบบปฏิบัติการของคุณคุณสามารถทดสอบลักษณะการทำงานของเวอร์ชันนั้นได้ในสถานการณ์เฉพาะของคุณ แต่ผลลัพธ์อาจแตกต่างออกไปหากคุณเปลี่ยนจาก Java 7 Update 11 เป็น Java 7 Update 15

What are the circumstances where the same javac executable, when run on a different platform, will produce different bytecode?

นั่นเป็นเรื่องที่ไม่รู้

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


0

ฉันจะใส่วิธีอื่น

อันดับแรกฉันคิดว่าคำถามไม่เกี่ยวกับการกำหนด:

แน่นอนว่ามันเป็นปัจจัยกำหนด: การสุ่มนั้นยากที่จะประสบความสำเร็จในวิทยาศาสตร์คอมพิวเตอร์และไม่มีเหตุผลใดที่คอมไพเลอร์จะแนะนำที่นี่ไม่ว่าด้วยเหตุผลใดก็ตาม

ประการที่สองถ้าคุณกำหนดใหม่ได้โดย "วิธีการที่คล้ายกันเป็นไฟล์ bytecode สำหรับไฟล์ sourcecode เดียวกันได้หรือไม่" แล้วไม่มีคุณไม่สามารถพึ่งพาความจริงที่ว่าพวกเขาจะคล้ายกัน

วิธีที่ดีในการตรวจสอบสิ่งนี้คือการทิ้ง. class (หรือ. pyc ในกรณีของฉัน) ไว้ในขั้นตอนคอมไพล์ของคุณ คุณจะทราบว่าในคอมพิวเตอร์เครื่องอื่น ๆ ในทีมของคุณการแจ้งเตือนคอมไพล์มีการเปลี่ยนแปลงระหว่างไฟล์. pyc เมื่อไม่มีการเปลี่ยนแปลงใด ๆ กับไฟล์. py (และ. pyc คอมไพล์ซ้ำอยู่ดี)

อย่างน้อยนั่นคือสิ่งที่ฉันสังเกตเห็น ดังนั้นใส่ * .pyc และ * .class ใน. gitignore ของคุณ!

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