在scala REPL中使用以下代码
import scala.beans.BeanProperty
class EmailAccount {
@scala.beans.BeanProperty var accountName: String = null
override def toString: String = {
return s"acct ($accountName)"
}
}
classOf[EmailAccount].getDeclaredConstructor()
结果
res0: java.lang.reflect.Constructor[EmailAccount] = public EmailAccount()
然而,在火花的REPL中,我得到了
java.lang.NoSuchMethodException: EmailAccount.<init>()
at java.lang.Class.getConstructor0(Class.java:2810)
at java.lang.Class.getDeclaredConstructor(Class.java:2053)
... 48 elided
导致这种差异的原因是什么?如何获得火花以匹配火花壳的行为。
我像这样推出了REPL:
/home/placey/Downloads/spark-2.0.0-bin-hadoop2.7/bin/spark-shell --master local --jars /home/placey/snakeyaml-1.17.jar
和
scala -classpath "/home/placey/snakeyaml-1.17.jar
Scala版本是 火花:
Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_55)
阶:
Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_55).
答案 0 :(得分:3)
实际上,这并不是scala.beans.BeanProperty
甚至Spark所特有的。通过使用-Yrepl-class-based
参数运行它,可以在标准Scala REPL中获得相同的行为:
scala -Yrepl-class-based
现在,让我们尝试定义一个简单的空类:
scala> class Foo()
defined class Foo
scala> classOf[Foo].getConstructors
res0: Array[java.lang.reflect.Constructor[_]] = Array(public Foo($iw))
scala> classOf[Foo].getFields
res1: Array[java.lang.reflect.Field] = Array(public final $iw Foo.$outer)
正如您所看到的,REPL通过向构造函数添加其他字段和参数来动态修改您的类。为什么呢?
每当你在Scala REPL中创建val
或var
时,它都会被包装在一个特殊的对象中,因为它没有&#34;全局变量&#34;在斯卡拉。请参阅this answer。
通常情况下,这是一个对象,因此它可以在全球范围内使用。但是,使用-Yrepl-class-based
,REPL使用类实例而不是单个全局对象。 Spark开发人员介绍了此功能,因为Spark需要类可序列化,因此可以将它们发送给远程工作者(请参阅this pull request)。
因此,您在REPL中定义的任何类都需要获取$iw
实例。否则,您将无法访问在REPL中定义的全局val
和var
。此外,生成的类会自动扩展Serializable
。
我担心你无法阻止这种情况。 spark-shell
默认启用-Yrepl-class-based
。即使有一个禁用此行为的选项,您也会遇到许多其他问题,因为您的类不再可序列化,但Spark需要序列化它们。