scala 中的非最终单例对象有什么意义?

2024-02-24

我一直以为objectScala 中的声明将被编译为final类,因为它们是由有效的匿名类实现的。自从final与非最终类相比,类更容易被 JVM 优化,我认为最终性有好处并且没有成本,所以所有object实施将是最终的。

但我一定错过了一些东西。默认情况下,object实现类是非最终的。必须明确声明final object得到一个final实现类:

Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_31).
Type in expressions to have them evaluated.
Type :help for more information.

scala> object Nonfinal;
defined object Nonfinal

scala> final object Final;
defined object Final

scala> :javap Nonfinal
  Size 518 bytes
  MD5 checksum f27390a538ccc6e45764beaeb888478c
  Compiled from "<console>"
public class Nonfinal$
  minor version: 0
  major version: 50
  flags: ACC_PUBLIC, ACC_SUPER
// snip!

scala> :javap Final
  Size 509 bytes
  MD5 checksum 2db90a8bab027857524debbe5cf8ef29
  Compiled from "<console>"
public final class Final$
  minor version: 0
  major version: 50
  flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER

非最终的目的是什么object?为什么一个人会not想要标记一个object final?

Update请注意,一个类似的问题 https://stackoverflow.com/questions/26079591/whats-the-point-of-declaring-an-object-as-final已被询问并得到答复(感谢特拉维斯·布朗!)一个答案是权威的,但必须是过时的,SLS版本2.9 http://www.scala-lang.org/docu/files/ScalaReference.pdf声称“final 对于对象定义来说是多余的”,但显然这不是真的,从 Scala 2.11 开始final明显影响为对象生成的字节码。

另一个(已接受!)答案指出存在一个很少使用的功能,用户可以通过该功能覆盖子类或特征中的对象。我认为这是正确的,所以我在这里的问题确实是重复的,但我花了几分钟才说服自己这一点。乍一看,重写对象看起来就像重写 val,在这种情况下,没有理由不能在字节码中将每个实现标记为 Final。但经过更多的思考和一些搜索,如果我有的话,这一定是真的

trait Base { 
  object Poop { 
    def stink = "Yuk!"
  }

  def poopSmell = this.Poop.stink
}

trait Derived extends Base {
  override object Poop {
    def stink = "Roses"
  }
}

那么Derived的Poop必须继承Base的Poop的类型,所以Derived.Poop的实现一定是Base的Poop的实现的子类,所以Base的poop在字节码中不能被标记为final。

所以我认为这是重复的,尽管我花了几分钟才解决问题。

但请注意,此功能似乎实际上效果不佳。要编译上述代码,必须运行scala -Yoverride-objects(或者大概scalac -Yoverride-objects在非 REPL 上下文中)。然后上面的代码确实在 REPL 中编译,但尝试实例化 Derived 的细化或具体扩展失败。

scala> :paste
// Entering paste mode (ctrl-D to finish)

trait Base { 
  object Poop { 
    def stink = "Yuk!"
  }

  def poopSmell = this.Poop.stink
}

trait Derived extends Base {
  override object Poop {
    def stink = "Roses"
  }
}

// Exiting paste mode, now interpreting.

defined trait Base
defined trait Derived

scala> (new Derived{}).poopSmell
java.lang.ClassFormatError: Duplicate method name&signature in class file $anon$1
  at java.lang.ClassLoader.defineClass1(Native Method)
  ...

scala> class Concrete extends Derived;
defined class Concrete

scala> new Concrete
java.lang.ClassFormatError: Duplicate method name&signature in class file Concrete
  at java.lang.ClassLoader.defineClass1(Native Method)

不管这个功能有多么糟糕,它的存在确实解释了为什么有时(我认为在实践中很少)可能希望有一个非最终版本object,所以之前接受的答案是正确的,这是重复的。

我要养成标记我的习惯object不过,几乎总是决赛。

Update 2请注意,重要的是,将对象标记为 Final 不会影响对象的延迟初始化语义:

scala> object PrintNonFinal{ println("PrintNonFinal") }
defined object PrintNonFinal

scala> final object PrintFinal{ println("PrintFinal") }
defined object PrintFinal

scala> identity( PrintNonFinal )
PrintNonFinal
res3: PrintNonFinal.type = PrintNonFinal$@2038ae61

scala> identity( PrintFinal )
PrintFinal
res4: PrintFinal.type = PrintFinal$@3dd4520b

Update 3请注意,根据下面的 som-snytt,对象重写只能应用于依赖于实例的类型,即object嵌套(直接或间接)在类或特征中。顶级对象不能被覆盖,因此,在没有任何干预类或特征的情况下,嵌套在顶级对象中的“静态可访问”对象也不能被覆盖。

As 索姆-斯尼特在下面的答案中演示了,顶级对象实际上被编译成最终类。

不幸的是,很容易表明嵌套在顶级对象中的静态可访问对象默认情况下会编译为非最终类,因此最好保持将除顶级对象之外的所有对象都声明为最终的习惯,甚至是嵌入在顶级对象中的对象。级别对象,除非它们嵌套在类或特征中并且您实际上打算启用对象覆盖。请参阅下面的(编辑过的)REPL 会话,演示了顶级对象的最终性(再次感谢索姆-斯尼特!) 以及嵌套在对象声明中的不可重写对象声明的非最终性,除非嵌套声明被显式声明为最终的。

Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_31).

scala> :paste -raw
// Entering paste mode (ctrl-D to finish)

package Foo {
  object Outer {
     object Inner {
     }
  }
}

// Exiting paste mode, now interpreting.

scala> :javap -sysinfo Foo.Outer$
  Size 343 bytes
  MD5 checksum 5502ef3151c41ab5c20ada0f0d386288
  Compiled from "<pastie>"
public final class Foo.Outer$ {
  public static final Foo.Outer$ MODULE$;
  public static {};
}

scala> :javap -sysinfo Foo.Outer$Inner$
  Size 410 bytes
  MD5 checksum fa4749f47d8f6b432841a4f9947831b1
  Compiled from "<pastie>"
public class Foo.Outer$Inner$ {
  public static final Foo.Outer$Inner$ MODULE$;
  public static {};
  public Foo.Outer$Inner$();
}

scala> :paste -raw
// Entering paste mode (ctrl-D to finish)

package bar {
  object Outer {
    final object Inner {
    }
  }
}

// Exiting paste mode, now interpreting.

scala> :javap -sysinfo bar.Outer$
  Size 343 bytes
  MD5 checksum 138a1e48b7ea4c2d6097c552c9cac440
  Compiled from "<pastie>"
public final class bar.Outer$ {
  public static final bar.Outer$ MODULE$;
  public static {};
}

scala> :javap -sysinfo bar.Outer$Inner$
  Size 410 bytes
  MD5 checksum 96c11a97df2d9630369f8f1c97db7089
  Compiled from "<pastie>"
public final class bar.Outer$Inner$ {
  public static final bar.Outer$Inner$ MODULE$;
  public static {};
  public bar.Outer$Inner$();
}

这就是你的最终答案吗?

由于 REPL 定义已包装,您需要paste -raw编译粘贴后的内容。

看起来顶级 Foo 和 Bar 是最终类:

scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

package foo { object Foo { object Fooz } }
package bar { final object Bar { object Baz} }

// Exiting paste mode, now interpreting.


scala> :javap -sysinfo foo.Foo$
  Size 339 bytes
  MD5 checksum 628ac559ca72294bd342a7813ced5d4c
  Compiled from "<pastie>"
public final class foo.Foo$ {
  public static final foo.Foo$ MODULE$;
  public static {};
}

scala> :javap -sysinfo bar.Bar$
  Size 339 bytes
  MD5 checksum 23a123e9827f1a0a6b033253e0613545
  Compiled from "<pastie>"
public final class bar.Bar$ {
  public static final bar.Bar$ MODULE$;
  public static {};
}

scala> :javap -sysinfo foo.Foo$Fooz$
  Size 401 bytes
  MD5 checksum a081412707f1fbf42f6fa68f2c7f46e9
  Compiled from "<pastie>"
public class foo.Foo$Fooz$ {
  public static final foo.Foo$Fooz$ MODULE$;
  public static {};
  public foo.Foo$Fooz$();
}

此外,假设的成员对象的重写是转移注意力或幻想。即使对象实际上只是惰性值,关系获得什么类型也并不明显。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

scala 中的非最终单例对象有什么意义? 的相关文章

  • 为什么不重新评估 Binding.scala 路由器?

    我正在尝试通过 Binding scala 为个人项目构建通用路由器 我定义了一个PageState trait sealed trait WhistState def text String def hash String def ren
  • 如何从命令行运行scala文件?

    scala是否支持scala run xxx scala go语言支持这样运行 go my go 并且Python支持 python my py 但看来 scala xxx scala 仅进行语法检查 未观察到任何输出或运行行为 那么有没有
  • 压缩 HList 的函数的推断类型

    谢谢https github com milessabin shapeless wiki Feature overview shapeless 2 0 0 https github com milessabin shapeless wiki
  • 实现一个scala集合,以便map、filter等产生正确的类型

    我正在尝试实施一个默认值映射 https stackoverflow com questions 3187411 designing a convenient default valued map in scala 我想要过滤器 地图等De
  • 运行 JAR 时“JCE 无法验证提供者 BC”

    在我的 scala 项目中我使用 org bouncycastle bcprov jdk14 1 51 用于密码学 如果它在 Scala IDE 中测试我的项目 它工作得很好 但是一旦我制作了一个 JAR 并尝试通过以下方式运行它java
  • 从继承的受保护 Java 字段创建公共访问器

    我怎样才能完成以下工作 class Foo extends javax swing undo UndoManager increase visibility works for method override def editToBeUnd
  • 在 Scala 中调用反射案例类构造函数

    我可以通过静态反射获取案例类的默认构造函数 val symbol currentMirror classSymbol myObj getClass typeSignature typeSymbol asClass val ctor symb
  • 用于真实 Web 项目的 Scala-JS [已关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 有人用过吗Scala JS在真实的网络项目中 但不仅仅适用于普通的JavaScript在隔离环境中替换 我想尽可能多地使用 Scala 我希望可
  • 如何在 Scala 中编写 Pig UDF

    我正在尝试在 Scala 中编写 Pig UDF 使用 Eclipse 我已将 pig jar 添加为 java 构建路径中的库 这似乎解决了以下 2 个导入问题 导入 org apache pig EvalFunc 导入 org apac
  • 如何设计具有相互依赖的测试的 Specs2 数据库测试?

    有没有一些首选的方法来设计Specs2 http etorreborre github com specs2 测试 有很多测试取决于之前测试的结果 下面 您将找到我当前的测试套件 我不喜欢var位于测试片段之间 不过 它们是 需要的 因为某
  • 用惯用的 Scala 更新大型数据结构

    我已经尝试 Scala 一段时间了 并且经常遇到支持不可变数据结构的建议 但是当你有一个像这样的数据结构时3D 场景图 大型神经网络或任何具有大量需要频繁更新的对象的东西 对场景中的对象进行动画处理 训练神经网络 这似乎是 运行时效率极低
  • Scala 中抛出异常,什么是“官方规则”

    我正在 Coursera 上学习 Scala 课程 我也开始阅读 Odersky 的 Scala 书 我经常听到的是 在函数式语言中抛出异常不是一个好主意 因为它破坏了控制流 并且我们通常返回一个失败或成功的 Either Scala 2
  • 以编程方式启动 Scala REPL?

    我想从命令行启动 Scala Swing 应用程序 然后在应用程序启动后 放入 Scala REPL 中以用作控制界面 理想情况下 我还想预先绑定一些变量名称 更好的是使用 REPL 的 Java2D 终端模拟器 但我找不到任何合适的东西
  • 通用 scala 函数,其输入是变量数量的函数

    我想定义一个函数f需要另一个函数g 我们需要g采取采取n双打 对于某些固定n 并返回一个 Double 函数调用f g 应该返回具体值n 例如 f Math max 2因为 Math sin 具有类型 Double Double gt Do
  • 如何在 Apache Spark 中通过 DStream 使用特征提取

    我有通过 DStream 从 Kafka 到达的数据 我想进行特征提取以获得一些关键词 我不想等待所有数据的到达 因为它是可能永远不会结束的连续流 所以我希望以块的形式执行提取 如果准确性会受到一点影响 对我来说并不重要 到目前为止 我整理
  • Scala 2.9 无法在 Windows XP 上运行“hello world”示例

    我正在尝试在 Windows XP 上使用 scala 2 9 1 Final 运行 HelloWorld 示例 object HelloWorld extends App println Hello World 文件另存为Hello sc
  • HashPartitioner 是如何工作的?

    我阅读了文档HashPartitioner http spark apache org docs 1 3 1 api java index html org apache spark HashPartitioner html 不幸的是 除了
  • 从 HList 获取元素

    我尝试了 HList 并按预期进行了以下工作 val hl 1 foo HNil val i Int hl 0 val s String hl 1 但是 我无法让以下代码正常工作 让我们暂时假设对列表进行随机访问是一个聪明的主意 class
  • 在 Spark MLlib 上使用 Java 中的 Breeze

    在尝试从Java使用MLlib时 使用微风矩阵运算的正确方法是什么 例如scala 中的乘法很简单 matrix vector 相应的功能在Java中是如何表达的 有一些方法 例如 colon times 可以通过正确的方式调用 breez
  • 规范化且不可变的数据模型

    Haskell如何解决 规范化不可变数据结构 问题 例如 让我们考虑一个表示前女友 男友的数据结构 data Man Man name String exes Woman data Woman Woman name String exes

随机推荐

  • 当对象更新时,更新对该对象的所有引用(对引用的引用)

    我想在java中声明一个对象 就像C 中指向指针的指针一样 让我给你看一个例子 At the application startup Initialize a settings container class Settings settin
  • 加速 Python

    这确实是两个问题 但它们非常相似 为了简单起见 我想我应该把它们放在一起 Firstly 给定一个已建立的 python 项目 除了简单的代码内优化之外 还有哪些不错的方法可以加速它 Secondly 用python从头开始编写程序时 有哪
  • 将服务从一项活动传递到另一项活动

    如何将服务从一项活动传递到另一项活动 我有一个音乐播放器 Activity1 它显示歌曲列表 当您单击它时 它会启动 Activity1 中的服务 我有一个按钮 用户可以单击该按钮来打开 Activity2 那么我将服务从 Activity
  • 是否可以将 stickylistviewheader 与 crisbanes pulltorefresh 合并?

    我构建了一个应用程序 其中需要 pulltorefresh 和 StickylistHeaders 我已经在应用程序中实现了 pulltorefresh 但无法使其与 StickyListHeaders 一起使用 是否可以合并这两个库 或者
  • 如何避免在回发时从 asp.net 重复输入?

    我有一个从模板表中提取数据的下拉列表 我有一个添加按钮来插入新模板 添加按钮将弹出 jQuery 弹出窗口以插入新值 将有一个保存按钮来保存新数据 On Save Click 我输入新数据并关闭弹出窗口 问题是这样的 当我刷新页面时 页面再
  • 将 C++ lambda 转换为 C 函数

    我正在编写一些包装代码 其中外部库调用 C 函数 使用可变参数模板等 关键点是外部库需要一个 c 函数 这通常没问题 因为这是合法的 LibraryFuncType fn params 虽然我可以轻松地手动完成此操作 但我想使用以下方法自动
  • 使用 DeviceWatcher 监视 USB 驱动器并检索设备信息?

    I m a WinForms开发人员和我已经知道如何使用 WMI 监视连接或断开连接的 USB 但不久前我发现了设备观察者 http msdn microsoft com en us library windows devices enum
  • 将字符串转换为八进制数的最Pythonic方法

    我希望使用存储在配置文件中的文件掩码来更改文件的权限 由于 os chmod 需要八进制数 因此我需要将字符串转换为八进制数 例如 000 gt 0000 or 0o000 for you python 3 folks 644 gt 064
  • Docker 组成和主机名

    我有一个包含 2 个名为 web 和 db 的服务 容器 的撰写文件 version 2 services web image nodejs latest ports 80 db image mysql latest ports 3306
  • is_null($var) 和 ($var === null) 有什么区别?

    这之间有什么区别吗 if is null var do something 和这个 if var null do something 检查变量是否包含 null 时哪种形式更好 有什么我应该注意的边缘情况吗 我初始化了所有变量 因此不存在的
  • 将模块导入 Pyscript

    当我们编写 Python 代码时 我们通常使用导入的包和模块 例如 我们在编码时可能会这样写 import numpy import requests from bs4 import BeautifulSoup 当我们尝试将 python
  • 在 git 中,如何仅从更改的行中删除 Windows 行结尾?

    有时 当我尝试向开源项目贡献代码时 该项目尚未格式化并且包含 UNIX 和 Window 行结尾 我的 智能 IDE 会以某种方式检测每个文件使用哪种类型的结尾 如果它检测到 Windows 行结尾 那么我的所有更改都将具有 Windows
  • 更改 Sysem.Variants.VarToWideStr 的区域设置格式

    我的应用程序上的第三方组件 FastReports 广泛使用 System Variants VarToWideStr 函数 这很好 只是它忽略了我需要该应用程序使用的区域设置 Example FormatSettings ShortDat
  • Spark 跨接收器的结构化流一致性

    我想在以下情况下更好地理解 Spark 2 2 结构化流的一致性模型 一个来源 Kinesis 从此源向 2 个不同接收器进行 2 次查询 一个用于存档目的的文件接收器 S3 另一个用于处理数据的接收器 数据库或文件 尚未决定 我想了解跨接
  • 覆盖 django 的模型相关管理器

    我如何才能超越关系经理 例如 user entry set django db models fields related RelatedManager 但我需要自己的经理 我尝试这段代码 但这不起作用 class EntryManager
  • 为什么 QObject ::findChildren 返回具有公共基类的子级?

    我使用 QObject 作为复合模式的基类 假设我有一个父类 File 在一个人为的示例中 我向其中添加不同类型的子类 HeaderSection 和 PageSection File HeaderSection 和 PageSection
  • 简单表达式缺少参数类型

    遵循播放 websocket 示例 http www playframework com documentation 2 3 x ScalaWebSockets我遇到了一个奇怪的问题 文档中的以下示例正在运行 Future successf
  • 弹出并刷新视图控制器

    我有三个视图控制器 当我到达第三个视图控制器时 我使用 poptorootviewcontroller 弹出到我的第一个视图控制器 但是当我在第三个视图控制器中使用 popviewcontroller 我想返回到我的第二个视图控制器 时 它
  • 为什么 PowerShell 无法识别带引号的参数?

    当您直接调用脚本 在 PowerShell 控制台或 ISE 中 或通过另一个 PowerShell 实例调用脚本时 为什么 PowerShell 对带引号的参数的处理方式有所不同 这是脚本 TestQuotes ps1 param str
  • scala 中的非最终单例对象有什么意义?

    我一直以为objectScala 中的声明将被编译为final类 因为它们是由有效的匿名类实现的 自从final与非最终类相比 类更容易被 JVM 优化 我认为最终性有好处并且没有成本 所以所有object实施将是最终的 但我一定错过了一些