在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()
但是在Spark的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).
实际上,这不是特定于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中创建aval
或var
Scala REPL时,它都会被包装在一个特殊的对象中,因为在Scala中没有“全局变量”之类的东西。看到这个答案。
通常,这是一个对象,因此全局可用。但是,-Yrepl-class-based
REPL使用类实例而不是单个全局对象。Spark开发人员引入了此功能,因为Spark需要将类可序列化,以便可以将它们发送到远程工作程序(请参阅此pull request)。
因此,您在REPL中定义的任何类都需要获取$iw
实例。否则,您将无法访问在REPL中定义的globalval
和var
。此外,生成的类会自动扩展Serializable
。
恐怕你无能为力。默认情况下spark-shell
启用-Yrepl-class-based
。即使可以禁用此行为,您也会遇到许多其他问题,因为您的类将不再可序列化,但是Spark需要对其进行序列化。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句