📜  Java中的final关键字

📅  最后修改于: 2020-03-29 05:37:01             🧑  作者: Mango

final关键字用于不同的上下文。首先,final是一个不可访问的修饰符适用于变量,方法或类。以下是使用final的情况。

final变量

使用final关键字声明变量时,其值本质上不能修改。这也意味着您必须初始化一个final变量。如果final变量是引用,则意味着该变量无法重新绑定以引用另一个对象,但是可以更改该引用变量所指向的对象的内部状态,即可以在final数组或final集合中添加或删除元素。规范的作法是使用下划线分隔单词,以大写形式表示final变量。
例子 :

// final变量
final int THRESHOLD = 5;
// 空的finalvariable
final int THRESHOLD;
// final static变量PI
static final double PI = 3.141592653589793;
// 空final static变量
static final double PI;

初始化final变量:
我们必须初始化一个final变量,否则编译器将抛出编译时错误。final变量只能通过初始化程序或赋值语句初始化一次。有三种初始化final变量的方法:

  1. 您可以在声明final变量时对其进行初始化。这种方法最为常见。如果在声明时进行初始化,则final变量称为空白final变量。以下是初始化空白final变量的两种方法。
  2. 可以在instance-initializer块内部或构造函数内部初始化空白的final变量。如果您的类中有多个构造函数,则必须在所有这些构造函数中对其进行初始化,否则将引发编译时错误。
  3. 可以在static块内初始化空白的final static变量。

让我们通过示例来看上述初始化final变量的不同方法。

//Java展示初始化不同的静态变量
class Gfg
{
    // final变量,直接初始化
    final int THRESHOLD = 5;
    // 空final变量
    final int CAPACITY;
    // 另一个空final变量
    final int  MINIMUM;
    // final static 变量 PI 
    // 直接初始化
    static final double PI = 3.141592653589793;
    // 空final static变量
    static final double EULERCONSTANT;
    // 对象初始化块
    // 初始化 CAPACITY
    {
        CAPACITY = 25;
    }
    // static初始化块
    // 初始化EULERCONSTANT
    static{
        EULERCONSTANT = 2.3;
    }
    // 构造函数初始化MINIMUM
    // 注意,如果有多个构造函数,您必须在每个当中初始化MINIMUM
    public GFG()
    {
        MINIMUM = -1;
    }
}

何时使用final变量:
普通变量和final变量之间的唯一区别是,我们可以将值重新分配给普通变量。final变量是一旦分配,就无法更改final变量的值。因此,final变量必须仅用于我们希望在程序执行期间保持恒定的值。

参考final变量:
当final变量是对对象的引用时,则此final变量称为引用final变量。例如,final的StringBuffer变量看起来像

final StringBuffer sb;

如您所知,final变量不能重新分配。但是在引用final变量的情况下,可以更改该引用变量指向的对象的内部状态。请注意,这不是重新分配。final的此属性称为非传递性。要了解对象内部状态的含义,请参见以下示例:

// Java展示引用final变量
class Gfg
{
    public static void main(String[] args)
    {
        // 引用final变量sb
        final StringBuilder sb = new StringBuilder("芒果");
        System.out.println(sb);
        // 改变引用final变量sb对象的值
        sb.append("For芒果");
        System.out.println(sb);
    }
}

输出:

芒果
芒果For芒果

非传递属性也适用于数组,因为数组Array是Java对象。具有final关键字的数组也称为final数组
注意 :

  1. 如上所述,final变量无法重新分配,否则将引发编译时错误。
    // Java展示final变量无法重新分配,否则将引发编译时错误
    class Gfg
    {
        static final int CAPACITY = 4;
        public static void main(String args[])
        {
            // final变量无法重新分配
            CAPACITY = 5;
        }
    }

    输出

    Compiler Error: cannot assign a value to final variable CAPACITY
  2. 在方法/构造函数/块内创建final变量时,它称为局部/本地final变量,并且必须在创建它的位置初始化一次。有关局部final变量,请参见以下程序
    // Java展示局部/本地final变量
    class Gfg
    {
        public static void main(String args[])
        {
            // 局部/本地final变量
            final int i;
            i = 20;
            System.out.println(i);
        }
    }

    输出:

    20
  3. 注意C++ const变量和Java final变量之间的区别。声明时,必须为C++中的const变量分配一个值。对于Java中的final变量,没有必要如上面的示例所示。final变量可以在以后分配值,但只能分配一次。
  4. final使用 foreach循环:finally with for-each声明是合法声明。
    // Java使用for-each声明final变量
    class Gfg
    {
        public static void main(String[] args)
        {
            int arr[] = {1, 2, 3};
            // f使用for-each声明final变量
            for (final int i : arr)
                System.out.print(i + " ");
        }
    }

    输出:

    1 2 3

    说明:由于i变量在每次循环迭代时都超出范围,因此实际上它是在每次迭代时重新声明,从而允许使用相同的标记(即i)来表示多个变量。

final类

当使用final关键字声明类时,该类称为final类。final类无法扩展extends(继承),final类有两种用法:

  1. 绝对不能继承,因为不能扩展final类。例如,所有包装器类(例如IntegerFloat等)都是final类。我们无法扩展它们。
    final class A
    {
         // 方法和字段
    }
    // 如下不合法.
    class B extends A
    {
        // 编译错误! 不能有子类A
    }
  2. final with类的另一个用途是创建一个不可变的类,如预定义的String类。如果不将其设置为final,则不能使该类不可变。

 

final方法

当使用final关键字声明方法时,该方法称为final方法。final方法不能被重写对象类做到这一点,以下代码片段通过方法说明了final关键字:

class A
{
    final void m1()
    {
        System.out.println("final方法.");
    }
}
class B extends A
{
    void m1()
    {
        // 编译错误! 无法重写.
        System.out.println("非法!");
    }
}

有关final方法和final类的更多示例和行为,请参阅将final与继承一起使用