Scala中对象和类之间的区别


635

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

classobjectScala 和有什么不一样?

Answers:


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

另请参阅Scala文档以获取对象

object 作为静态成员的主机

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

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可以被传递到期望类型的对象的功能BC,或B with C

的附加功能 object

Scala中还存在一些对象的特殊功能。我建议阅读官方文档

  • def apply(...) 启用的常规方法的无名称语法 A(...)
  • def unapply(...)允许创建自定义模式匹配提取器
  • 如果附带同名的类,则对象在解析隐式参数时将扮演特殊角色

38
它还将定义类A,并在对象A中将所有方法创建为类A上的静态方法(用于与Java接口)。(模在斯卡拉2.7的一个错误是一直固定在斯卡拉2.8)
肯·布鲁姆

2
@KenBloom真的吗?我尝试了并且不起作用:scala> Commerce res8:Commerce.type = Commerce $ @ 6eb2756 scala> classOf [Commerce] <控制台>:23:错误:找不到:类型Commerce classOf [Commerce] ^ scala>新Commerce <控制台>:23:错误:未找到:键入Commerce New Commerce ^
Hendy Irawan

3
@Hendy:Scala无法识别Commerce该类,但是JVM和Java语言可以识别。(这是您可以做的,object Foo{ def main(args:Seq[String]) }并希望程序能够运行。)
Ken Bloom

3
我认为ziggystar的答案更为精确,该类是一个匿名类,除非明确定义了一个名为Commerce的对应类(然后Commerce对象将成为Commerce类的伴侣对象)
Hendy Irawan

3
@DavidApltauer我敢打赌,答案中没有包含足够的细节。但是对于大多数阅读此书的人来说,这些可能并不重要。而且我从来没有遇到过将对象作为某些特征的实例传递的问题,这并不意味着它们不存在。但应该可以。
ziggystar

249

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

An object是单例-保证是唯一的类的实例。对于object代码中的每个代码,都会创建一个匿名类,该匿名类继承自您声明object要实现的任何类。从Scala源代码中看不到此类,尽管您可以通过反射来了解。

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 2010年

4
@ithkuil完成。对不起这个愚蠢的例子,我想不出一个好而简短的例子。
Daniel C. Sobral

如果我想在对象中使用类方法怎么办?那有可能吗?如果我有一个类的方法,并且想在Object中使用它,那么如果您尝试导入该类,则将无法使用。最终,您必须创建一个构造函数,然后调用该方法。因此,通过创建同伴对象,您可以使用导入来访问对象的方法,反之亦然。有人可以验证吗?
piyushGoyal,2015年

@piyushGoyal不正确。假设对象有一个方法def f(x: X) = ???,那么它将能够x在同伴类中调用私有方法X
Daniel C. Sobral

这里传递给函数的X是XI类的实例吗?如果是,那么最终您将使用对象x来调用def f中的X类的方法。
piyushGoyal,2015年

76

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

对象具有 Java中的静态方法和字段相同(和一些其他)目的


19

正如许多人所解释的,object定义了一个单例实例。我认为这里答案中的一件事被遗漏了,object它有几个目的。

  • 它可以是伴侣对象为class/ trait,包含了可能被认为是静态的方法或便捷方法。

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

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

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

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

  • 它引入了单例类型。

这是一个非常强大且通用的结构。对于Scala初学者来说,非常令人困惑的是,同一构造可能具有截然不同的用途。一次object可以服务于许多这些不同的用途,这可能会更加令人困惑。


18

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


17

形式上的差异-

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

用法的区别:

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

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

      
        
      


“您不能为对象提供构造函数参数”对象具有apply(...)方法,其功能与构造函数非常相似。这让我有些困惑。
丹妮尔(Danielle)

7

对象关键字创建一个新的单型,这就好比一个是只有一个命名实例。如果您熟悉Java,则声明一个对象在Scala中就像创建一个匿名类的新实例一样。

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


6

对象是一个类,但是它已经有一个实例,因此您不能调用new ObjectName。另一方面,Class只是类型,可以通过调用作为实例new ClassName()


4

在scala中,没有static概念。因此,scala创建了一个singleton对象,以提供程序执行的入口点。如果不创建单例对象,则代码将成功编译,但不会产生任何输出。在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中,当您拥有与单例对象同名的类时,该类称为伴随类,而单例对象称为伴随对象。

伴随类及其伴随对象都必须在同一源文件中定义。

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

抱歉,为时已晚,但希望对您有所帮助。


2

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

更多信息,请在scala编程中检查本文的 类和对象关键字


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定义连接创建,则可以在object内部创建它们以避免重复,就像在Java中使用singleton对象一样。


0

如果您来自Java背景,则scala中的类概念类似于Java,但是scala中的类不能包含静态成员。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.