Final explanation of Java keywords

Final is an important keyword in Java. This article will summarize it from three perspectives: final modifies data, methods and classes.

Data modified by final in Java

The data modified by final represents that it will never change. It means that once you modify a piece of data with final, you can only look at it later. If you want to modify it, there is no way. The data we don't want to change are as follows:

//编译时知道其值
private final int valueOne = 9;
//在编译时不能知道其值
private final int i4 = rand.nextInt(20);

Final field with initial value

That is, the field declared final and given the initial value on the spot.

 private final int valueOne = 9;

Final + basic data type

The value stored in the basic data type variable modified by final will never change.

/*基本类型变量*/
//带有编译时数值的final基本类型
private final int valueOne = 9;
private static final int VALUE_TWO = 99;
public static final int VALUE_THREE = 39;
//!false:fd1.valueOne++;
//!false:fd1.VALUE_TWO++;
//!false:fd1.VALUE_THREE++;

Kangkang's three eye-catching false statements well confirm what we said before: the value cannot be changed!!! It should be noted that, by convention, the following is a typical way to define constants:

//典型常量的定义方式
public static final int VALUE_THREE = 39;

Final + reference data type

As we said before, basic types store values and reference types store address values. Since the final + basic data type does not allow you to change the value, we can understand that the final + reference data type does not allow you to change the address value of the actual object. (that is, it can no longer point to new objects, which is very specific)

private Value v1 = new Value(1);
private final Value v2 = new Value(22);
private static final Value V_3 = new Value(333);

//引用变量并不是常量,存储地址可以改变
fd1.v1 = new Value(10);

//v2是引用变量,final修饰之后表示地址不能改变,但是实际对象的值是可以改变的
fd1.v2.i++;
//!false:fd1.v2 = new Value(3);

//V_3与v2类似,是静态和非静态的区别,下面会说明
fd1.V_3.i++;
//!false:fd1.V_3 = new Value(10);
}

Through the example, it is also proved that a reference data type variable decorated with final can no longer point to a new object, because the address value it stores can no longer be changed, but it does not affect the actual object it points to. Take a typical reference type as an example. We know that array is a typical reference type. The reference variable of array stores the address in the array heap, and the heap stores the value of each index of the array.

/*引用变量之数组*/
private final int[] a = {1,2,3,4,5,6};

The reference variable a is specified as final, so the address value in it can no longer be changed, and it can no longer point to a new array.

//!false:fd1.a = new int[]{2,6,7};
for (int i = 0; i < fd1.a.length; i++) {
    fd1.a[i]++;

However, each element in the array it points to can be changed because the elements in the array are not qualified.

Final and static final

private final int i4 = rand.nextInt(20);
static final int INT_5 = rand.nextInt(20);
System.out.println(fd1);//fd1: i4 = 15,INT_518

FinalData fd2 = new FinalData("fd2");
System.out.println(fd2);//fd2: i4 = 13,INT_518
FinalData fd3 = new FinalData("fd3");
System.out.println(fd3);//fd3: i4 = 1,INT_5 = 18

Blank final field

That is, a field declared final without an initial value.

private final String id;//空白final

If there is only the above sentence, the compiler will report an error because it is not initialized.

Variable 'id' might not have been initialized

Therefore, if you define a blank final field, be sure to assign a value to it in the constructor! (final must be assigned with an expression at the definition of the domain or in each constructor, because the system will not initialize the final domain by default)

//在构造器中为空白final域赋初值
public FinalData(){
    id = "空白final默认id";
}
public FinalData(String id){
    this.id = id;
}

Do not attempt to access the domain before initialization, otherwise an error will be reported.

Final modified parameters

Parameters of basic data type

Similarly, it is easy to understand that the passed in parameters are not changed but only read.

public int finalParamTest(final int i){
    //!false:i++;
    //不让改,只让读
    return i+1;
}

However, I have added many tests to define four different parameters respectively. If you pass in param0 and Param1 to the method, you will report an error. (I'm very confused. I didn't mention it in this part of the book. I checked a lot of data and didn't understand it clearly. I hope Daniel can comment and point out the maze)

/*检测传入参数*/
int param0 = 5;
final int param1 = 10;
static final int PARAM_2 = 15;
static int param3 = 20;
//!false:System.out.println(fd1.finalParamTest(param0));
//!false:System.out.println(fd1.finalParamTest(param1));
//non-static field'param1' cannot be referenced from a static context
System.out.println(fd1.finalParamTest(PARAM_2));
System.out.println(fd1.finalParamTest(param3));
/*为什么形参列表里的参数用final修饰,但是用final修饰的param1无法传进去,
一定要static修饰?*/

Parameters referencing data types

public void finalReferenceTest(final FinalData fd){
    //!false:fd = new FinalData();
    //不能再指向新的对象,存储地址不准变
    fd.param0++;
}

Similarly, the parameter of this reference type cannot point to a new object, but its actual value pointing to the object can be changed.

Finally, the following code is a super invincible test code that integrates various plates according to the examples in thinking in Java and your own ideas. Rush!

package com.my.pac16;

import java.util.Arrays;
import java.util.Random;

/**
 * @auther Summerday
 */

class Value{
    int i;//package access
    public Value(int i){
        this.i =i;
    }

}
/*final域在使用前必须被初始化:定义时,构造器中*/
public class FinalData {
    /*检测传入参数*/
    int param0 = 5;
    final int param1 = 10;
    static final int PARAM_2 = 15;
    static int param3 = 20;
    private static Random rand = new Random(47);
    private final String id;//空白final
    public FinalData(){
        id = "空白final默认id";
    }
    public FinalData(String id){
        this.id = id;
    }
    //带有编译时数值的final基本类型
    private final int valueOne = 9;
    private static final int VALUE_TWO = 99;
    //典型常量的定义方式
    public static final int VALUE_THREE = 39;
    //在编译是不能知道其值
    private final int i4 = rand.nextInt(20);
    static final int INT_5 = rand.nextInt(20);
    private Value v1 = new Value(1);
    private final Value v2 = new Value(22);
    private static final Value V_3 = new Value(333);

    private final int[] a = {1,6};
    @Override
    public String toString(){
        return id+": "+"i4 = "+i4+",INT_5 = "+INT_5;
    }
    public int finalParamTest(final int i){
        //!false:i++;
        //不让改,只让读
        return i+1;
    }
    public void finalReferenceTest(final FinalData fd){
        //!false:fd = new FinalData();
        //不能再指向新的对象,存储地址不准变
        fd.param0++;

    }

    public static void main(String[] args) {
        FinalData fd1 = new FinalData("fd1");
        /*基本类型变量*/
        //!false:fd1.valueOne++;
        //!false:fd1.VALUE_TWO++;
        //!false:fd1.VALUE_THREE++;
        /*引用变量*/
        fd1.v1 = new Value(10);
        fd1.v2.i++
        //!false:fd1.v2 = new Value(3);
        System.out.println("fd1.v2.i = [" + fd1.v2.i + "]");

        //!false:fd1.V_3 = new Value(10);
        fd1.V_3.i++;
        System.out.println("fd1.V_3.i = [" + fd1.V_3.i + "]");
        /*引用变量之数组*/
        System.out.println("before:fd1.a[] = " + Arrays.toString(fd1.a));

        /*数组引用变量a是final修饰,
        但是不代表它指向的数据值是final,
        而是a存储的地址值不能改变
         */
        //!false:fd1.a = new int[]{2,7};
        for (int i = 0; i < fd1.a.length; i++) {
            fd1.a[i]++;
        }
        System.out.println("after :fd1.a[] = " + Arrays.toString(fd1.a));
        /*final 与static final*/
        //下面示例分别创建了三个不同的对象,对其final 和final static 进行测试
        /*可以发现,三个对象的i4值是随机生成且不能改变的,且不相同,而INT_5的值不随对象改变而改变,因为被static修饰,在类加载时已经被初始化*/
        System.out.println(fd1);//fd1: i4 = 15,INT_518

        FinalData fd2 = new FinalData("fd2");
        System.out.println(fd2);//fd2: i4 = 13,INT_518
        FinalData fd3 = new FinalData("fd3");
        System.out.println(fd3);//fd3: i4 = 1,INT_5 = 18

        //!false:System.out.println(fd1.finalParamTest(param0));
        //!false:System.out.println(fd1.finalParamTest(param1));
        //non-static field'param1' cannot be referenced from a static context
        System.out.println(fd1.finalParamTest(PARAM_2));
        System.out.println(fd1.finalParamTest(param3));
        /*为什么形参列表里的参数用final修饰,但是用final修饰的param1无法传进去,
        一定要static修饰?*/

        System.out.println("fd1.param0 = "+fd1.param0);
        fd1.finalReferenceTest(fd1);
        System.out.println("fd1.param0 = "+fd1.param0);
    }

}

Method of final modification in Java

package com.my.pac16;

/**
 * @auther Summerday
 */
public class FinalMethod {
    public final int age = 10;
    public final void test() {
        System.out.println("test()");
    }

    private final void test2() {
        System.out.println("test2()");
    }
    
}

final class Subclass extends FinalMethod {
    //不能重写:public final void test()
    //可以重载
    public final void test(int a) {
        System.out.println("test()");
    }
    
    //!false:@Override
    public final void test2() {
        System.out.println("is not override test2()");
    }

    public static void main(String[] args) {
        Subclass sb = new Subclass();
        sb.test(2);
        sb.test();
        sb.test2();//并不是重写
        System.out.println(sb.age);//final修饰的域可以被继承
    }
}

Final modified classes in Java

If the article is misunderstood or the description is not in place, you are welcome to correct it in the comment area. Reference book: Thinking in Java

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>