Java final keyword explanation

In java, the meaning of final is slightly different in different scenarios, but in general, it refers to "this is immutable". Next, let's talk about the four main uses of final.

final data

When writing a program, we often need to show that a data is immutable, which we call constant. In java, variables decorated with the final keyword can only be assigned once, and cannot be assigned again in the lifetime. More importantly, final will tell the compiler that the data will not be modified, so the compiler may replace or even perform calculations on the data during compilation, which can optimize our program a little. However, when it comes to basic types and reference types, there are subtle differences in the effect of the final keyword. Let's look at the following example:

package s1;

public class L {
	public static void main(String[] args) {
		final int i1 = 1;  	//Define variables and assign constants directly. This is a compile time constant
		i1 = 11;			//Compilation error because final data can only be assigned once
		final int i2; 		//Define variables, but do not assign them first; assign them where you need them later, which is not a compile time constant
		i2 = 2;		
		i2 = 12;			//Compilation error because final data can only be assigned once
		//Although i3 is final and assigned, it is not a constant, so i3 is not a compile time constant
		final int i3 = (int) (Math.random() * 10);
		i3 = 13;			//Compilation error because final data can only be assigned once
		//The above part is an example of basic types. Let's take a look at related objects
		final Value value1 = new Value();
		value1 = new Value();	//Compilation error because final data can only be assigned once
		//The following is OK, because value1 has not changed (it has not been assigned again), only the value in the value1 object has changed
		value1.value = 1;		
		value1.value = 1;
	}
}

class Value {
	int value;
}

Blank final

java allows "blank final", which refers to the domain declared as final without initial value. In any case, the compiler ensures that blank final must be initialized before it can be used. However, blank final provides more flexibility in the use of the keyword final. For this reason, the final domain in a class can be different according to different objects, but keep its constant characteristics. Here is a list:

package s1;

public class L {
	public static void main(String[] args) {
		Value value1 = new Value(10);
		value1.maxValue = 20;	//Compilation error because final data can only be assigned once
		Value value2 = new Value(20);
	}
}

class Value {
	final int maxValue;
	Value(int value) {
		this.maxValue = value;
	}
}

final method

The main reason for using the final method is to lock the method to prevent the successor from modifying its meaning. This is for design reasons: you want to make sure that method behavior remains the same in inheritance and is not overridden. Example:

package s1;

public class L {
	public static void main(String[] args) {
		
	}
}

class L1 {
	final void calculate() {
		System.out.println(getClass().getSimpleName() + "calculate");
	}
}

class L2 extends L1 {
	void calculate() {    //Compilation error, cannot overwrite the calculate method in L1 because it is final
		
	}
}

final and private keywords

All private methods in the class are implicitly specified as final methods. Because a subclass cannot call the private method that accesses the parent class, it cannot be overridden and polymorphism cannot be implemented (for polymorphism, please refer to https://blog.csdn.net/GracefulGuigui/article/details/103869327 ) You can add a final modifier to the private method, but that doesn't add any extra meaning to the method. Example:

package s1;

public class L {
	public static void main(String[] args) {
		L1 l1 = new L2();
		l1.test();
	}
}

class L1 {
	void test() {
		calculate1();
		calculate2();
	}
	private final void calculate1() {
		System.out.println("L1 calculate1");
	}
	void calculate2() {
		System.out.println("L1 calculate2");
	}
}

class L2 extends L1 {
        // No error will be reported. Although the calculate1 method in L1 is final, private restricts L2's access to calculate1 of L1, so it can start the method with the same name + the same parameter list
	void calculate1() {
		System.out.println("L2 calculate1");
	}
	void calculate2() {
		System.out.println("L2 calculate2");
	}
}

Operation result:

L1 calculate1    //Polymorphism is not supported because it is a private method
L2 calculate2    // Because of polymorphism, the actual call is calculate2 of L2

Class final

The final class is relatively simple and easy to understand. The class modified by final indicates that it cannot be inherited by other classes.

Published 64 original articles, won praise 4, visited 10000+
Private letter follow

Tags: Java

Posted on Sat, 11 Jan 2020 01:03:51 -0500 by Undead_Zeus