面试题:Java final关键字作用

前置知识

final 在 Java 中是关键字之一,意为最终,表示对象或数据是最终形态的、不可改变的意思,它可以修饰 类、变量、方法使用 final 修饰的 类、方法、变量具有如下特点

  1. final 修饰的类不能被继承
  2. final 修饰的方法不能被子类重写
  3. final 修饰的成员变量或局部变量(即常量),只能赋值一次,不能重复赋值
    • final 修饰的成员变量须在声明时赋值,如果在声明时未赋值,必须在构造方法中显式赋值才能使用
    • final 修饰的局部变量可以只声明不赋值,但必须在使用前进行赋值

final 关键字深入使用理解

final 变量

  • 如果 final 修饰的是一个基本数据类型的变量,则其数值一旦在初始化之后就不能更改
  • 如果 final 修饰的是一个引用类型的变量,则对其初始化之后就不能再将其指向另一个对象,但该实例对象的实例变量可以修改值
  •  匿名内部类不能访问外部类方法中的局部变量,除非该变量被声明为final类型
public class TestMain {

    public static final int a = 10;

    public static void main(String[] args) {

        final int b = 11;

        //以下两行代码均报错,不能为 final 修饰的常量重复赋值
        //a = 11;
        //b = 12;

        //final 修饰的是一个引用类型的变量,则对其初始化之后就不能再将其指向另一个对象,但该实例对象的实例变量可以修改值
        final String[] str = {"a","b","c"};
        System.out.println(Arrays.toString(str));//输出 [a, b, c]
        str[0] = "d";
        System.out.println(Arrays.toString(str));//输出 [d, b, c]

        final Student student = new Student("001");
        System.out.println(student);//输出 Student(id=001)
        student.setId("002");
        System.out.println(student);//输出 Student(id=002)
        //student = new Student("003");//无法为最终变量 student 重新分配引用地址
    }
    
    /**在内部类的方法使用到方法中定义的局部变量,则该局部变量需要添加 final 修饰符*/
    public void test(){
        //此处在Java8里 final不用写,但其实是 final 的,看字节码文件便知
        final int number = 123;
        InnerClass innerClass = () -> System.out.println(number);
        innerClass.show();
    }

    /**在内部类的方法形参使用到外部传过来的变量,则形参需要添加 final 修饰符*/
    public void test(final String str){
        InnerClass innerClass = () -> System.out.println(str);
        innerClass.show();
    }
}

interface InnerClass {
    void show();
}

@Data
@AllArgsConstructor
class Student{
    private String id;
}
  • final 成员变量必须满足以下其中一个条件(使用前必须要赋值)

    • 在构造函数中赋值

    • 初始化赋值(直接赋值或者初始化块中赋值)

/*常量在声明时初始化*/
public final int num1 = 123;

------------------------------------------------------

/*常量在初始化块中初始化*/
public final int num2;

{
    num2 = 123;
}

------------------------------------------------------

/*常量在构造函数中初始化*/
public final int num3;

public Constructor(int num){
    this.num3 = num;

    /*重复的给常量初始化会报错*/
    //this.num1 = 123;
}

------------------------------------------------------

/*静态常量在声明时初始化*/
public static final int num4 = 123;

------------------------------------------------------

/*静态常量在静态代码块中初始化,不能在初始化块中初始化*/
public static final int num5;

static {
    num5 = 123;
}

final 类

当用 final 修饰一个类时,表明这个类不能被继承。final 类中的所有成员方法都会被隐式地指定为 final 方法。例如 final 在 String、StringBuffer、StringBuilder 中都修饰类,其中在 String 类中的静态内部类中为了防止修改应用而大量使用 final 修饰局部变量

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    
    private final char value[];
    
    public int indexOf(int ch, int fromIndex) {
        final int max = value.length;
        ...........
    }

}

final 方法

使用 final 方法的原因

  1. 防篡改。以防任何继承类修改它的含义

  2. 效率。在早期的 Java 实现版本中,会将 final 方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的 Java 版本已经不需要使用 final 方法进行这些优化了)。类中所有的 private 方法都隐式地指定为 final

public class Parent {
    
    public final void show(){
        System.out.println("parent");
    }
}

public class Children extends Parent{

    //此处重写父类的final方法报错
    /*@Override
    public void show() {
        super.show();
    }*/
}

 

posted @ 2022-07-03 23:00  伊文小哥  阅读(77)  评论(0编辑  收藏  举报