Scala:哪些类不应该有伴生对象?

Scala:哪些类不应该有伴生对象?,scala,companion-object,Scala,Companion Object,以下模式似乎是scala的惯用模式: class Foo() {} object Foo { def apply() = new Foo() } val x = Foo() 惯用方法的动机是什么?在哪些情况下,我不应该提供工厂方法,强制客户端使用val y=new Foo()?所有带有伴生对象的案例是否都应提供工厂方法 如果以下任何一项都不适用,则类不需要伴生对象: 类中有一些功能与实例无关(在Java中称为“静态”) 人们希望提供一个构造函数,避免调用new。这在Scala中通过使用Som

以下模式似乎是scala的惯用模式:

class Foo() {}
object Foo { def apply() = new Foo() }
val x = Foo()

惯用方法的动机是什么?在哪些情况下,我不应该提供工厂方法,强制客户端使用
val y=new Foo()
?所有带有伴生对象的案例是否都应提供工厂方法

如果以下任何一项都不适用,则类不需要伴生对象:

  • 类中有一些功能与实例无关(在Java中称为“静态”)
  • 人们希望提供一个构造函数,避免调用
    new
    。这在Scala中通过使用
    SomeClass.apply(params)
如果上面没有一个是感兴趣的,那么就不需要伴生对象。
如果您有这些需求,那么伴生对象是一个有用的结构。如果没有,就没有理由拥有它。我不知道有什么理由绝对没有伴星。这是一个不需要编写的工具。

Case class apply通常由编译器重写为new。如果您编写一个自定义应用程序,即使是一个很小的应用程序,也无法做到这一点

隐式值类周围可能存在类似的边缘情况

$ scala
Welcome to Scala 2.12.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.

scala> case class K(i: Int)
defined class K

scala> K(42)
res0: K = K(42)

scala> :javap -c res0
Compiled from "<console>"
public class $line4.$read$$iw$$iw$ {
  public static $line4.$read$$iw$$iw$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class $line4/$read$$iw$$iw$
       3: invokespecial #28                 // Method "<init>":()V
       6: return

  public $line3.$read$$iw$$iw$K res0();
    Code:
       0: aload_0
       1: getfield      #31                 // Field res0:L$line3/$read$$iw$$iw$K;
       4: areturn

  public $line4.$read$$iw$$iw$();
    Code:
       0: aload_0
       1: invokespecial #33                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: putstatic     #35                 // Field MODULE$:L$line4/$read$$iw$$iw$;
       8: aload_0
       9: new           #14                 // class $line3/$read$$iw$$iw$K
      12: dup
      13: bipush        42
      15: invokespecial #38                 // Method $line3/$read$$iw$$iw$K."<init>":(I)V
      18: putfield      #31                 // Field res0:L$line3/$read$$iw$$iw$K;
      21: return
}

scala> case class K(i: Int) ; object K { def apply(j: Int) = new K(j) }
defined class K
defined object K

scala> K(42)
res1: K = K(42)

scala> :javap -c res1
Compiled from "<console>"
public class $line6.$read$$iw$$iw$ {
  public static $line6.$read$$iw$$iw$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class $line6/$read$$iw$$iw$
       3: invokespecial #31                 // Method "<init>":()V
       6: return

  public $line5.$read$$iw$$iw$K res1();
    Code:
       0: aload_0
       1: getfield      #34                 // Field res1:L$line5/$read$$iw$$iw$K;
       4: areturn

  public $line6.$read$$iw$$iw$();
    Code:
       0: aload_0
       1: invokespecial #36                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: putstatic     #38                 // Field MODULE$:L$line6/$read$$iw$$iw$;
       8: aload_0
       9: getstatic     #41                 // Field $line5/$read$$iw$$iw$K$.MODULE$:L$line5/$read$$iw$$iw$K$;
      12: bipush        42
      14: invokevirtual #45                 // Method $line5/$read$$iw$$iw$K$.apply:(I)L$line5/$read$$iw$$iw$K;
      17: putfield      #34                 // Field res1:L$line5/$read$$iw$$iw$K;
      20: return
}
$scala
欢迎使用Scala 2.12.3(OpenJDK 64位服务器虚拟机,Java 1.8.0131)。
键入要计算的表达式。或者尝试:帮助。
scala>案例类K(i:Int)
定义类K
scala>K(42)
res0:K=K(42)
scala>:javap-c res0
从“”编译
公共类$line4.$read$$iw$$iw${
公共静态$line4.$read$$iw$$iw$MODULE$;
公共静态{};
代码:
0:new#2//class$line4/$read$$iw$$iw$
3:invokespecial#28//方法“”:()V
6:返回
public$line3.$read$$iw$$iw$K res0();
代码:
0:aload_0
1:getfield#31//Field res0:L$line3/$read$$iw$$iw$K;
4:轮到你了
公共$line4.$read$$iw$$iw$();
代码:
0:aload_0
1:invokespecial#33//方法java/lang/Object。“:()V
4:aload_0
5:putstatic#35//字段模块$:L$line4/$read$$iw$$iw$;
8:aload_0
9:new#14//class$line3/$read$$iw$$iw$K
12:dup
13:bipush 42
15:invokespecial#38//Method$line3/$read$$iw$$iw$K.“”:(I)V
18:putfield#31//Field res0:L$line3/$read$$iw$$iw$K;
21:返回
}
scala>case类K(i:Int);对象K{def apply(j:Int)=新K(j)}
定义类K
定义对象K
scala>K(42)
res1:K=K(42)
scala>:javap-c res1
从“”编译
公共类$line6.$read$$iw$$iw${
公共静态$line6.$read$$iw$$iw$MODULE$;
公共静态{};
代码:
0:new#2//class$line6/$read$$iw$$iw$
3:invokespecial#31//方法“”:()V
6:返回
public$line5.$read$$iw$$iw$K res1();
代码:
0:aload_0
1:getfield#34//Field res1:L$line5/$read$$iw$$iw$K;
4:轮到你了
公共$line6.$read$$iw$$iw$();
代码:
0:aload_0
1:invokespecial#36//方法java/lang/Object。“:()V
4:aload_0
5:putstatic#38//字段模块$:L$line6/$read$$iw$$iw$;
8:aload_0
9:getstatic#41//字段$line5/$read$$iw$$iw$K$。模块$:L$line5/$read$$iw$$iw$K$;
12:bipush 42
14:invokevirtual#45//方法$line5/$read$$iw$$iw$K$。应用:(I)L$line5/$read$$iw$$iw$K;
17:putfield#34//Field res1:L$line5/$read$$iw$$iw$K;
20:返回
}

这就是
case
类的用途
case类Foo(){}
将使用相同的
apply
方法自动生成
对象Foo
(事实上,它将生成更多)。前面的一个问题解决了你的大部分问题。两个几乎相同的问题。我想这个问题可以重新表述为“对于哪些类,我们需要一个构造函数而不需要
new
”?有会议吗?@Bergi——事实上,这就是我想要表达的意思。我也看到了。我明白,在许多情况下,这并不是真正需要的。