【问题标题】:Difference between object and class in ScalaScala中对象和类之间的区别
【发布时间】:2010-12-17 20:11:07
【问题描述】:

我刚刚浏览了 Internet 上的一些 Scala 教程,并注意到在一些示例中,在示例开头声明了一个对象。

Scala 中的classobject 有什么区别?

【问题讨论】:

    标签: scala class object


    【解决方案1】:

    一个对象恰好有一个实例(你不能调用new MyObject)。您可以拥有一个类的多个实例。

    Object 与 Java 中的静态方法和字段具有相同(以及一些额外的)用途

    【讨论】:

      【解决方案2】:

      tl;博士

      • class C 定义了一个类,就像在 Java 或 C++ 中一样。
      • object O 创建一个 singleton 对象 O 作为某个匿名类的实例;它可用于保存与某些类的实例无关的静态成员。
      • object O extends T 使对象 O 成为 trait T 的实例;然后,您可以在任何地方传递O,应该是T
      • 如果有class C,那么object CC类的companion object;请注意,伴随对象不会自动成为C 的实例。

      另请参阅 objectclass 的 Scala 文档。

      object 作为静态成员的宿主

      大多数情况下,您需要object 来保存无需先实例化某个类的实例即可使用的方法和值/变量。 这种用法与 Java 中的static 成员密切相关。

      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 {
        ...
      }
      

      此声明首先声明了一个匿名(不可访问)类,它同时扩展了BC,并实例化了一个名为A 的此类的单个实例。

      这意味着 A 可以传递给期望类型为 BCB with C 的对象的函数。

      object 的附加功能

      Scala 中还存在一些对象的特殊功能。 我推荐阅读official documentation

      • def apply(...) 启用 A(...) 的常用方法无名语法
      • def unapply(...) 允许创建自定义模式匹配 extractors
      • 如果伴随同名的类,则对象在解析implicit parameters时承担特殊角色

      【讨论】:

      • 它还将定义类 A,并将对象 A 中的所有方法创建为类 A 上的静态方法(用于与 Java 交互)。 (以 Scala 2.7 中的一个错误为模,在 Scala 2.8 中已修复)
      • @KenBloom 真的吗?我试过但没有用: scala> Commerce res8: Commerce.type = Commerce$@6eb2756 scala> classOf[Commerce] :23: error: not found: type Commerce classOf[Commerce] ^ scala> new Commerce :23:错误:未找到:键入Commerce new Commerce ^
      • @Hendy:Scala 不会识别Commerce 类,但 JVM 和 Java 语言会。 (这就是您可以执行object Foo{ def main(args:Seq[String]) } 并期望程序运行的方式。)
      • 我觉得ziggystar的回答比较准确,类是匿名类,除非明确定义了对应的名为Commerce的类(那么Commerce对象将是Commerce类的伴生对象)
      • @DavidApltauer 我敢打赌,我的回答没有涵盖足够多的微妙之处。但对于大多数阅读本文的人来说,这些可能并不重要。而且我从来没有遇到过将对象作为某些特征的实例传递的问题,这并不意味着它们不存在;但它应该可以工作。
      【解决方案3】:

      class 是一个定义,一个描述。它根据其他类型的方法和组合来定义一个类型。

      object 是一个单例——一个保证唯一的类的实例。对于代码中的每个object,都会创建一个匿名类,它继承自您声明object 以实现的任何类。这个类不能从 Scala 源代码中看到——尽管你可以通过反射得到它。

      objectclass 之间存在关系。如果一个对象具有相同的名称,则称它们是一个类的伴生对象。发生这种情况时,每个人都可以访问对方的 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
         }
      }
      

      【讨论】:

      • 很抱歉打扰您,但您能否举个例子,说明如何将方法导入伴随对象或如何为它们添加前缀?
      • @ithkuil 完成。抱歉这个愚蠢的例子,我想不出一个又好又短的例子。
      • 如果我想在 Object 中使用类方法怎么办?那可能吗?如果我有一个类的方法并且我想在 Object 中使用它,那么如果你尝试导入该类,你将无法做到。最终,您必须创建一个构造函数并调用该方法。因此,通过创建伴随对象,您可以使用 import 访问 Object 的方法,反之则不行。有人可以验证吗?
      • @piyushGoyal 不正确。假设该对象有一个方法def f(x: X) = ???,那么它将能够调用伴生类Xx 上的私有方法。
      • 函数中传入的 X 我猜是 X 类的实例?如果是,那么最终您将使用对象 x 来调用定义中的 X 类的方法。对吗?
      【解决方案4】:

      在 Scala 中定义一个对象就像在 Java 中定义一个只有静态方法的类。然而,在 Scala 中,一个对象可以扩展另一个超类,实现接口,并像一个类的实例一样被传递。 (所以它就像类上的静态方法,但更好)。

      【讨论】:

        【解决方案5】:

        形式上的区别——

        1. 您不能为对象提供构造函数参数
        2. Object 不是类型 - 您不能使用 new 运算符创建实例。但它可以有字段、方法、扩展超类和混合特征。

        用法上的区别:

        • Scala 没有静态方法或字段。相反,您应该使用object。您可以在有或没有相关类的情况下使用它。在第一种情况下,它被称为伴随对象。你必须:
          1. 对类和对象使用相同的名称
          2. 将它们放在同一个源文件中。
        • 要创建程序,您应该使用object 中的main 方法,而不是class

          object Hello {
            def main(args: Array[String]) {
              println("Hello, World!")
            }
          }
          
        • 您也可以像在 java 中使用单例对象一样使用它。

            

        【讨论】:

        • "你不能为对象提供构造函数参数" 对象有 apply(...) 方法,它的功能很像构造函数。这让我有点困惑。
        【解决方案6】:

        正如许多人所解释的,object 定义了一个单例实例。我认为这里的答案中被忽略的一件事是object 有多种用途。

        • 它可以是 class/trait 的伴随对象,包含可能被视为静态方法或便利方法的对象。

        • 它可以像模块一样工作,包含相关/附属类型和定义等。

        • 它可以通过扩展一个class或一个或多个traits来实现一个接口。

        • 它可以表示不包含数据的sealed trait 的情况。在这方面,它通常被认为比没有参数的case class 更正确。 sealed trait 只有 case object 实现者的特殊情况或多或少是枚举的 Scala 版本。

        • 它可以作为implicit驱动逻辑的证据。

        • 它引入了单例类型。

        这是一个非常强大且通用的结构。 Scala 初学者可能会非常困惑的是,相同的结构可以有截然不同的用途。而object 可以同时服务于这些不同的用途,这可能会更加令人困惑。

        【讨论】:

          【解决方案7】:

          对象在某种程度上类似于Java中的静态类,静态特性意味着静态类在放到JVM中时不需要创建对象,可以直接使用它的类名和同一个实例(相同的数据状态)在任何地方共享。

          【讨论】:

            【解决方案8】:

            object 关键字创建了一个新的单例类型,它就像一个只有一个命名实例的class。如果您熟悉 Java,那么在 Scala 中声明一个 object 很像创建一个匿名类的新实例。

            Scala 没有等效于 Java 的 static 关键字,并且 object 经常在 Scala 中使用,您可以在 Java 中使用具有静态成员的类。

            【讨论】:

              【解决方案9】:

              Object 是一个类,但它已经有一个实例,所以你不能调用new ObjectName。另一方面,Class 只是类型,它可以通过调用new ClassName() 成为实例。

              【讨论】:

                【解决方案10】:

                Scala 类与 Java 类相同,但 scala 没有为您提供类中的任何入口方法,如 java 中的 main 方法。与对象关键字关联的主要方法。您可以将 object 关键字视为创建隐式定义的类的单例对象。

                更多信息查看这篇文章 class and object keyword in scala programming

                【讨论】:

                  【解决方案11】:

                  在 Scala 中,没有 static 的概念。因此 scala 创建了一个单例对象来为您的程序执行提供入口点。 如果您不创建单例对象,您的代码将成功编译,但不会产生任何输出。在 Singleton Object 中声明的方法可以全局访问。单例对象可以扩展类和特征。

                  Scala 单例对象示例

                  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中,当你有一个与单例对象同名的类时,它被称为伴生类,单例对象被称为伴生对象。

                  伴生类和它的伴生对象都必须在同一个源文件中定义。

                  Scala 伴随对象示例

                  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.
                  

                  在scala中,一个类可以包含:

                  1.数据成员

                  2。成员方法

                  3。构造函数块

                  4.嵌套类

                  5.超类信息等

                  您必须初始化类中的所有实例变量。没有默认范围。如果您不指定访问范围,则它是公共的。必须有一个定义了 main 方法的对象。它为您的程序提供了起点。在这里,我们创建了一个类的示例。

                  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);  
                      }  
                  } 
                  

                  对不起,我来晚了,但我希望它能帮助你。

                  【讨论】:

                    【解决方案12】:

                    如果你是java背景,scala中类的概念有点类似于Java,但是scala中的类不能包含静态成员。

                    scala 中的对象是单例类型,您可以使用对象名称在其中调用方法,scala 中的对象是关键字,而 java 中的对象是类的实例

                    【讨论】:

                      【解决方案13】:

                      一个类就像其他语言中的任何其他类一样。您可以像定义任何其他语言一样定义类,但有一些语法差异。

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

                      但是,object 是一个只有单个对象的类。这很有趣,因为它可以用于使用 companion object 创建类的静态成员。这个伴生对象可以访问类定义的私有成员,并且它与您定义的类同名。

                      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 中使用单例对象所做的那样。

                      【讨论】:

                        猜你喜欢
                        • 2014-10-19
                        • 2013-10-05
                        • 2013-06-16
                        • 1970-01-01
                        • 2010-11-15
                        • 1970-01-01
                        • 2017-10-04
                        • 2017-07-16
                        相关资源
                        最近更新 更多