Java 关键字 final 知识点巩固

Java中关键字 final

这个关键字在代码中使用的很多,但其原理跟多人不会关注。

一位面试官朋友闲聊是曾说过,他常问的关于final的一个问题是,“当Java中final修饰HashMap集合时,HashMap集合数据能修改吗?向这个HashMap集合add数据的时候,程序会不会报错。”这个问题,80% 的面试人员会答错。

在此再整理下关于final的用法。

 

1、基本用法

基本用法,final可以修饰类、方法、变量(成员变量+局部变量)

修饰类:

用final修饰类,表明该类不能被继承。final类中成员变量可以根据需要设置为final,但是final类中所有成员方法都会隐式指定为final方法。

 

 

要谨慎使用final修饰类,除非这个类真的在以后不会用来继承。

修饰方法:

用final修饰方法,会把方法锁定,以防止任何继承类修改它的含义。只有在想明确禁止该方法在子类中被覆盖的情况才将方法设置为final。

类的private方法会隐式的指定为final方法。

修饰变量:

用final修饰变量,如果是基本数据类型,数值一旦初始化之后就不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

 

 

2、深入理解

类的final变量和普通变量的区别

当final作用于类的成员变量时,成员变量必须在定义时或者构造器中进行初始化赋值,且final变量一旦被初始化赋值,就不能再被赋值了。

import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author wgy
 * @version 1.0
 * @description
 * @date 2020/8/30 15:54
 */
public class TestFinal {
    private static Logger log = LoggerFactory.getLogger(TestFinal.class);
    public static void main(String[] args) {
        String str_1 = "test_1";
        final String str_2 = "test_";
        String str_3 = "test_";

        /** 这里访问 final str_2 是直接访问它的值 ,相当于 "test_" + 1 */
        String val_1 = str_2 + 1;
        String val_2 = "test_" + 1;

        /** 这里访问str_3是根据连接进行, */
        String val_3 = str_3 + 1;

        log.info("str_1 == val_1 : {}" , (str_1 == val_1));
        log.info("str_1 == val_2 : {}" , (str_1 == val_2));
        log.info("str_1 == val_3 : {}" , (str_1 == val_3));
        log.info("str_1 eq val_3 : {}" , (str_1.equals(val_3)));
    }
}

输出结果:

16:18:19.304 [main] INFO com.ycb.iot.finaltest.TestFinal - str_1 == val_1 : true
16:18:19.310 [main] INFO com.ycb.iot.finaltest.TestFinal - str_1 == val_2 : true
16:18:19.310 [main] INFO com.ycb.iot.finaltest.TestFinal - str_1 == val_3 : false
16:18:19.310 [main] INFO com.ycb.iot.finaltest.TestFinal - str_1 eq val_3 : true

 

当final变量是基本数据类型以及String类型时,如果编译期间能知道它的确切值,则编译器会把它当作编译期常量使用。注意是确切知道final变量值,才会这样。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @author wgy
 * @version 1.0
 * @description
 * @date 2020/8/30 15:54
 */
public class TestFinal {
    private static Logger log = LoggerFactory.getLogger(TestFinal.class);
    public static void main(String[] args) {
        String str_1 = "test_1";
        final String str_2 = getStrVal();
        String str_3 = "test_";

        /** 这里访问 final str_2 是直接访问它的值 ,相当于 "test_" + 1 */
        String val_1 = str_2 + 1;
        String val_2 = "test_" + 1;

        /** 这里访问str_3是根据连接进行, */
        String val_3 = str_3 + 1;

        log.info("str_1 == val_1 : {}" , (str_1 == val_1));
        log.info("str_1 == val_2 : {}" , (str_1 == val_2));
        log.info("str_1 == val_3 : {}" , (str_1 == val_3));
        log.info("str_1 eq val_3 : {}" , (str_1.equals(val_3)));
    }

    public static String getStrVal(){
        return "test_";
    }
}

输出结果:

16:20:35.015 [main] INFO com.ycb.iot.finaltest.TestFinal - str_1 == val_1 : false
16:20:35.019 [main] INFO com.ycb.iot.finaltest.TestFinal - str_1 == val_2 : true
16:20:35.019 [main] INFO com.ycb.iot.finaltest.TestFinal - str_1 == val_3 : false
16:20:35.019 [main] INFO com.ycb.iot.finaltest.TestFinal - str_1 eq val_3 : true

被final修饰的引用变量内容是否可变

引用变量被final修饰后,虽然不能再指向其他对象,但是它指向的对象的内容是可变的。

/**
 * @author wgy
 * @version 1.0
 * @description
 * @date 2020/8/30 15:54
 */
public class TestFinal {
    private static Logger log = LoggerFactory.getLogger(TestFinal.class);
    public static void main(String[] args) {
        final TestFinalVal testFinalVal = new TestFinalVal();
        int value_1 = testFinalVal.value + 10;
        log.info("value_1 : {} ", value_1);
    }
}

class TestFinalVal{
    public int value = 100;
}

 输出结果:

16:26:52.604 [main] INFO com.ycb.iot.finaltest.TestFinal - value_1 : 110 

3、对于开头的问题:

很多人第一反应: HashMap一旦存进去值,就不能变了。结果是错的,存进去之后还能变。

第二反应:HashMap第一次初始化之后,它的各项属性值不能变了,比如Capacity、size等。结果还是错的,这些属性还是可以变化。

当final修饰基本类型和String时,变量值不可变。当修饰其他类型的对象时,final使其引用恒定不变,但是对象自身却可以自由修改变换。

 

原文地址:https://www.cnblogs.com/wgy1/p/13585672.html