【问题标题】:Where is the Object class or java.lang imported into the scala package or Any class?导入 scala 包或 Any 类的 Object 类或 java.lang 在哪里?
【发布时间】:2020-06-03 03:44:24
【问题描述】:

据我了解,Scala 中的终极类是Any 类。但是,我认为 Scala 是由 Java 构建的,所以最终的类不应该是 Object 吗?我一直在检查文档,我可能是错的,但它没有显示 ObjectAny 的父类,我也看不到 java.lang 包被导入到 Scala 的任何地方,这应该是它的主干吧?

【问题讨论】:

  • 终极班是什么意思?它可以被视为终端对象,具体取决于您如何看待类型系统,但仍然......而且 Scala 绝对不是基于 Java 构建的。我不知道你从哪里得到的。它在 JVM 上运行,因此能够与 Java 代码互操作。
  • 我的误会,对此深表歉意,感谢您的回复。

标签: scala superclass scala-java-interop


【解决方案1】:

您将 Scala 编程语言与其一种实现混淆了。

编程语言是一组数学规则和限制。不多。它不是“用任何东西写成的”(可能用英文除外),也不是“建立在任何东西上”(可能写规范的纸除外)。

实现是一种软件,它要么读取用编程语言编写的程序,然后执行该程序,其方式与编程语言的确切内容完全相同。规范说应该发生,发生(在这种情况下,我们将实现称为解释器),或者它读取程序并以另一种语言输出另一个程序,其方式是使用语言的解释器执行那个输出程序,使事情完全按照输入语言规范所述的方式发生。

无论哪种方式,编写实现的人的工作是确保他的实现按照规范所说的去做。

因此,即使我正在编写“基于 Java 构建”并用 Java 编写的 Scala 实现,我仍然需要确保 Any 是顶级类型,因为 that's what the Scala Language Specification says。看看 Scala 语言规范是如何准确表达这个 [bold 强调我的] 可能很有启发性:

AnyRefAnyVal 类必须仅提供在类 Any 中声明的成员,但实现可能会向这些类添加特定于主机的方法(例如,一个实现可以用它自己的对象根类来识别类AnyRef)。

目前有三个积极维护的 Scala 实现,一个废弃了一个。

废弃的 Scala 实现是 Scala.NET,它是一个针对公共语言基础架构的编译器。由于缺乏兴趣和资金,它被放弃了。 (基本上,所有可能会使用 Scala.NET 的用户都已经在使用 F#。)

目前维护的 Scala 实现有:

  • Scala-native:针对 unixoid 操作系统和 Windows 的编译实现。
  • Scala.js:针对 ECMAScript 和 Web 平台的编译实现。
  • Scala(不幸的是一个令人困惑的名称,因为它与语言相同):针对 Java 平台的编译实现。 “Java 平台”是指 Java 虚拟机和 Java 运行时环境,但不是 Java 编程语言。

所有三个实现都是 100% 用 Scala 编写的。实际上,它们不是三个完全独立的实现,它们使用相同的编译器前端,只是后端不同,它们使用 Scala 标准库中用 Scala 编写的相同部分,只是重新实现用其他语言编写的部分。

所以, 是真的,Scala 的 Java 实现确实确实对java.lang.Object 做了一些事情。然而,java.lang.Object不是scala.Any 的超类。事实上,它不可能因为scala.Any是引用类型和值类型的根超类,而java.lang.Object只是所有引用的根超类类型。因此,java.lang.Object 实际上等价于scala.AnyRef 而不是scala.Any。但是,java.lang.Object 也不是scala.AnyRef 的超类,而是相同 类。

另外,java.lang._ 就像scala._ 一样自动导入。但这并不适用于Scala编程语言,它适用于Scala编程语言的Java实现,不幸的是它的名字也是Scala。

因此,对于三个实现之一,java.lang.Object 是根类,但不是scala.Any,而是与scala.AnyRef同一类

但同样,这仅适用于 Scala 的 Java 实现。例如,在 Scala.NET 中,根超类将被标识为 System.Object,而不是 java.lang.Object,它等效于 scala.Any,而不是 scala.AnyRef,因为 CLI 具有像 Scala 这样的统一类型系统,其中引用类型和值类型统一在同一个类型系统中。而且我还没有检查过 Scala.js,但我会假设它会将 Object 识别为 scala.AnyRef

但是请注意,这些都不是,因为实现是“构建”的。这样做的原因是为了尝试合并 Scala 和 Java / CLI / ECMAScript 类层次结构,是为了互操作性,它是为了便于从 Java / 上的所有其他语言调用 Scala 代码。 CLI / ECMAScript 平台,反之亦然,从 Scala 调用用其他语言编写的代码。如果你不关心这些,那么就没有必要跳过这些圈子了。

【讨论】:

  • 我有三个问题:我假设 REPL 也最终将代码编译到 JVM,然后像 Scala-Native 一样将 Java 字节码分解为机器码? Scala-Native 是大多数 Windows 用户会使用的实现吗?在Java中JVM不编译或解释代码依赖,Scala不一样吗?
  • REPL 使用 Scala 编译器工具箱来编译单个 sn-ps 并执行它们。它是否编译到 JVM 取决于您使用的 Scala 实现:Scala-JVM 将编译为 JVM,Scala.js 将编译为 ECMAScript,Scala-native 将编译为本机代码。 JVM 如何执行代码取决于您使用的 JVM 实现。一些 JVM 解释,一些编译,一些首先解释,然后编译最常用的代码部分。 JVM 字节码只是一种语言,一组数学规则和限制。它可以通过多种不同的方式实现。
  • 我认为 Scala-native 在 Windows 上并不流行。我不认为 Scala-native 很受欢迎。它仍在开发中,语言版本落后于 Scala.js 和 Scala-JVM。 (Scala-JVM 实现的 Scala 语言规范当前版本是 2.13,3 已经在进行中。Scala-native 实现的 Scala 语言规范当前版本是 2.11。)
  • "在 Java 中不依赖 JVM 编译或解释代码,是不是同样适用于 Scala?" – Java 只是一种语言,一组数学规则和限制。它可以以许多不同的方式实现。 Java 语言规范中没有任何关于 JVM 的内容。例如,在没有任何 JVM 的情况下将 Java 编译为本机代码是完全合法的,并且确实(或至少确实)存在这样的实现。即使您将 Java 编译到 JVM,Java 虚拟机规范中仍然没有任何关于编译或……的说明。
  • … 解释。任何实现者都可以随意实现 JVM。有解释的 JVM,有提前静态编译的 JVM,有即时动态编译的 JVM,有解释、收集统计数据,然后只编译统计上得到的代码部分的 JVM执行频率最高。
【解决方案2】:

java.lang.Object 不是scala.Any 的父级。考虑以下关系

implicitly[Any <:< java.lang.Object]     // error
implicitly[AnyVal <:< java.lang.Object]  // error
implicitly[AnyRef <:< java.lang.Object]  // ok

但是,假设您有以下 Java 类

public class Foo {
    public void bar(Object o) {}
    public void zar(int o) {}
    public void qux(java.lang.Integer o) {}
}

那么当从 Scala 调用时,以下所有内容仍然可以工作

val foo = new Foo
foo.bar(42.asInstanceOf[Int])
foo.bar(42.asInstanceOf[Any])
foo.bar(42.asInstanceOf[AnyVal])
foo.bar(42.asInstanceOf[AnyRef])
foo.zar(42) // zar takes primitive int
foo.qux(42) // qux takes java.lang.Integer

【讨论】:

    猜你喜欢
    • 2015-05-10
    • 2012-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-27
    • 2020-09-29
    • 2014-10-09
    相关资源
    最近更新 更多