我們已經知道,java有靜态成員變量,有非靜态成員變量,有靜态代碼塊,有非靜态代碼塊,有構造方法,有繼承,那麼虛拟機在建立一個類的時候,先做什麼,後做什麼,父類構造方法子類構造方法誰先執行?靜态代碼塊非靜态代碼塊誰先執行?我們寫三個類來測試一下,一個父類,一個子類,一個執行類。
package com.dyz.test;
public class SuperTest{
//靜态成員變量
public static String super_static = "父類靜态變量";
//非靜态成員變量
public String super_dynamic = "父類非靜态變量";
//靜态代碼塊
static{
System.out.println("父類靜态代碼塊");
System.out.println("父類靜态代碼塊中修改前的靜态變量值:"+super_static);
super_static = "父類靜态變量被父類靜态代碼塊修改";
System.out.println("父類靜态代碼塊中修改後的靜态變量值:"+super_static);
}
//非靜态代碼塊
{
System.out.println("父類非靜态代碼塊");
System.out.println(super_dynamic);
super_dynamic = "父類非靜态變量被父類非靜态代碼塊修改";
System.out.println(super_dynamic);
}
//構造方法
public SuperTest(){
System.out.println("父類構造方法");
System.out.println("父類構造方法中的非靜态變量值:"+super_dynamic);
super_dynamic = "父類非靜态變量被父類構造方法修改";
System.out.println("父類構造方法中的非靜态變量值:"+super_dynamic);
System.out.println("父類構造方法中修改前的靜态變量值:"+super_static);
super_static = "父類靜态變量被父類構造方法修改";
System.out.println("父類構造方法中修改後的靜态變量值:"+super_static);
}
}
package com.dyz.test.son;
import com.dyz.test.SuperTest;
public class SonTest extends SuperTest{
public static String child_static = "子類靜态變量";
public String child_dynamic = "子類非靜态變量";
static{
System.out.println("子類靜态代碼塊");
System.out.println("子類靜态代碼塊中修改前的靜态變量值:"+child_static);
child_static = "子類靜态變量被子類靜态代碼塊修改";
System.out.println("子類靜态代碼塊中修改後的靜态變量值:"+child_static);
}
{
System.out.println("子類非靜态代碼塊");
System.out.println(child_dynamic);
child_dynamic = "子類非靜态變量被子類非靜态代碼塊修改";
System.out.println(child_dynamic);
}
public SonTest(){
System.out.println("子類構造方法");
System.out.println("子類構造方法中的非靜态變量值:"+child_dynamic);
child_dynamic = "子類非靜态變量被子類構造方法修改";
System.out.println("子類構造方法中的非靜态變量值:"+child_dynamic);
System.out.println("子類構造方法中靜态變量值:"+child_static);
child_static = "子類靜态變量被子類靜态代碼塊修改";
System.out.println("子類構造方法中靜态變量值:"+child_static);
}
}
package com.dyz.test;
import com.dyz.test.son.*;
public class TestSonAndSuper{
public static String child_static = "靜态變量";
public String child_dynamic = "非靜态變量";
static{
System.out.println("靜态代碼塊");
System.out.println("靜态代碼塊中修改前的靜态變量值:"+child_static);
child_static = "靜态變量被子類靜态代碼塊修改";
System.out.println("靜态代碼塊中修改後的靜态變量值:"+child_static);
}
{
System.out.println("非靜态代碼塊");
System.out.println(child_dynamic);
child_dynamic = "非靜态變量被非靜态代碼塊修改";
System.out.println(child_dynamic);
}
public TestSonAndSuper(){
System.out.println("構造方法");
System.out.println("構造方法中的非靜态變量值:"+child_dynamic);
child_dynamic = "非靜态變量被構造方法修改";
System.out.println("構造方法中的非靜态變量值:"+child_dynamic);
System.out.println("構造方法中靜态變量值:"+child_static);
child_static = "靜态變量被子類靜态代碼塊修改";
System.out.println("構造方法中靜态變量值:"+child_static);
}
public static void main(String[] args)throws InterruptedException{
System.out.println("開始執行main方法******");
int i = 0;
SonTest t = null;
while(i<10){
System.out.println(i);
i++;
Thread.sleep(1000);
}
t = new SonTest();
System.out.println("=============================");
t = new SonTest();
}
}
說下我們的設計思路:
1.靜态變量和非靜态變量定義時候直接初始化,然後在靜态代碼塊和非靜态代碼塊中看是否已經先執行了初始化,如果未初始化,理論輸出應該是null;
2.執行類中也增加靜态變量和靜态代碼塊
3.main方法中增加一個延時器,設定時間10秒,然後建立子類對象。
OK我們來看執行結果
可以看到,執行類的靜态代碼塊被執行了,即使我們沒有執行個體化這個類,但是非靜态塊代碼和構造方法沒有被執行,因為我們沒有建立執行類的對象。
我們從main方法和結果來看:
1.我們在main方法開始就列印了語句,但是靜态塊的語句卻在更之前執行了
2.執行類的靜态塊在輸出的時候,執行類的靜态變量值已經有值了,也就是說靜态變量的指派在靜态塊之前執行。
3.我們聲明了引用變量,但是聲明語句過程中沒有執行任何代碼輸出,此時子類和父類的靜态塊都沒被執行
4.在延時器代碼執行過程中,也沒有任何其他代碼被執行
5.父類的靜态變量最先被指派,然後執行了父類的靜态塊代碼
6.子類的靜态變量被指派了,然後執行了子類的靜态塊代碼
7.父類的非靜态變量被指派了,然後執行了父類的非靜态代碼塊
8.父類的構造方法執行
9.子類的非靜态變量被指派了,然後執行了子類的非靜态代碼塊
10. 子類的構造方法
11. 建立新的子類對象,也不會再執行靜态變量的初始化和靜态代碼塊了
從代碼執行情況,我們現在可以判斷建立一個新對象時各種初始化語句執行的先後順序了:
1. 父類的靜态變量初始化
2. 父類的靜态代碼塊
3. 子類的靜态變量初始化
4. 子類的靜态代碼塊
5. 父類的非靜态變量初始化
6. 父類的非靜态代碼塊
7. 父類構造方法
8. 子類的非靜态變量初始化
9. 子類的非靜态代碼塊
10. 子類的構造方法
另外,我們還知道了:
1. 不管如何,靜态變量初始化、靜态代碼塊隻會執行一次,而且一定是最先執行
2. 聲明一個類型的引用變量,并不會執行這個類型的靜态語句
3. 調用一個類的靜态方法之前,會先執行執行靜态變量指派和靜态代碼塊(從執行類main方法可以看出)
Java中的注釋
一直想說一下注釋的問題,但是總感覺之前的筆記内容都不少,再加上注釋可能太多影響學習。今天這個内容不太多,順便在這裡把注釋說明一下。
注釋是用來解釋代碼、或者進行備注資訊的。比如在日後的開發中,可能會有好幾個人同時完成一個子產品的工作,那麼自己開發的代碼就要加上注釋,說明是代碼的作者是誰,什麼時候寫的,是為了完成什麼功能,大概的設計思路是什麼等等等等。試想一下,如果别人開發了代碼沒加注釋,然後他公休去旅遊了,或者辭職跑路了,你再接觸這個代碼,連想找個人問一下都不知道,是不是很悲催?所謂己所不欲勿施于人,我們自己平時寫代碼就要注意添加合理的注釋。
JAVA的注釋有三種,第一種是行注釋,文法是使用兩個斜杠
//注釋的内容
從兩個斜杠開始,這之後這一整行的内容,編譯器都不會去管了,這個注釋我們在之前的代碼中已經見過,一般用在代碼中,對某一段代碼做簡單說明。
第二種注釋是段落注釋,文法是以斜杠加星号開始,以星号加斜杠結束,文法如下:
這樣的注釋一般用來進行一些較大的修改、擴充等等,需要說明的内容較多時可以采用。不同于上一種注釋,這種注釋是可以跨行的,無論有多少行,隻要是使用了,注釋内容才結束
第三種注釋是文檔注釋,文法是使用斜杠加兩個星号開頭,以星号加斜杠結尾,文法如下:
這種注釋可以生成文檔,一般用于類的開頭、方法的開頭,用來介紹作者、版本、建立時間、用途、參數說明、傳回值介紹等等。
//放在com.dyz.test包中
package com.dyz.test;
/**
* @author dyz
* @date 2018-05-25
* @version 1.0.0
* @description Example類,是一個公共類,不繼承任何父類,
* 不實作任何接口,隻用于舉例描述各種注釋
*/
public class Example{
//雙斜杠注釋可以放在代碼上頭
private String name;//也可以放在代碼後面
//private String age; 如果放在代碼前面,這行代碼就會被注釋掉,不生效
/*
這種注釋可以跨行
*/
public void setName(String name){
this.name = name;
}
/**
* @author dyz
* @version 1.0.0
* @description 示範一下文檔注釋在代碼中的使用
* @param 沒有參數
* @returnType java.lang.String
*/
public String getName(){
/*
System.out.println("被注釋起來的代碼不會被執行");
*/
return this.name;
}
}
另外,關于java代碼的排版,一般是package語句、import語句、聲明類的語句以及類結束的括号}靠最左邊,聲明成員變量、靜态代碼塊、非靜态代碼塊、建構方法、方法向内縮進并保持列平齊。方法、建構方法、靜态代碼塊和非靜态代碼塊中的代碼再進一步縮進并保持列平齊。代碼中如果有for、while、if等語句,語句内的代碼再縮進。
package com.dyz.test;import java.util.Scanner;public class HelloWorld{private String name;public static void main(String[] args){Scanner sc = new Scanner(System.in);System.out.println("Hello World!");sc.close();}}
試看上面這個類,全部擠在一起,空間倒是節省了,但是完全沒有可讀性,相信大家都不會喜歡。總之,我們寫出來的代碼要簡潔美觀、可讀性強、邏輯性強。