Home  >  Article  >  Java  >  In-depth analysis of final implementation principles in Java (with examples)

In-depth analysis of final implementation principles in Java (with examples)

不言
不言forward
2018-11-27 16:56:014664browse

This article brings you an in-depth analysis of the final implementation principle in Java (with examples). It has certain reference value. Friends in need can refer to it. I hope it will be useful to you. Helps.

Final is a reserved keyword in Java that can declare member variables, methods, classes and local variables.

Once you make the reference declaration final, you will not be able to change the reference. The compiler will check the code. If you try to initialize the variable again, the compiler will report a compilation error.

1. Final variables

Final member variables represent constants and can only be assigned once. The value will not change after the assignment (final requires the address The value cannot be changed)

When final modifies a basic data type, it means that the value of the basic data type cannot change once it is initialized; if final modifies a reference type, it will change after it is initialized. It can no longer point to other objects, but the content of the object pointed to by the reference can change. Essentially it's the same thing, because the referenced value is an address, and final requires the value, that is, the value of the address not to change.

Final modifies a member variable (property) and must be initialized explicitly. There are two initialization methods. One is to initialize the variable when it is declared. The second method is to not assign an initial value when declaring the variable, but to assign it to the variable in all constructors of the class where the variable is located. initial value.

2. Final method

There are two reasons for using the final method.

The first reason is to lock the method to prevent any inherited class from modifying its meaning and cannot be overridden;

The second reason is efficiency. Final methods are faster than non-final methods. Fast, because it is statically bound during compilation and does not need to be dynamically bound at runtime.

(Note: The private method of the class will be implicitly designated as the final method)

3. Final class

When a class is modified with final, it indicates that this class cannot be inherited.

Member variables in the final class can be set to final as needed, but be aware that all member methods in the final class will be implicitly designated as final methods.

When using final to modify a class, you should choose carefully. Unless this class really will not be used for inheritance in the future or for security reasons, try not to design the class as a final class.

4. Summary of the use of final

Benefits of the final keyword:

(1) The final keyword improves performance. Both JVM and Java applications cache final variables.

(2) Final variables can be safely shared in a multi-threaded environment without additional synchronization overhead.

(3) Using the final keyword, the JVM will optimize methods, variables and classes.

Important knowledge points about final

1. The final keyword can be used for member variables, local variables, methods and classes.

2. Final member variables must be initialized when declared or initialized in the constructor, otherwise a compilation error will be reported.

3. You cannot assign a value to a final variable again.

4. Local variables must be assigned a value when declared.

5. All variables in anonymous classes must be final variables.

6. The final method cannot be overridden.

7. Final classes cannot be inherited.

8. The final keyword is different from the finally keyword, which is used for exception handling.

9. The final keyword is easily confused with the finalize() method. The latter is a method defined in the Object class and is called by the JVM before garbage collection.

10. All variables declared in the interface are final.

11. The two keywords final and abstract are anti-correlated, and the final class cannot be abstract.

12. The final method is bound during the compilation phase, which is called static binding.

13. Final variables that are not initialized when declared are called blank final variables. They must be initialized in the constructor or initialized by calling this(). If you don't do this, the compiler will report an error "final variable (variable name) needs to be initialized".

14. Declaring classes, methods, and variables as final can improve performance, so that the JVM has the opportunity to estimate and then optimize.

15. According to Java code conventions, final variables are constants, and usually constant names should be capitalized.

16. Declaring a collection object as final means that the reference cannot be changed, but you can add, delete or change content to it.

5. Final principle

It is best to first understand the java memory model Java concurrency (2): Java memory model

For the final domain, the compiler and processor must abide by two Reordering rules:

1. Writing a final field in the constructor and subsequently assigning a reference to the constructed object to a reference variable cannot be reordered between these two operations.

(Write the final variable first, then call the object reference)

Reason: The compiler will insert a StoreStore barrier after writing the final field

2. The first reading of a reference to an object containing a final field and the subsequent first reading of the final field cannot be reordered between the two operations.

(Read the reference of the object first, then read the final variable)

The compiler will insert a LoadLoad barrier in front of the read final field operation

Example 1:

public class FinalExample {
    int i; // 普通变量
    final int j; // final 变量
    static FinalExample obj;
    public void FinalExample() { // 构造函数
        i = 1; // 写普通域
        j = 2; // 写 final 域
    }
    public static void writer() { // 写线程 A 执行
        obj = new FinalExample();
    }
    public static void reader() { // 读线程 B 执行
        FinalExample object = obj; // 读对象引用
        int a = object.i; // 读普通域         a=1或者a=0或者直接报错i没有初始化
        int b = object.j; // 读 final域      b=2
    }
}

The first case: the operation of writing the ordinary field is reordered by the compiler outside the constructor

And the operation of writing the final field is written as final The field reordering rules are "limited" within the constructor, and reader thread B correctly reads the value of the final variable after initialization.

Writing the reordering rules of the final field can ensure that the object's final field has been correctly initialized before the object reference is visible to any thread, while ordinary fields do not have this guarantee.

The second case: the operation of reading the ordinary field of the object is reordered by the processor to read before reading the object reference

And read The reordering rules of the final field will "limit" the operation of reading the object's final field to after reading the object reference. At this time, the final field has been initialized by the A thread, which is a correct read operation.

The reordering rules for reading final fields ensure that before reading the final field of an object, the reference to the object containing the final field must be read first.

Example 2: If the final field is a reference type

For reference types, write the final field The reordering rules add the following constraints to the compiler and processor:

Write the member fields of a final referenced object within the constructor, and subsequently write the reference to the constructed object outside the constructor Assignment to a reference variable cannot be reordered between these two operations.

public class FinalReferenceExample {
    final int[] intArray; // final 是引用类型
    static FinalReferenceExample obj;
    public FinalReferenceExample() { // 构造函数
        intArray = new int[1]; // 1
        intArray[0] = 1; // 2
    }
    public static void writerOne() { // 写线程 A 执行
        obj = new FinalReferenceExample(); // 3
    }
    public static void writerTwo() { // 写线程 B 执行
        obj.intArray[0] = 2; // 4
    }
    public static void reader() { // 读线程 C 执行
        if (obj != null) { // 5
            int temp1 = obj.intArray[0]; // 6  temp1=1或者temp1=2,不可能等于0
        }
    }
}

Assume that first thread A executes the writerOne() method, after execution thread B executes writerTwo() method, and after execution thread C executes reader () method.

In the above figure, 1 is writing to the final field, and 2 is writing to the member field of the object referenced by this final field. , 3 is to assign the reference of the constructed object to a reference variable. In addition to the aforementioned 1 cannot be reordered with 3, 2 and 3 cannot be reordered either.

JMM can ensure that the reading thread C can at least see the writing of the member field of the final reference object by the writing thread A in the constructor. That is, C can at least see that the value of array index 0 is 1. The writing of array elements by writing thread B may or may not be visible to reading thread C. JMM does not guarantee that thread B's writing is visible to reading thread C, because there is data competition between writing thread B and reading thread C, and the execution results at this time are unpredictable.

The above is the detailed content of In-depth analysis of final implementation principles in Java (with examples). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:cnblogs.com. If there is any infringement, please contact admin@php.cn delete