Java 字节码最终字段赋值(jasmin)
Java bytecode final field assignment (jasmin)
在 java 语言中,final 字段在初始化时采用立即值并且不能再更改。
在 java 字节码 (jasmin) 中,如果我创建一个 final 字段,它会忽略我在初始化时分配给它的立即值,我可以稍后像更改任何其他变量一样更改它。
例如。 java代码:
public class App{
final int CONST = 2;
App(){
CONST = 3;
}
public static void main(String[] args){
App app = new App();
}
}
输出:
App.java:4 error: cannot assign a value to final variable CONST
例如。茉莉花字节码:
.class App
.super java/lang/Object
.field private final CONST I = 2 ;!!! the immediate value is ignored, 0 assigned
.method public <init>()V
.limit stack 3
.limit locals 1
aload_0
invokespecial java/lang/Object/<init>()V
aload_0
bipush 3
putfield App/CONST I ;!!! overwritting final field
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 1
.limit locals 1
new App
invokespecial App/<init>()V
return
.end method
输出:
Generated: App.class
没有错误?我还测试了打印出新的 CONST 值,它就像一个普通变量一样工作。为什么 final 字段不像 java 代码中那样工作?
Java 语言强制执行了很多在字节码级别没有强制执行的约束。其中之一是处理最终字段。
在Java字节码中,对final字段的唯一限制是静态final字段不能在<clinit>
方法之外赋值,非静态final字段不能在<init>
方法之外赋值(即构造函数)。
您可以为最终字段分配 0、1、2 次或任意次数。如果链接构造函数,则可以在一个构造函数中分配给它,然后在另一个构造函数中覆盖它。
要了解有关字节码工作原理的更多信息,您应该阅读 JVM 规范。
附带说明一下,尽管语法看似相似,但以下是完全不同的东西。
final int CONST = 2;
.field private final CONST I = 2 ;!!! the immediate value is ignored, 0 assigned
在第一个示例中,这是一个(非静态)初始化程序。所有初始化器的主体实际上只是复制粘贴到您的每个构造函数中。所以你得到的效果就好像你在构造函数中写了 CONST = 2
一样。
相比之下,Jasmin 语法正在创建一个 ConstantValue
属性。这通常用于为静态最终字段提供初始值。它可以为任何字段指定,但对于非静态字段会被忽略,因此您会看到该值被忽略。
在 java 语言中,final 字段在初始化时采用立即值并且不能再更改。 在 java 字节码 (jasmin) 中,如果我创建一个 final 字段,它会忽略我在初始化时分配给它的立即值,我可以稍后像更改任何其他变量一样更改它。
例如。 java代码:
public class App{
final int CONST = 2;
App(){
CONST = 3;
}
public static void main(String[] args){
App app = new App();
}
}
输出:
App.java:4 error: cannot assign a value to final variable CONST
例如。茉莉花字节码:
.class App
.super java/lang/Object
.field private final CONST I = 2 ;!!! the immediate value is ignored, 0 assigned
.method public <init>()V
.limit stack 3
.limit locals 1
aload_0
invokespecial java/lang/Object/<init>()V
aload_0
bipush 3
putfield App/CONST I ;!!! overwritting final field
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 1
.limit locals 1
new App
invokespecial App/<init>()V
return
.end method
输出:
Generated: App.class
没有错误?我还测试了打印出新的 CONST 值,它就像一个普通变量一样工作。为什么 final 字段不像 java 代码中那样工作?
Java 语言强制执行了很多在字节码级别没有强制执行的约束。其中之一是处理最终字段。
在Java字节码中,对final字段的唯一限制是静态final字段不能在<clinit>
方法之外赋值,非静态final字段不能在<init>
方法之外赋值(即构造函数)。
您可以为最终字段分配 0、1、2 次或任意次数。如果链接构造函数,则可以在一个构造函数中分配给它,然后在另一个构造函数中覆盖它。
要了解有关字节码工作原理的更多信息,您应该阅读 JVM 规范。
附带说明一下,尽管语法看似相似,但以下是完全不同的东西。
final int CONST = 2;
.field private final CONST I = 2 ;!!! the immediate value is ignored, 0 assigned
在第一个示例中,这是一个(非静态)初始化程序。所有初始化器的主体实际上只是复制粘贴到您的每个构造函数中。所以你得到的效果就好像你在构造函数中写了 CONST = 2
一样。
相比之下,Jasmin 语法正在创建一个 ConstantValue
属性。这通常用于为静态最终字段提供初始值。它可以为任何字段指定,但对于非静态字段会被忽略,因此您会看到该值被忽略。