scala - 在 Scala Trait 中使用 Val

标签 scala

我在 Scala 中将特征定义为

trait checkTrait
 {
     val name:String = "male"
 }

据我了解,当在 Scala 类中声明 val 时,仅生成访问器,但是当我使用 JAD 反编译器反编译上面的代码时,会生成以下代码

public interface checkTrait
{

    public abstract void checkTrait$_setter_$name_$eq(String s);
    public abstract String name();
}

无法理解“checkTrait$setter$name_$eq(String s)”到底是什么 是变异者吗?如果是 Mutator 那么它们是如何生成的,因为根据语言规范,不会为 Vals 生成 Mutator

最佳答案

是的,你说得对。 checkTrait$setter$name_$eq(String s) 是一个用于初始化设置 name 值的 Mutator 方法。

这是由于 Scala 特征 将转换为 Java 接口(interface),并且由于 Java interface 字段是 隐式静态和最终,但在Scala中,trait字段需要是classinstance<的字段。因此这个 Mutator 方法 用于初始化 checkTrait 子类的字段。

Java 8 (pre-release) interface member variables

完整说明:

反编译时,Scala Compilertrait checkTrait转换为Java' s 接口(interface)。为此反编译应该在checkTrait中有另一个staticinit方法,例如:

public interface checkTrait {
  public abstract void checkTrait$_setter_$name_$eq(java.lang.String);

  public abstract java.lang.String name();

  public static void $init$(checkTrait);
    Code:

       1: ldc           #18                 // String male
       3: invokeinterface #20,  2           // InterfaceMethod checkTrait$_setter_$name_$eq:(Ljava/lang/String;)V
       8: return
}

如您所见,这是一个接受 checkTrait 实例参数的静态 init 方法。并调用checkTrait$_setter_$name_$eq这个mutator方法来初始设置值,值为:ma​​le

让我们尝试扩展 checkTrait:

class A extends checkTrait

反编译这个A类:

public class A implements checkTrait {
  public java.lang.String name();
    Code:
       0: aload_0
       1: getfield      #15                 // Field name:Ljava/lang/String;
       4: areturn

  public void checkTrait$_setter_$name_$eq(java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #15                 // Field name:Ljava/lang/String;
       5: return

  public A();
    Code:
       0: aload_0
       1: invokespecial #24                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: invokestatic  #28                 // InterfaceMethod checkTrait.$init$:(LcheckTrait;)V
       8: return
}

我们可以发现,在A的构造方法中,它会通过以下方式调用checkTrait static init方法:

5: invokestatic  #28                 // InterfaceMethod checkTrait.$init$:(LcheckTrait;)V

将当前实例传递给初始化name字段值。

这就是在 trait 中实现字段的 Scala 方式。

关于scala - 在 Scala Trait 中使用 Val,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43446423/

相关文章:

scala - Scala将字符串转换为枚举值的安全方法

scala - 在Scala中将null转换为Int和Double

scala - 我如何根据 Scala 中的模式匹配在 map 中找到一个键

scala - 如何初始化一个从右到右并指定左的类型?

scala - 如何从 Async[IO] 创建 Async[Future]

scala - 处理容器停止/重新加载事件

debugging - 每个项目的 SBT 调试端口

file - Scala - 按文件后缀名从文件夹中删除文件

scala - 使用更高种类的类型时类型不匹配

scala - 警告 :Multiple versions of scala libraries detected?