寫Java代碼的時候很少去關注成員變量的聲明和初始化順序,今天借此機會拋出一些問題:語言的設計者們為什麼會這樣設計?比如說很常見的一個問題:abstract(抽象)類不能用final進行修飾。這個問題比較好理解:因為一個類一旦被修飾成了final,那麼意味著這個類是不能被繼承的,而abstract(抽象)類又不能被實例化。如果一個抽象類可以是final類型的,那麼這個類又不能被繼承也不能被實例化,就沒有存在的意義。從語言的角度來講一個類既然是抽象類,那麼它就是為了繼承,所以給它標識為final是沒有意義的。語言的設計者們當然不可能讓這麼大的一個bug產生。對於開發者而言抽象類不能修飾final可能就是一種約定俗成的規定,並沒有特殊意義。我們完全可以往前想一點:為什麼這麼設計?
下面我所展示的一些代碼實例也同樣會采用我上面的一些思考方法。有一些是一些”契約“,並沒有特別的緣由,可能用別的方法也是合理的。下面的代碼會講到初始化的一些策略,從實際的執行結果中得出一些結論。
代碼一
public class Test1 {
{
a = 1;
//System.out.println(a);//這裡會拋錯。
}
private int a=2;//這裡初始化一次,上面的動態塊中也對a進行了賦值,這個時候a=?,為什麼可以對a進行賦值,而不可以對a進行輸出
public static void main(String[] args){
Test1 test1 = new Test1();
System.out.println(test1.a);
}
}
看看上面的代碼一,第一個問題就是這段代碼能否編譯通過。結果是能編譯通過。這裡說明一個問題就是變量的聲明和賦值是兩步操作?(這句話我先保留一半,在上面
的代碼中有一行代碼我注釋掉了,這裡會拋錯,對於這個問題我也沒有想明白為什麼。)
第一個問題解決了。那下一個問題很顯然最後輸出的結果是什麼?答案是“2”,這裡可能會有些詫異。從直觀上來講就是說明在賦值的過程中是完全按照代碼的前後順序進
行。
public class Test2 {
{
a = 4;
}
private final int a;//這裡我並沒有對a做初始化。
public static void main(String[] args){
Test2 test2 = new Test2();
System.out.println(test2.a);
}
}
“代碼二”只是在“代碼一”的基礎上對成員變量a多修飾了一個final,另外我並沒有立即初始化。第一個問題就是這段代碼能不能編譯通過,答案是能。在這裡展示這段代碼是為了後面做鋪墊,因為這段代碼仍然符合上面的“契約”。
public class Test3 {
{
a = 4;
}
private static int a;
public static void main(String[] args){
Test3 test3 = new Test3();//注意:這裡開始new了一個對象
System.out.println(test3.a);
}
}
代碼三在代碼一的的基礎上對於成員變量a多修飾了一個static。這裡同樣可以編譯通過,最後輸出的結果也皆大歡喜為4。這裡要注意的是我是new了一個對象,而不是直接訪問靜態變量。
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2013-10/92159p2.htm