Java-Final關鍵字
Final成員變量
final修飾的成員變量必須由程序員顯式的指定初始值
final修飾的類變量:
靜態(tài)初始塊中指定初始值或者聲明該變量時指定初始值
而且只能在兩個地方的其中之一指定
final修飾的實例變量:
非靜態(tài)初始塊,聲明該實例變量或構造函數(shù)中指定初始值
只能在三個中的一個指定
實例變量不能在靜態(tài)初始塊中指定初始值,因為靜態(tài)初始塊是靜態(tài)成員惜辑,不可訪問實例變量---非靜態(tài)成員
類變量不能在普通初始塊中指定初始值,因為類變量在類初始化階段已經(jīng)被初始化了
public class FinalVariableTest {
// 定義成員變量時指定默認值几晤,合法。
final int a = 6;
// 下面變量將在構造器或初始化塊中分配初始值
final String str;
final int c;
final static double d;
// 既沒有指定默認值植阴,又沒有在初始化塊蟹瘾、構造器中指定初始值,
// 下面定義的ch實例變量是不合法的掠手。
// final char ch;
// 初始化塊憾朴,可對沒有指定默認值的實例變量指定初始值
{
//在初始化塊中為實例變量指定初始值,合法
str = "Hello";
// 定義a實例變量時已經(jīng)指定了默認值喷鸽,
// 不能為a重新賦值伊脓,因此下面賦值語句非法
// a = 9;
}
// 靜態(tài)初始化塊,可對沒有指定默認值的類變量指定初始值
static
{
// 在靜態(tài)初始化塊中為類變量指定初始值魁衙,合法
d = 5.6;
}
// 構造器,可對既沒有指定默認值株搔、有沒有在初始化塊中
// 指定初始值的實例變量指定初始值
public FinalVariableTest()
{
// 如果在初始化塊中已經(jīng)對str指定了初始化值剖淀,
// 構造器中不能對final變量重新賦值,下面賦值語句非法
// str = "java";
c = 5;
}
public void changeFinal()
{
// 普通方法不能為final修飾的成員變量賦值
// d = 1.2;
// 不能在普通方法中為final成員變量指定初始值
// ch = 'a';
}
public static void main(String[] args)
{
FinalVariableTest ft = new FinalVariableTest();
System.out.println(ft.a);
System.out.println(ft.c);
System.out.println(ft.d);
}
}
假如打算在構造函數(shù)中纤房,初始塊中對final成員變量進行初始化纵隔,則不應在初始化之前直接訪問final成員變量
但Java又允許通過方法來訪問final成員變量,此時系統(tǒng)就會幫你將final成員變量進行默認初始化
public class FinalErrorTest {
// 定義一個final修飾的實例變量
// 系統(tǒng)不會對final成員變量進行默認初始化
final int age;
{
// age沒有初始化炮姨,所以此處代碼將引起錯誤捌刮。
// System.out.println(age);
printAge();
age = 6;
System.out.println(age);
}
public void printAge(){
System.out.println(age);
}
public static void main(String[] args)
{
new FinalErrorTest();
}
}
final成員變量在顯式初始化之前不能直接訪問,但又可以通過方法來訪問舒岸,這可能是Java設計的一個缺陷
final局部變量
系統(tǒng)不會對局部變量進行初始化绅作,必須程序員自己進行顯式初始化
所以用final修飾局部變量,可以在定義同時指定初始值蛾派,也可以不指定
如果定義時沒有指定初始值俄认,可以在后面進行初始化个少,但只能進行一次
如果定義時已經(jīng)指定初始值,后面就不能再賦值
public class FinalLocalVariableTest {
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修飾基本類型變量,不能對該變量重新賦值
final修飾引用類型變量萎津,final只保證這個變量所引用的地址不變卸伞,即一直引用同一個對象,但是這個對象是可以改變的
class Person
{
private int age;
public Person(){}
// 有參數(shù)的構造器
public Person(int age)
{
this.age = age;
}
// 省略age的setter和getter方法
// age的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修飾數(shù)組變量姜性,iArr是一個引用變量
final int[] iArr = {5, 6, 12, 9};
System.out.println(Arrays.toString(iArr));
// 對數(shù)組元素進行排序瞪慧,合法
Arrays.sort(iArr);
System.out.println(Arrays.toString(iArr));
// 對數(shù)組元素賦值,合法
iArr[2] = -8;
System.out.println(Arrays.toString(iArr));
// 下面語句對iArr重新賦值部念,非法
// iArr = null;
// final修飾Person變量弃酌,p是一個引用變量
final Person p = new Person(45);
// 改變Person對象的age實例變量,合法
p.setAge(23);
System.out.println(p.getAge());
// 下面語句對p重新賦值儡炼,非法
// p = null;
}
}
"宏替換"final變量
當變量滿足三個條件時妓湘,這個final變量就不再是一個變量,而是一個直接量:
final修飾符修飾
在定義時就指定了初始值
該初始值可以在編譯時就被確定
public class FinalLocalTest {
public static void main(String[] args) {
final int a = 5;
System.out.println(a);
}
}
System.out.println(a)語句實際上是直接執(zhí)行 System.out.println(5)
如果被賦值的表達式只是基本的算術表達式或字符串連接操作乌询,沒有訪問普通變量以及調用方法榜贴,Java編譯器同樣將這種final變量當做“宏變量”處理
public class FinalReplaceTest {
public static void main(String[] args)
{
// 下面定義了4個final“宏變量”
final int a = 5 + 2;
final double b = 1.2 / 3;
final String str = "leran" + "Java";
final String book = "Java" + 99.0;
// 下面的book2變量的值因為調用了方法,所以無法在編譯時被確定下來
final String book2 = "Java" + String.valueOf(99.0); //①
System.out.println(book == "Java99.0");
System.out.println(book2 == "Java99.0");
}
}
再看一個例子:
public class StringJoinTest {
public static void main(String[] args)
{
String s1 = "LJava";
// s2變量引用的字符串可以編譯時就確定出來妹田,
// 因此s2直接引用常量池中已有的"LJava"字符串
String s2 = "L" + "Java";
System.out.println(s1 == s2); // 輸出true
// 定義2個字符串直接量
String str1 = "L"; //①
String str2 = "Java"; //②
// 將str1和str2進行連接運算
String s3 = str1 + str2;
System.out.println(s1 == s3); // 輸出false
}
}
final方法
final修飾的方法不可重寫
public class FinalMethodTest
{
public final void test(){}
}
class Sub extends FinalMethodTest
{
// 下面方法定義將出現(xiàn)編譯錯誤唬党,不能重寫final方法
// public void test(){}
}
final類
final修飾的類不可以有子類