Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Scala—如何在运行时保证val的不变性_Java_Scala_Jvm - Fatal编程技术网

Java Scala—如何在运行时保证val的不变性

Java Scala—如何在运行时保证val的不变性,java,scala,jvm,Java,Scala,Jvm,当我们用java创建final时,它保证即使在运行时也不能更改,因为JVM保证它 Java类: public class JustATest { public final int x = 10; } class AnTest { val x = 1 var y = 2 } Compiled from "AnTest.scala" public class AnTest { public int x(); Code: 0: aload_0

当我们用java创建final时,它保证即使在运行时也不能更改,因为JVM保证它

Java类:

public class JustATest {
    public final int x = 10;
}
class AnTest {

  val x = 1
  var y = 2
}
Compiled from "AnTest.scala"
public class AnTest {
  public int x();
    Code:
       0: aload_0
       1: getfield      #14                 // Field x:I
       4: ireturn

  public int y();
    Code:
       0: aload_0
       1: getfield      #18                 // Field y:I
       4: ireturn

  public void y_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #18                 // Field y:I
       5: return

  public AnTest();
    Code:
       0: aload_0
       1: invokespecial #25                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_1
       6: putfield      #14                 // Field x:I
       9: aload_0
      10: iconst_2
      11: putfield      #18                 // Field y:I
      14: return
}
Javap反编译:

public class JustATest {
    public final int x = 10;
}
class AnTest {

  val x = 1
  var y = 2
}
Compiled from "AnTest.scala"
public class AnTest {
  public int x();
    Code:
       0: aload_0
       1: getfield      #14                 // Field x:I
       4: ireturn

  public int y();
    Code:
       0: aload_0
       1: getfield      #18                 // Field y:I
       4: ireturn

  public void y_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #18                 // Field y:I
       5: return

  public AnTest();
    Code:
       0: aload_0
       1: invokespecial #25                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_1
       6: putfield      #14                 // Field x:I
       9: aload_0
      10: iconst_2
      11: putfield      #18                 // Field y:I
      14: return
}
从“JustATest.java”编译而来

反编译输出:

public class JustATest {
    public final int x = 10;
}
class AnTest {

  val x = 1
  var y = 2
}
Compiled from "AnTest.scala"
public class AnTest {
  public int x();
    Code:
       0: aload_0
       1: getfield      #14                 // Field x:I
       4: ireturn

  public int y();
    Code:
       0: aload_0
       1: getfield      #18                 // Field y:I
       4: ireturn

  public void y_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #18                 // Field y:I
       5: return

  public AnTest();
    Code:
       0: aload_0
       1: invokespecial #25                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_1
       6: putfield      #14                 // Field x:I
       9: aload_0
      10: iconst_2
      11: putfield      #18                 // Field y:I
      14: return
}
从“AnTest.scala”编译而来
公共类赌注{
公共int x();
代码:
0:aload_0
1:getfield#14//字段x:I
4:我轮到你了
公共int y();
代码:
0:aload_0
1:getfield#18//Field y:I
4:我轮到你了
公共无效y_u$eq(int);
代码:
0:aload_0
1:iload_1
2:putfield#18//字段y:I
5:返回
公共赌注();
代码:
0:aload_0
1:invokespecial#25//方法java/lang/Object。“:()V
4:aload_0
5:iconst_1
6:putfield#14//字段x:I
9:aload_0
10:iconst_2
11:putfield#18//Field y:I
14:返回
}

有了这些信息,
val
的不变性概念仅在编译时由scala编译器控制?如何在运行时保证这一点?

在Scala中,通过
val
传递不变性是一种编译时强制,与发出的字节码无关。在Java中,您声明当字段为
final
时,为了不重新分配它,而在Scala中,用
val
声明变量只意味着不能重新分配它,但可以重写它。如果希望字段是
final
,则需要像在Java中那样指定它:

class AnTest {
  final val x = 10
}
这将产生:

public class testing.ReadingFile$AnTest$1 {
  private final int x;

  public final int x();
    Code:
       0: bipush        10
       2: ireturn

  public testing.ReadingFile$AnTest$1();
    Code:
       0: aload_0
       1: invokespecial #19                 // Method java/lang/Object."<init>":()V
       4: return
}
public class testing.ReadingFile$AnTest$1{
私人最终int x;
公共最终整数x();
代码:
0:bipush 10
2:我轮到你了
public testing.ReadingFile$AnTest$1();
代码:
0:aload_0
1:invokespecial#19//方法java/lang/Object。“:()V
4:返回
}
这相当于您在Java中看到的字节码,只是编译器为
x

发出了一个getter。真正简单的答案是:有些Scala特性可以用JVM字节码编码,有些则不能

特别是,有一些约束不能用JVM字节码编码,例如
密封的
private[this]
,或
val
。这意味着,如果您掌握了Scala源文件的已编译JVM字节码,那么您可以通过非Scala语言与代码交互,从而完成Scala无法完成的任务

这并不特定于JVM后端,Scala.js也有类似的、甚至更明显的问题,因为这里的编译目标(ECMAScript)提供的约束表达方式比JVM字节码更少


但事实上,这只是一个普遍的问题:我可以使用像Haskell这样安全、纯净的语言,将其编译为本机代码,如果我掌握了已编译的二进制代码,那么所有的安全性都将丢失。事实上,大多数Haskell编译器执行(几乎)完全的类型擦除,因此实际上没有类型,编译后也没有类型约束。

正如您所说,val不变性仅在编译时得到保证。实际上,您可以使用运行时反射来更改val。运行时值唯一可以更改的方法是在代码中进行反射。你在寻找什么样的“运行时保证”?@YuvalItzchakov:值不变性的概念在java中并不存在,即int可以更改,但在scala中,val保证它不能更改。在这种情况下,这是如何与jvm通信的,因为val的行为不能像finalIt一样,不会反映在jvm字节码中,因为它是在编译时强制执行的。如果您试图更改
val
,您的代码将无法编译。为什么您需要将其逐步转换为字节码呢?在Java中,FYI
final
也是一个编译时约束。您可以更改
最终
字段。