ความแตกต่างระหว่างวัตถุและคลาสใน Scala


635

ฉันเพิ่งจะไปทำแบบฝึกหัด Scala บนอินเทอร์เน็ตและได้สังเกตในบางตัวอย่างวัตถุจะถูกประกาศในตอนเริ่มต้นของตัวอย่าง

ความแตกต่างระหว่างclassและobjectในสกาล่าคืออะไร?

คำตอบ:


578

TL; DR

  • class C กำหนดคลาสเช่นเดียวกับใน Java หรือ C ++
  • object Oสร้างวัตถุเดี่ยวOเป็นตัวอย่างของคลาสที่ไม่ระบุชื่อ มันสามารถใช้เพื่อเก็บสมาชิกคงที่ที่ไม่เกี่ยวข้องกับอินสแตนซ์ของบางชั้นเรียน
  • object O extends Tทำให้วัตถุที่Oเป็นตัวอย่างของtrait T; จากนั้นคุณสามารถผ่านOได้ทุกที่Tคาดว่า
  • ถ้ามีclass Cแล้วobject Cเป็นวัตถุสหายของชั้นC; ทราบว่าวัตถุสหายคือไม่ได้Cโดยอัตโนมัติตัวอย่างของ

ดูเอกสารของสกาล่าสำหรับวัตถุและคลาสด้วย

object เป็นโฮสต์ของสมาชิกแบบคงที่

บ่อยครั้งที่คุณต้องมีobjectวิธีการเก็บและค่า / ตัวแปรที่จะสามารถใช้ได้โดยไม่ต้องยกตัวอย่างแรกของบางคลาส การใช้งานนี้เกี่ยวข้องอย่างใกล้ชิดกับstaticสมาชิกใน Java

object A {
  def twice(i: Int): Int = 2*i
}

จากนั้นคุณสามารถเรียกใช้วิธีการข้างต้นA.twice(2)ได้

ถ้าtwiceเป็นสมาชิกของบางคลาสAคุณจะต้องสร้างอินสแตนซ์ก่อน:

class A() {
  def twice(i: Int): Int = 2 * i
}

val a = new A()
a.twice(2)

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

object เป็นตัวอย่างที่มีชื่อพิเศษ

คุณสามารถใช้objectตัวมันเองเป็นตัวอย่างพิเศษของคลาสหรือลักษณะพิเศษได้ เมื่อคุณทำเช่นนี้วัตถุของคุณจำเป็นต้องขยายบางส่วนtraitเพื่อที่จะกลายเป็นตัวอย่างของคลาสย่อยของมัน

พิจารณารหัสต่อไปนี้:

object A extends B with C {
  ...
}

ประกาศนี้ครั้งแรกประกาศไม่ระบุชื่อ (ไม่สามารถเข้าถึงได้) คลาสที่ขยายทั้งสองBและCและ instantiates Aเช่นเดียวของชั้นนี้ชื่อ

วิธีนี้Aสามารถส่งผ่านไปยังฟังก์ชั่นคาดหวังว่าวัตถุชนิดBหรือหรือCB with C

คุณสมบัติเพิ่มเติมของ object

นอกจากนี้ยังมีคุณสมบัติพิเศษบางอย่างของวัตถุใน Scala ผมขอแนะนำให้อ่านเอกสารอย่างเป็นทางการ

  • def apply(...) เปิดใช้งานวิธีการไวยากรณ์น้อยชื่อปกติของ A(...)
  • def unapply(...)อนุญาตให้สร้างรูปแบบการแยกชุดรูปแบบที่กำหนดเอง
  • หากมีคลาสชื่อเดียวกันวัตถุจะถือว่ามีบทบาทพิเศษเมื่อแก้ไขพารามิเตอร์โดยนัย

38
นอกจากนี้ยังจะกำหนดคลาส A และสร้างวิธีการทั้งหมดในวัตถุ A เป็นวิธีการคงที่ในคลาส A (สำหรับการเชื่อมต่อกับ Java) (Modulo ข้อผิดพลาดใน Scala 2.7 ที่ได้รับการแก้ไขใน Scala 2.8)
เคนบลูม

2
@ เคนบลูมจริงๆเหรอ? ฉันพยายามและไม่ทำงาน: scala> Commerce res8: Commerce.type = Commerce $ @ 6eb2756 scala> classOf [Commerce] <console>: 23: ข้อผิดพลาด: ไม่พบ: พิมพ์ Commerce classOf [Commerce] ^ scala> Commerce ใหม่ < คอนโซล>: 23: ข้อผิดพลาด: ไม่พบ: พิมพ์ Commerce new Commerce ^
Hendy Irawan

3
@Hendy: Scala จะไม่จดจำCommerceคลาส แต่ภาษา JVM และภาษาจาวาจะเป็นเช่นนั้น (นั่นเป็นวิธีที่คุณสามารถทำได้object Foo{ def main(args:Seq[String]) }และคาดว่าโปรแกรมจะทำงาน)
Ken Bloom

3
ฉันคิดว่าคำตอบของ ziggystar นั้นแม่นยำยิ่งขึ้นคลาสนั้นเป็นคลาสที่ไม่ระบุตัวตนยกเว้นว่าคลาสที่เกี่ยวข้องชื่อ Commerce ถูกกำหนดไว้อย่างชัดเจน (จากนั้นวัตถุเชิงพาณิชย์จะเป็นวัตถุร่วมกับชั้นพาณิชย์)
Hendy Irawan

3
@DavidApltauer ฉันเดิมพันว่ามีรายละเอียดปลีกย่อยที่ไม่ครอบคลุมโดยคำตอบของฉัน แต่สิ่งเหล่านั้นอาจไม่สำคัญสำหรับคนส่วนใหญ่ที่อ่านข้อความนี้ และฉันไม่เคยมีปัญหากับการส่งวัตถุเป็นตัวอย่างของลักษณะบางอย่างซึ่งไม่ได้หมายความว่ามันไม่มีอยู่จริง แต่มันควรจะทำงาน
ziggystar

249

A classคือคำจำกัดความคำอธิบาย มันกำหนดประเภทในแง่ของวิธีการและองค์ประกอบของประเภทอื่น ๆ

An objectเป็น singleton - อินสแตนซ์ของคลาสที่รับประกันว่าจะไม่ซ้ำกัน สำหรับทุก ๆobjectในรหัสคลาสนิรนามจะถูกสร้างขึ้นซึ่งสืบทอดมาจากคลาสใดก็ตามที่คุณประกาศว่าobjectจะนำไปใช้ คลาสนี้ไม่สามารถมองเห็นได้จากซอร์สโค้ดของสกาล่า - แม้ว่าคุณจะสามารถผ่านมันไปได้

มีความสัมพันธ์ระหว่างเป็นและobject classวัตถุถูกกล่าวว่าเป็นวัตถุร่วมของชั้นเรียนหากพวกเขาใช้ชื่อเดียวกัน เมื่อสิ่งนี้เกิดขึ้นแต่ละคนจะสามารถเข้าถึงวิธีการprivateมองเห็นในที่อื่น ๆ แม้ว่าวิธีการเหล่านี้จะไม่นำเข้าโดยอัตโนมัติ คุณต้องนำเข้าอย่างชัดเจนหรือนำหน้าด้วยชื่อคลาส / วัตถุ

ตัวอย่างเช่น:

class X {
  // class X can see private members of object X
  // Prefix to call
  def m(x: Int) = X.f(x)

  // Import and use
  import X._
  def n(x: Int) = f(x)

  private def o = 2
}

object X {
  private def f(x: Int) = x * x

  // object X can see private members of class X
  def g(x: X) = {
    import x._
    x.o * o // fully specified and imported
   }
}

1
ขออภัยที่รบกวนคุณ แต่คุณอาจชี้ไปที่ตัวอย่างเกี่ยวกับวิธีการนำเข้าวิธีการไปยังวัตถุที่แสดงร่วมหรือวิธีนำหน้าพวกเขาได้อย่างไร
ithkuil

4
@ithkuil เรียบร้อยแล้ว ขออภัยเกี่ยวกับตัวอย่างที่โง่ฉันไม่สามารถนึกถึงสิ่งที่ดีและสั้นได้
Daniel C. Sobral

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

@piyushGoyal ไม่จริง สมมติว่าวัตถุมีเมธอดdef f(x: X) = ???จากนั้นจะสามารถเรียกใช้เมธอดส่วนตัวxของคลาสที่แสดงร่วมXได้
Daniel C. Sobral

ที่นี่ X ที่ผ่านมาในฟังก์ชั่นเป็นตัวอย่างของคลาส XI เดา? ถ้าใช่ในที่สุดคุณก็ใช้อ็อบเจกต์ x เพื่อเรียกเมธอดของคลาส X ใน def f .. ใช่ไหม?
piyushGoyal

76

วัตถุมีหนึ่งอินสแตนซ์ที่แน่นอน(คุณไม่สามารถโทรได้new MyObject) คุณสามารถมีคลาสได้หลายอินสแตนซ์

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


19

ตามที่อธิบายโดยหลาย ๆ คนให้objectนิยามอินสแตนซ์ซิงเกิล สิ่งหนึ่งในคำตอบที่นี่ที่ฉันเชื่อว่าถูกทิ้งไว้คือobjectให้บริการหลายวัตถุประสงค์

  • มันสามารถเป็นวัตถุร่วมกับclass/ trait, ที่มีสิ่งที่อาจจะพิจารณาวิธีการคงที่หรือวิธีการอำนวยความสะดวก

  • สามารถทำหน้าที่เหมือนโมดูลที่มีประเภทและคำจำกัดความที่เกี่ยวข้อง / บริษัท ย่อย ฯลฯ

  • มันสามารถใช้อินเทอร์เฟซโดยการขยายclassอย่างน้อยหนึ่งtraitรายการ

  • มันสามารถเป็นตัวแทนของกรณีsealed traitที่ไม่มีข้อมูล ในแง่นี้มันมักถูกพิจารณาว่าถูกต้องมากกว่า a ที่case classไม่มีพารามิเตอร์ กรณีพิเศษของ a ที่sealed traitมีตัวcase objectดำเนินการเพียงอย่างเดียวคือ Enum เวอร์ชัน Scala มากหรือน้อย

  • มันสามารถทำหน้าที่เป็นหลักฐานสำหรับimplicitตรรกะไดรฟ์

  • มันแนะนำประเภทเดี่ยว

มันเป็นโครงสร้างที่ทรงพลังและทั่วไปมาก สิ่งที่อาจสร้างความสับสนให้กับผู้เริ่มต้นสกาล่าก็คือโครงสร้างที่เหมือนกันสามารถใช้งานได้อย่างมากมาย และobjectสามารถให้บริการการใช้งานที่แตกต่างกันเหล่านี้ทั้งหมดในครั้งเดียวซึ่งอาจทำให้เกิดความสับสนมากยิ่งขึ้น


18

การกำหนดวัตถุใน Scala ก็เหมือนกับการกำหนดคลาสใน Java ที่มีวิธีการคงที่เท่านั้น อย่างไรก็ตามใน Scala วัตถุสามารถขยายซูเปอร์คลาสอื่นให้ใช้อินเทอร์เฟซและส่งผ่านราวกับว่ามันเป็นตัวอย่างของคลาส (ดังนั้นมันก็เหมือนกับวิธีการคงที่ในชั้นเรียน แต่ดีกว่า)


17

ความแตกต่างอย่างเป็นทางการ -

  1. คุณไม่สามารถให้พารามิเตอร์คอนสตรัคสำหรับวัตถุ
  2. วัตถุไม่ใช่ประเภท - คุณไม่สามารถสร้างอินสแตนซ์กับโอเปอเรเตอร์ใหม่ได้ แต่มันสามารถมีฟิลด์วิธีขยายซูเปอร์คลาสและมิกซ์ในลักษณะ

ความแตกต่างในการใช้งาน:

  • สกาล่าไม่มีวิธีการคงที่หรือสาขา objectแต่คุณควรใช้ คุณสามารถใช้มันโดยมีหรือไม่มีคลาสที่เกี่ยวข้อง ในกรณีที่ 1 เรียกว่าวัตถุที่แสดงร่วม คุณต้อง:
    1. ใช้ชื่อเดียวกันสำหรับทั้งคลาสและวัตถุ
    2. วางไว้ในไฟล์ต้นฉบับเดียวกัน
  • การสร้างโปรแกรมที่คุณควรใช้วิธีการหลักในการไม่ได้อยู่ในobjectclass

    object Hello {
      def main(args: Array[String]) {
        println("Hello, World!")
      }
    }
  • คุณอาจจะใช้มันเมื่อคุณใช้วัตถุ singleton ใน java

      
        
      


"คุณไม่สามารถให้พารามิเตอร์คอนสตรัคเตอร์สำหรับวัตถุ" วัตถุมีเมธอด Apply (... ) ซึ่งทำหน้าที่เหมือนคอนสตรัคเตอร์มาก ทำให้ฉันสับสนเล็กน้อย
แดเนียล

7

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

Scala ไม่เทียบเท่ากับคำสำคัญคงที่ของ Java และวัตถุมักจะใช้ใน Scala ที่คุณอาจใช้คลาสที่มีสมาชิกคงที่ใน Java


6

วัตถุเป็นคลาส แต่มีอินสแตนซ์ (เป็น) อยู่แล้วดังนั้นคุณจึงไม่สามารถโทรnew ObjectNameได้ บนมืออื่น ๆ , ชั้นnew ClassName()เป็นเพียงประเภทและสามารถเป็นตัวอย่างโดยการโทร


4

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

ตัวอย่างวัตถุ Scala Singleton

object Singleton{  
    def main(args:Array[String]){  
        SingletonObject.hello()         // No need to create object.  
    }  
}  


object SingletonObject{  
    def hello(){  
        println("Hello, This is Singleton Object")  
    }  
}  

เอาท์พุท:

Hello, This is Singleton Object

ในสกาล่าเมื่อคุณมีคลาสที่มีชื่อเดียวกับวัตถุซิงเกิลมันจะเรียกว่าคลาสสหายและวัตถุซิงเกิลเรียกว่าสหายวัตถุ

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

ตัวอย่างวัตถุ Scala Companion

class ComapanionClass{  
    def hello(){  
        println("Hello, this is Companion Class.")  
    }  
}  
object CompanoinObject{  
    def main(args:Array[String]){  
        new ComapanionClass().hello()  
        println("And this is Companion Object.")  
    }  
}  

เอาท์พุท:

Hello, this is Companion Class.
And this is Companion Object.

ในสกาล่าคลาสสามารถมี:

1. ข้อมูลสมาชิก

2. วิธีการเป็นสมาชิก

3. ตัวสร้างบล็อก

4. ชั้นซ้อน

5. ข้อมูลระดับซูเปอร์ ฯลฯ

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

ตัวอย่าง Scala ตัวอย่างของการเรียน

class Student{  
    var id:Int = 0;                         // All fields must be initialized  
    var name:String = null;  
}  
object MainObject{  
    def main(args:Array[String]){  
        var s = new Student()               // Creating an object  
        println(s.id+" "+s.name);  
    }  
} 

ฉันขอโทษฉันสายเกินไป แต่ฉันหวังว่ามันจะช่วยคุณได้


2

คลาส Scala เหมือนกับ Java Class แต่ scala ไม่ได้ให้วิธีการเข้าเรียนใด ๆ ในชั้นเรียนเหมือนกับวิธีหลักใน java วิธีการหลักที่เกี่ยวข้องกับคำหลักวัตถุ คุณสามารถนึกถึงคำสำคัญของวัตถุว่าเป็นการสร้างวัตถุเดี่ยวของชั้นที่กำหนดโดยปริยาย

ข้อมูลเพิ่มเติมตรวจสอบคลาสของบทความนี้ และคำสำคัญของวัตถุในการเขียนโปรแกรมสกาล่า


2

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


1

คลาสเหมือนกับคลาสอื่น ๆ ในภาษาอื่น คุณกำหนดคลาสเหมือนกับภาษาอื่นที่มีความแตกต่างทางไวยากรณ์

class Person(val name: String)
val me = new Person("My name")

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

class Person(var name: String) {

  import Person._

  def hi(): String = sayHello(name)
}

object Person {
  private def sayHello(name: String): String = "Hello " + name
}

val me = new Person("My name")
me.hi()

นอกจากนี้จุดสำคัญคือคลาสวัตถุนั้นถูกสร้างขึ้นอย่างขี้เกียจซึ่งเป็นอีกจุดสำคัญ ดังนั้นสิ่งเหล่านี้จะไม่ถูกยกตัวอย่างเว้นแต่ว่ามันจำเป็นในรหัสของเรา

หากคุณกำลังกำหนดการสร้างการเชื่อมต่อสำหรับ JDBC คุณสามารถสร้างพวกเขาภายในวัตถุเพื่อหลีกเลี่ยงการทำซ้ำเช่นเดียวกับที่เราทำใน Java กับวัตถุเดี่ยว


0

หากคุณมาจากพื้นหลัง java แนวคิดของคลาสใน scala นั้นคล้ายกับ Java แต่คลาสใน scala ไม่สามารถมีสมาชิกแบบสแตติกได้

วัตถุในสกาล่าเป็นประเภทเดี่ยวที่คุณเรียกใช้วิธีการภายในโดยใช้ชื่อวัตถุในวัตถุสกาล่าเป็นคำหลักและในวัตถุ Java เป็นตัวอย่างของการเรียน

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