为啥私有构造函数在案例类中仍然可见?

Posted

技术标签:

【中文标题】为啥私有构造函数在案例类中仍然可见?【英文标题】:Why is private constructor still visible in case class?为什么私有构造函数在案例类中仍然可见? 【发布时间】:2020-11-05 22:13:45 【问题描述】:

我想将构造函数及其字段隐藏在一个类中,并且只使用伴随对象创建实例,但我无法实现。我有 scala 2.13.3,它基于 java 8。这是一个代码示例:

A.scala

package X

object A 
  def apply(x: Int): A = A(Seq(x))


case class A private(private val s: Seq[Int])

B.scala

package Y

import X.A

class B 
  val b = A(Seq.empty)

虽然我只想让apply(x:Int) 可见,但这段代码会编译,因此私有构造函数也是可见的。如何更改此代码以按预期工作?

【问题讨论】:

如果您希望构造函数和字段是私有的,您可能希望使用普通类而不是案例类。这样您就不需要隐藏伴随对象中的默认应用。此外,copy 方法使构造函数再次公开。 【参考方案1】:

将方法A.apply(Seq[Int])也设为私有

A.scala

package X

object A 
  def apply(x: Int): A = A(Seq(x))
  private def apply(s: Seq[Int]): A = new A(s) // make explicit and private instead of auto-generated and public


case class A private(private val s: Seq[Int])

B.scala

package Y

import X.A

class B 
  //val b = A(Seq.empty) // doesn't compile

这里val b = A(Seq.empty) 行产生错误

Error: polymorphic expression cannot be instantiated to expected type;
 found   : [A]Seq[A]
 required: Int

A.apply(Seq[Int]) 方法在 B 中不可见。

【讨论】:

@xan 不,StructType(Seq, Map, Map) 似乎可以访问:scastie.scala-lang.org/xxK1MUclTGOPjGcimFYtlg 编写无法编译的代码。 @xan 如果你只写StructType(Seq(), Map(), Map())类型被推断为StructType.apply(Seq[Nothing], Map[Nothing, Nothing], Map[Nothing, Nothing])并且重载版本中没有这样的apply方法。 @xan 有趣,val b = A(Seq.empty) 产生 found: [A]Seq[A]; required: Intval b = A(Seq()) 产生 found: Seq[Nothing]; required: Int 这很有趣。似乎无效方法的处理方式不同。 scastie.scala-lang.org/NO7j9zgbQ82Z7Zmdabmg4g 它们都被推断为 Dotty 中的Seq[Nothing],不过:scastie.scala-lang.org/S10JSz44QGSNd6cTPJ4ltQ

以上是关于为啥私有构造函数在案例类中仍然可见?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我可以在复制构造函数中访问私有变量?

抽象类中的私有构造函数

Java 私有构造函数可见性

在 PHP5 类中,何时调用私有构造函数?

如果构造函数在私有部分,为啥我们不能创建对象?

内部类中的私有构造函数在外部类中初始化