start

A friend in the group asked this question:

In the spirit of helpfulness, MY response was:

Later, I thought something was wrong, so I carefully read the Java Virtual Machine Specification and understanding the Java Virtual Machine. Find problems with your understanding.

Because of their own understanding error and mislead others, is really let me very ashamed!

So I added my friend to apologize to my friend, who was very accommodating and understanding.

Today’s question starts with that story.

Instance variables that final decorates

ConstantValue is a ConstantValue attribute that tells the vm to automatically assign a value to a static variable. Only variables that are modified with the static keyword can use this attribute. But why can private final A = 10 be assigned?”

I looked through the second edition of Understanding the Java Virtual Machine, and on page 191, it did have the preceding sentence

As the book makes clear, the ConstantValue property notifies the virtual machine to automatically assign a value to a static variable.

Does that mean that only static class variables will have a ConstantValue attribute added to the corresponding field table in the class file?

The answer is no. Final instance variables may also be compiled into class files with a ConstantValue attribute in the corresponding field table.

Notice I’m using the word “possibly” here, because it’s conditional. What situations have a ConstantValue attribute?

Let’s write code that lists several instances of instance variables that are modified with final, compile it, and then use javap-verbose to look at the bytecodes generated for us by the Java compiler.

We can see that there are four field tables in the field table set. The sub-tables correspond to the five instance attributes of A, B, C, D, and E. They all have ACC_PUBLIC(public) and ACC_FINAL(final) access flags. However, only the field bands corresponding to A and B have ConstantValue. Let’s summarize:

The final modifier does not assign String or primitive member variables to the constructor, but when compiled into a bytecode file, the corresponding field table will also have a ConstantValue attribute.

Does this conclusion conflict with Understanding the Java Virtual Machine?

So I looked through the JVM Spec Java SE 8Edition (translated by Zhou Zhiming as “Java Virtual Machine Specification”, but I don’t have the translated Chinese version) and found this sentence in section 4.7.2:

The book makes it clear that if a non-static field represented by field_info contains a ConstantValue property, the ConstantValue property will be ignored by the Java virtual machine. That is, if you add a ConstantValue to a non-static field, the JVM ignores it, and the result is the same.

After reading the instructions in the Java Virtual Machine Specification, come back to understanding the Java Virtual Machine:

The ConstantValue attribute is used to tell the VM to automatically assign a value to a static variable. Only class variables decorated with the static keyword can use this attribute.

There is no controversy in the first half of the sentence, but I think the expression in the second half is not very clear, which is easy to cause misunderstanding.

Only class variables decorated with the static keyword can be initialized with this property, otherwise it will be ignored by the JVM.

Ok, let’s go back to the question my friend asked: why can private final A = 10 be assigned?

First of all, the question itself is not very accurate. I understand what my friend really wants to ask is “why private final a = 10 can also be assigned as a ConstantValue property?”

I think this is a very good question. Through experiments, my friend found that the field table corresponding to the instance variable modified with final has ConstantValue attribute. Combined with In-depth Understanding of Java Virtual Machine, he believed that A let the virtual machine know and then assign value to it through the ConstantValue attribute. In the end, he found a conflict with the book and raised the question above.

What’s wrong with that line of thinking? I don’t think there’s a problem.

But is that correct? Obviously not.

Because this is what the virtual machine specification says. For non-static fields, the ConstantValue attribute does not take effect.

As for why to design like this, I am not skilled enough to understand the designer’s idea.

When exactly is an instance variable that is final alone assigned?

This question is also easy to answer, as a look at the bytecode makes clear.

By looking at the bytecode, we can see that there is a method whose bytecode instructions are on the right.

What is method? Let’s take a look at the Java Virtual Machine specification:

Let’s review this phrase: appear as

At the JVM level, every constructor written in Java is represented as an instance initial method, which is a method.

Remember that this method is called when the instance is initialized.

Putfield is an instruction that assigns values to instance variables of a specified class.

It is now clear that these final instance variables are assigned in the instance constructor method when the object is created.

Class variable that is static modified

The ConstantValue property is used to tell the virtual machine to automatically assign a value to a static variable.

Let’s go back to static variables, the key word static.

Before I do that, I need to give you an overview of the process of class loading:

The life cycle of a class consists of seven phases. Class loading refers to the first five phases: load – > validate – > prepare – > parse – > initialize.

Life cycle diagram of a class

Let’s go through the stages briefly:

  • Load: Transforms the static storage structure represented by bytecode into the runtime data structure of the method area.

  • Verification: Verifies the bytecode format to ensure that the information contained in the byte stream of the Class file meets the requirements of the current VM and does not compromise the vm’s own security.

  • Preparation: Create static fields for the class or interface and set initial values for static variables.

  • Parse: Replace symbolic references in the constant pool with direct references.

  • Initialization: Executes the class constructor method.

What is a class constructor method?

JVM Spec Java SE 8Edition says:

In plain English, the compiler collects all the static variable assignments, all the static code blocks, and merges them into a single method, called a method. This method is executed during the initialization phase of the class load.

For class variables (static), there are two options:

  • Assign using the ConstantValue attribute.

  • Assign values in class constructor methods.

The current choice of Javac compilers implemented by Oracle is:

  • Final +static modifier: Assign a value using the ConstantValue attribute.

  • Just use the static modifier: assign a value in a method.

Note that the initialization is done by generating a ConstantValue property, which must be of primitive type or java.lang.String.

This is because the Class file format only has literals that correspond to base attributes and strings, so the ConstantValue attribute cannot support anything else if it wants to.

We can also verify this with the javap-verbose decompilation command:

Final +static modified constants

As mentioned above, methods are assigned during the initialization phase of class loading.

What about static+final modified constants during the class loading phase? We can take a look at the JVM specification:

We can see that in the JVM specification static+final modified constants are executed before the method is executed during initialization.

Yi? A class attribute with a ConstantValue is assigned to a normal class attribute during the preparation phase of class loading.

Understanding the Java Virtual Machine?

Is the book wrong? No, because understanding the Java Virtual Machine is based on HotSpot VM.

That’s exactly what HotSpot VM does, and we can also find the corresponding source code in openJdk:

It does seem that HotSpot VM’s assignment of constants of primitive or string type is done in the preparation phase.

But a key point is that the assignment is still done before the call.

The outside world will not notice that HotSpot VM does this initialization assignment ahead of time, so no problem.

Remember, however, that the specification explicitly states that the correct Initialization time is during the “Initialization” phase.

conclusion

  1. Final modifies instance properties that are assigned at instance creation time.

  2. Static modifies a class property that is assigned initial values during class load preparation and initialization.

  3. Static +final modified String or primitive constants, and literals are assigned during initialization in the JVM specification, whereas HotSpot VM directly assigns values during preparation.

  4. For other reference type constants that are static+final, the assignment steps are the same as in point 2.

Also, it is important not to confuse Understanding the Java Virtual Machine in Depth with the Java Virtual Machine Specification.

  • The Java Virtual Machine Specification is the translated official JVM specification document. All JVM implementations are subject to the specification, but there are mandatory and recommended specifications.
  • Understanding the Java Virtual Machine is a book written by the author based on his own understanding, combined with the concrete implementation of HotSpot VM, to make it easier for readers to understand the JVM.

Write in the last

I am uneducated, OpenJdk source code is not thorough understanding.

Some knowledge points in the article can not find authoritative information online to prove.

However, I try to base my analysis on official documents. If there is any mistake, please point it out! I will be in the first time to modify, not misleading others!

Finally, thank you for reading!

More exciting, wechat public account “CoderW”, waiting for you to progress together!

The test code involved in the article: github.com/xiaoyingzhi…

The JVM Spec Java SE 8 edition:docs.oracle.com/javase/spec…

IDEA to check the bytecode plug-in: plugins.jetbrains.com/plugin/9248…

In-depth Understanding of the Java Virtual Machine: the book is available on all major platforms, and the third edition is recommended.