Java中的final關鍵字

1. final修飾符

1.1. final成員變量

final修飾變量時,該變量一旦獲得了初始值之後就不可改變,final既可以修飾成員變量(包括類變量和實例變量),也可以修飾局部變量、形參。

final修改的類屬性、實例屬性能指定初始值的地方如下:

②  類屬性:可在靜態初始化塊中、聲明該屬性時指定初始值

②  實例屬性:可在非靜態初始化塊、聲明該屬性、構造器中指定初始值

package io;

public class FinalVariableDemo {
	// 定義成員變量時指定默認值,合法。
	final int a = 6;
	// 下面變量將在構造器或初始化塊中分配初始值
	final String str;
	final int c;
	final static double d;
	// 既沒有指定默認值,又沒有在初始化塊、構造器中指定初始值,
	// 下面定義char Field是不合法的。
	// final char ch;
	// 初始化塊,可對沒有指定默認值的實例Field指定初始值
	{
		// 在初始化塊中爲實例Field指定初始值,合法
		str = "Hello";
		// 定義a Field時已經指定了默認值,
		// 不能爲a重新賦值下面賦值語句非法
		// a = 9;
	}
	// 靜態初始化塊,可對沒有指定默認值的類Field指定初始值
	static {
		// 在靜態初始化塊中爲類Field指定初始值,合法
		d = 5.6;
	}

	// 構造器,可對既沒有指定默認值、有沒有在初始化塊中
	// 指定初始值的實例Field指定初始值
	public FinalVariableDemo() {
		// 如果初始化塊中對str指定了初始化值,
		// 構造器中不能對final變量重新賦值,下面賦值語句非法
		// str = "java";
		c = 5;
	}

	public void changeFinal() {
		// 普通方法不能爲final修飾的成員變量賦值
		// d = 1.2;
		// 不能在普通方法中爲final成員變量指定初始值
		// ch = 'a';
	}

	public static void main(String[] args) {
		FinalVariableDemo ft = new FinalVariableDemo();
		System.out.println(ft.a);
		System.out.println(ft.c);
		System.out.println(ft.d);
	}
}

1.2. final局部變量

系統不會對局部變量進行初始化,局部變量必須由程序員顯示初始化。因此使用final修飾局部變量時,既可以在定義時指定默認值,也可以不指定默認值。

下面程序示範了final修飾局部變量、形參的情形:

package com;

public class FinalLocalVariableDemo {
	public void test(final int a) {
		// 不能對final修飾的形參賦值,下面語句非法
		// a = 5;
	}

	public static void main(String[] args) {
		// 定義final局部變量時指定默認值,則str變量無法重新賦值
		final String str = "hello";
		// 下面賦值語句非法
		// str = "Java";
		// 定義final局部變量時沒有指定默認值,則d變量可被賦值一次
		final double d;
		// 第一次賦初始值,成功
		d = 5.6;
		// 對final變量重複賦值,下面語句非法
		// d = 3.4;
	}
}
final修飾形參時,因爲形參在調用該方法時,由系統根據傳入的參數來完成初始化,因此使用final修飾的形參不能被賦值。

1.3. final修飾基本類型變量和引用類型變量的區別

當使用final修飾基本類型變量時,不能對基本類型變量重新賦值;對引用類型變量而言,它保存的僅僅是一個引用,final只保證這個引用類型變量所引用的地址不會改變,即一直引用同一個對象,但這個對象完全可以改變。

package com;

import java.util.*;

class Person {
	private int age;

	public Person() {
	}

	// 有參數構造器
	public Person(int age) {
		this.age = age;
	}

	// 省略age Field的setter和getter方法
	// age Field的setter和getter方法
	public void setAge(int age) {
		this.age = age;
	}

	public int getAge() {
		return this.age;
	}
}

public class FinalReferenceTest {
	public static void main(String[] args) {
		// final修飾數組變量,iArr是一個引用變量
		final int[] iArr = { 5, 6, 12, 9 };
		System.out.println(Arrays.toString(iArr));
		// 對數組元素進行排序,合法
		Arrays.sort(iArr);
		System.out.println(Arrays.toString(iArr));
		// 對數組元素賦值,合法
		iArr[2] = -8;
		System.out.println(Arrays.toString(iArr));
		// 下面語句對iArr重新賦值,非法
		// iArr = null;
		// final修飾Person變量,p是一個引用變量
		final Person p = new Person(45);
		// 改變Person對象的age Field,合法
		p.setAge(23);
		System.out.println(p.getAge());
		// 下面語句對p重新賦值,非法
		// p = null;
	}
}
從上述程序可以看出,final修飾的引用類型變量不能被重新賦值,但可以改變引用類型變量所引用對象的內容。

1.4. final方法

final修飾的方法不能被重寫,但可以被重載。

1:如下所示,test()方法由public修飾,故Sub可以繼承父類中的test()方法,但由於test()方法由final修飾,其子類不可對其進行重寫。

public class FinalMethodTest
{
	public final void test(){}
}
class Sub extends FinalMethodTest
{
	//下面方法定義將出現編譯錯誤,不能重寫final方法
	public void test(){}
}
例2:如下所示,test()方法由private修飾,故Sub並未繼承父類中的test()方法,test()方法是父類的私有方法。
public class PrivateFinalMethodTest
{
	private final void test(){}
}
class Sub extends PrivateFinalMethodTest
{
	//下面方法定義將不會出現問題
	public void test(){}
}
例3:
public class FinalOverload
{
	//final修飾的方法只是不能被重寫,完全可以被重載
	private final void test(){}
	private final void test(String arg){}
}

1.5. final類

final修飾的類不可以有子類

發佈了93 篇原創文章 · 獲贊 16 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章