อะไรคือความสัมพันธ์ระหว่าง Any, AnyVal, AnyRef, Object และจะแมปอย่างไรเมื่อใช้ในโค้ด Java


111

ฉันมักจะลองทุกชุดจนกว่าจะรวบรวม ใครช่วยอธิบายได้ไหมว่าฉันควรใช้ที่ไหน

คำตอบ:


125

ฉันจะไม่เห็นด้วยกับคำตอบของ Chris ในเรื่องเดียว เรียน, และมีการเรียน แต่จะไม่ปรากฏเป็นคลาสใน bytecode เนื่องจากข้อ จำกัด ภายในของ JVMAnyAnyRefAnyVal

สิ่งนี้เกิดขึ้นจากข้อเท็จจริงที่ว่าไม่ใช่ทุกอย่างใน Java ที่เป็นวัตถุ นอกจากวัตถุแล้วยังมีวัตถุดึกดำบรรพ์ อ็อบเจ็กต์ทั้งหมดใน Java สืบเชื้อสายมาจากjava.lang.Objectแต่ดั้งเดิมถูกแยกออกจากกันและในปัจจุบัน*ไม่สามารถขยายได้โดยโปรแกรมเมอร์ โปรดทราบด้วยว่าสิ่งดั้งเดิมมี "ตัวดำเนินการ" ไม่ใช่วิธีการ

ในทางกลับกันใน Scala ทุกอย่างเป็นวัตถุวัตถุทั้งหมดเป็นของคลาสและโต้ตอบด้วยวิธีการ JVM bytecode ที่สร้างขึ้นไม่ได้สะท้อนถึงสิ่งนี้ แต่ก็ไม่ได้ทำให้น้อยลงเช่นเดียวกับที่ Java มี generics แม้ว่า bytecode จะไม่มีก็ตาม

ดังนั้นใน Scala วัตถุทั้งหมดจึงสืบเชื้อสายมาจากAnyและรวมถึงสิ่งที่ Java พิจารณาวัตถุและสิ่งที่ Java ถือว่าเป็นสิ่งดั้งเดิม ไม่มีสิ่งที่เทียบเท่าใน Java เนื่องจากไม่มีการรวมกันดังกล่าว

ทุกสิ่งที่ถือว่าเป็นของดั้งเดิมใน Java นั้นสืบเชื้อสายมาจากAnyValใน Scala จนกระทั่ง Scala 2.10.0 AnyValถูกปิดผนึกและโปรแกรมเมอร์ไม่สามารถขยายได้ มันน่าสนใจที่จะดูว่าจะเกิดอะไรขึ้นกับ Scala บน. Net เนื่องจากความสามารถในการทำงานร่วมกันเพียงอย่างเดียวเรียกร้องให้ Scala อย่างน้อยก็รู้จัก "primitives" ที่ผู้ใช้กำหนดเอง

นอกจากนี้การขยายAnyคือAnyRefซึ่งเทียบเท่ากับjava.lang.Object(บน JVM ในอัตราใดก็ได้)

ขึ้นอยู่กับกาลา 2.9.x ผู้ใช้จะไม่สามารถขยายAnyหรือAnyValไม่อ้างอิงพวกเขาจาก Java แต่มีอยู่ใช้งานอื่น ๆ ที่พวกเขาจะถูกนำไปใน Scala โดยเฉพาะพิมพ์ลายเซ็น:

def f(x: AnyVal) = println(x)
def g(x: AnyRef) = println(x)
def h(x: Any) = println(x)

ความหมายแต่ละอย่างควรชัดเจนจากลำดับชั้น อย่างไรก็ตามสิ่งที่ควรทราบคือfและhจะกล่องอัตโนมัติ แต่gจะไม่ นั่นเป็นสิ่งที่ตรงกันข้ามกับสิ่งที่ Java ทำในสิ่งนั้นfและhไม่สามารถระบุได้และg(กำหนดด้วยjava.lang.Object) จะทำให้เกิดการชกมวยอัตโนมัติ

เริ่มต้นด้วย Scala 2.10.0 ผู้ใช้สามารถขยายAnyValหรือAnyด้วยความหมายต่อไปนี้:

  • หากคลาสขยายออกไปจะAnyValไม่มีการสร้างอินสแตนซ์สำหรับมันบนฮีปภายใต้เงื่อนไขบางประการ ซึ่งหมายความว่าฟิลด์ของคลาสนี้ (บน 2.10.0 อนุญาตให้ใช้เพียงฟิลด์เดียว - ไม่ว่าจะยังคงเห็นการเปลี่ยนแปลงอยู่หรือไม่) จะยังคงอยู่บนสแต็กไม่ว่าจะเป็นแบบดั้งเดิมหรือการอ้างอิงถึงอ็อบเจ็กต์อื่น วิธีนี้ช่วยให้สามารถขยายวิธีการได้โดยไม่ต้องเสียค่าใช้จ่ายในการสร้างอินสแตนซ์

  • ถ้าเป็นลักษณะขยายAnyแล้วก็สามารถนำมาใช้กับทั้งการเรียนที่ขยายและการเรียนที่ขยายAnyRefAnyVal

PS: ในมุมมองของฉันเอง Java มีแนวโน้มที่จะทำตาม C # ในการอนุญาตให้ใช้ primitives "struct" และอาจเป็นแบบ typedef เนื่องจากการขนานกันโดยไม่ต้องหันหน้าไปทางพวกเขานั้นพิสูจน์ได้ยากที่จะบรรลุด้วยประสิทธิภาพที่ดี


2
การอัปเดต: ณ Scala 2.9.2 AnyValถูกกำหนดให้เป็นsealed trait AnyVal extends Anyไฟล์. แต่ใน Scala 2.10 นี้มีการเปลี่ยนแปลงไปabstract class AnyVal extends Any with NotNullและมันก็เป็นไปได้ที่จะขยายด้วยคุณลักษณะการเรียนค่าใหม่เช่น:AnyVal class MyValue(val u: Int) extends AnyVal
ebruchez

@ebruchez ขอบคุณสำหรับบันทึก ฉันได้อัปเดตคำตอบของฉันพร้อมภาพรวมของความสามารถใหม่
Daniel C. Sobral

Nothing และ Null เกี่ยวข้องกับเรื่องนี้อย่างไร?
Gaurav Khare


5

AnyและAnyValฉันเชื่อว่าเป็นส่วนหนึ่งของระบบประเภทสกาลาและไม่ใช่คลาสดังกล่าว (ในลักษณะเดียวกับที่Nothingเป็นประเภทไม่ใช่คลาส) คุณไม่สามารถใช้อย่างชัดเจนจากภายในโค้ด Java

Howwever ใน Java / Scala interoperation เมธอดที่ยอมรับ Java Objectจะคาดหวัง scala Any/ AnyRef.

คุณกำลังพยายามทำอะไรอยู่?


ฉันพยายามทำความเข้าใจหัวข้อนี้ให้ดีขึ้นเพื่อที่ฉันจะได้รู้ว่าฉันควรใช้ประเภทใดเมื่อฉันวางแผนที่จะเรียก Java Scala หรือในทางกลับกัน คำตอบนี้stackoverflow.com/questions/2334200/…และคำอธิบายของมันเพื่อAnyRefเตือนฉันว่าสิ่งนี้ยังคงลึกลับสำหรับฉัน
huynhjl
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.