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){}
}