02-Java常用關鍵字理解(基礎)

注:源碼系列文章主要是對某付費專欄的總結記錄吭敢。如有侵權剪廉,請聯(lián)系刪除质帅。

1 static

1.1 靜態(tài)變量

  • 靜態(tài)變量:又稱為類變量烈疚,也就是說這個變量屬于類黔牵,類所有的實例都共享靜態(tài)變量,可以直接通過類名來訪問它爷肝。靜態(tài)變量在內存中只存在一份猾浦;
  • 實例變量:每創(chuàng)建一個實例就會產生一個實例變量,它與該實例共生共死灯抛。
public class StaticExample {
    // 靜態(tài)變量
    public static int ID = 1;
    // 實例變量
    private String name;

    public StaticExample() {
        this.name = "李雷";
    }

    // TEST
    public static void main(String[] args) {
        // 靜態(tài)變量直接通過類名訪問
        System.out.println(StaticExample.ID);

        // 實例變量
        StaticExample example = new StaticExample();
        System.out.println(example.name);
    }
}

1.2 靜態(tài)方法

靜態(tài)方法在類加載的時候就存在了金赦,它不依賴于任何實例,所有靜態(tài)方法必須有實現(xiàn)对嚼,也就是說它不能是抽象方法夹抗。

靜態(tài)方法只能調用同樣被 static 修飾的方法或屬性,不能調用普通方法纵竖,我們常用的 util 類里面的各種方法漠烧,我們比較喜歡用 static 修飾方法,好處就是調用特別方便靡砌。

static 方法內部的變量在執(zhí)行時是沒有線程安全問題的已脓。方法執(zhí)行時,數(shù)據運行在棧里面乏奥,棧的數(shù)據每個線程都是隔離開的摆舟,所以不會有線程安全的問題,所以 util 類的各個 static 方法邓了,我們是可以放心使用的恨诱。

public static void print(String... args) {
    for (String arg : args) {
        System.out.print(arg + " ");
    }
}

1.3 靜態(tài)代碼塊

靜態(tài)代碼塊在類初始化時只運行一次。

public class A {

    static {
        System.out.println("static code block");
    }

    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new A();
    }
}

執(zhí)行結果:

static code block

1.4 靜態(tài)內部類

略骗炉。

1.5 靜態(tài)導包

在使用靜態(tài)變量和方法時照宝,不用在指明 ClassName,從而簡化代碼句葵,但可讀性大大降低厕鹃。

import com.alibaba.fastjson.JSON;
import com.google.common.base.Splitter;

import java.util.List;

public class A {

    public static void main(String[] args) {
        // 不用指明 ClassName
        System.out.println(StaticExample.ID);

        // 非靜態(tài)需要導包, 也就是指明 ClassName
        Splitter splitter = Splitter.on(",");
        List<String> list = splitter.trimResults().omitEmptyStrings().splitToList("a,b,c,d");
        System.out.println(JSON.toJSONString(list));
    }
}

1.6 執(zhí)行順序

靜態(tài)變量和靜態(tài)代碼塊優(yōu)先于實例變量和普通代碼塊執(zhí)行,靜態(tài)變量和靜態(tài)代碼塊的初始化順序取決于它們在代碼中的順序乍丈。如下:

靜態(tài)變量/靜態(tài)代碼塊 -> 實例變量/普通代碼塊 -> 構造函數(shù)

存在繼承情況下剂碴,初始化順序為:

  1. 父類(靜態(tài)變量、靜態(tài)代碼塊)
  2. 子類(靜態(tài)變量轻专、靜態(tài)代碼塊)
  3. 父類(實例變量忆矛、普通代碼塊)
  4. 父類(構造函數(shù))
  5. 子類(實例變量、普通代碼塊)
  6. 子類(構造函數(shù))

static 修飾的方法请垛,在類初始化的時候并不會初始化催训,只有當自己被調用時洽议,才會被執(zhí)行。

2 final

2.1 數(shù)據

聲明數(shù)據為 final漫拭,可以是編譯時常量亚兄,也可以是在運行時被初始化后不能被改變的常量。

  • 對于基本類型采驻,final 使數(shù)值不變审胚;
  • 對于引用類型,final 使引用不變挑宠,也就不能引用其它對象菲盾,但是被引用的對象本身是可以修改的颓影。
public class FinalExample {

    int a;

    public static void main(String[] args) {
        // 基本類型
        final int b = 100;
        // 改變基本類型
        // b = 200; // Cannot assign a value to final variable 'b'

        // 引用類型
        final FinalExample example = new FinalExample();
        System.out.println(example.a);
        example.a = 1;
        System.out.println(example.a);
    }
}

一般用于以下三種場景:

  1. 被 final 修飾的類各淀,表明該類是無法繼承的;
  2. 被 final 修飾的方法诡挂,表明該方法是無法覆蓋的碎浇;
  3. 被 final 修飾的變量,說明該變量在聲明的時候璃俗,就必須初始化完成奴璃,而且以后也不能修改其內存地址。

第 3 點需要注意城豁,我們說的是無法修改其內存地址苟穆,并沒有說無法修改其值。因為對于 List唱星、Map雳旅、自定義Object 這些類來說,被 final 修飾后间聊,是可以修改其內部值的攒盈,但卻無法修改其初始化時的內存地址。如:String 被 final 修飾哎榴;String 存儲數(shù)據的 char 數(shù)組被 final 修飾型豁;上面的 FinalExample 等。

3 try尚蝌、catch迎变、finally

這三個關鍵字常用于捕獲異常的一整套流程,try 用來確定代碼范圍飘言,catch 捕獲可能發(fā)生的異常衣形,finally 用來執(zhí)行一定要執(zhí)行的代碼塊(如 IO流的關閉)。除了這些地方我們還需要清楚的知道热凹,每個地方如果發(fā)生異常會怎么辦泵喘。如:

public static void main(String[] args) {
    try {
        log.info("try run.");

        if(true) {
            throw new RuntimeException("try exception");
        }
    } catch (Exception e) {
        log.info("catch run: " + e.getMessage());

        if(true) {
            throw new RuntimeException("catch exception");
        }
    } finally {
        log.info("finally run.");
    }
}

總結:

  1. finally 先執(zhí)行后泪电,再拋出 catch 的異常;
  2. 最終捕獲的異常是 catch 的異常纪铺,try 拋出來的異常已經被 catch 吃掉了相速,所以當我們遇見 catch 也有可能拋出異常時,可以先打印出 try 的異常信息鲜锚,這樣 try 的異常在日志中就會有所體現(xiàn)突诬。

4 volatile

volatile 的意思是可見的,常用來修飾某個共享變量芜繁,意思是當共享變量的值被改變后旺隙,會及時通知到其它線程上,其它線程就能知道當前共享變量的值已經被修改了骏令。

在多核 CPU 下蔬捷,為了提高效率,線程在拿值時榔袋,是直接和 CPU 緩存交互的周拐,而不是內存。主要是因為 CPU 緩存執(zhí)行速度更快凰兑,比如線程要拿值 C妥粟,會直接從 CPU 緩存中拿,CPU 緩存中沒有吏够,才會從內存中拿勾给,所以線程讀的操作永遠都是拿 CPU 緩存的值。

這個時候會產生一個問題锅知,CPU 緩存中的值和內存中的值可能并不是時刻都同步播急,導致線程計算的值可能不是最新的,共享變量的值有可能已經被其它線程所修改了喉镰,但此時修改的是機器內存的值旅择,CPU 緩存的值還是老的,導致計算會出現(xiàn)問題侣姆。

這時候有個機制生真,就是內存會主動通知 CPU 緩存。當前共享變量的值已經失效了捺宗,你需要重新來拉取一份柱蟀,CPU 緩存就會重新從內存中拿取一份最新的值。

volatile 關鍵字就會觸發(fā)這種機制蚜厉,加了 volatile 關鍵字的變量长已,就會被識別成共享變量,內存中的值一旦被修改后,就會通知各個 CPU 緩存术瓮,使 CPU 緩存中的值也對應被修改康聂,從而保證線程從 CPU 緩存中拿去出來的值是最新的。

-

從圖中看到胞四,線程 1 和線程 2 一開始都讀取了 C 值恬汁,CPU 1 和 CPU 2 緩存中也都有了 C 值,然后線程 1 把 C 值修改了辜伟,這時候內存中 C 值和 CPU 2 緩存中的 C 值就不等了氓侧,內存這是發(fā)現(xiàn) C 值被 volatile 關鍵字修飾,發(fā)現(xiàn)其實共享變量导狡,就會使 CPU 2 緩存中的 C 值狀態(tài)置為無效约巷,CPU 2 會從內存中重新拉取一份最新的 C 值到緩存,旱捧。這時候線程 2 再來讀取緩存中的 C 值独郎,讀取的已經是內存中最新的值了。

5 transient

transient 關鍵字用來修飾類變量廊佩,意思是當前變量是無需進行序列化的囚聚。在序列化時,會忽略該變量标锄。如:ArrayList 對內部存儲數(shù)據 elementData 使用 transient 修飾 transient Object[] elementData,因為 elementData 數(shù)組并不會存儲滿茁计,所以無需全部序列化料皇,這里重寫了 writeObjectreadObject

6 default

default 關鍵字一般會用在接口的方法上星压,意思是對于該方法践剂,子類是無需強制實現(xiàn)的,但自己必須有默認的實現(xiàn)娜膘,如:

public interface DefaultExample {

    default void print() {
        System.out.println("default method");
    }
}

7 面試題

7.1 如何證明 static 靜態(tài)變量和類實例無關逊脯?

答:從三個方面就可以看出靜態(tài)變量和類無關。

  1. 我們不需要初始化類就可以直接使用靜態(tài)變量竣贪;
  2. 我們在類中執(zhí)行 main 方法军洼,即使不寫初始化類的代碼,靜態(tài)變量也會自動初始化演怎;
  3. 靜態(tài)變量只會初始化一次匕争,初始化完成之后,不管我們再 new 多少個類出來爷耀,靜態(tài)變量都不會再初始化了甘桑。

不僅僅是靜態(tài)變量,靜態(tài)方法塊也和類無關。

7.2 常撑芎迹看見變量和方法被 static 和 final 兩個關鍵字同時修飾铆帽,為什么這么做?

答:這么做有兩個目的:

  1. 變量和方法于類無關德谅,可以直接使用锄贼,使用比較方便;
  2. 強調變量內存地址不可變女阀,方法不可以被繼承覆寫宅荤,強調了方法內部的穩(wěn)定性。

7.3 catch 中發(fā)生了未知異常浸策,finally 還會執(zhí)行么冯键?

答:會的。catch 發(fā)生了異常庸汗,finally 還會執(zhí)行的惫确,并且 finally 執(zhí)行完之后,才會拋出 catch 中的異常蚯舱。

捕獲 catch 會吃掉 try 中拋出的異常改化,為了避免這種情況,在一些可以預見的 catch 中會發(fā)生異常的地方枉昏,先把 try 拋出的異常打印出來陈肛,這樣從日志中就可以看到完成的異常信息了。

7.4 vilatile 關鍵字的作用和原理

答:參考上文兄裂。

------------------------------------- END -------------------------------------

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末句旱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子晰奖,更是在濱河造成了極大的恐慌谈撒,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匾南,死亡現(xiàn)場離奇詭異啃匿,居然都是意外死亡,警方通過查閱死者的電腦和手機蛆楞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門溯乒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人臊岸,你說我怎么就攤上這事橙数。” “怎么了帅戒?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵灯帮,是天一觀的道長崖技。 經常有香客問我,道長钟哥,這世上最難降的妖魔是什么迎献? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮腻贰,結果婚禮上吁恍,老公的妹妹穿的比我還像新娘。我一直安慰自己播演,他們只是感情好冀瓦,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著写烤,像睡著了一般翼闽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洲炊,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天感局,我揣著相機與錄音,去河邊找鬼暂衡。 笑死询微,一個胖子當著我的面吹牛,可吹牛的內容都是我干的狂巢。 我是一名探鬼主播撑毛,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼隧膘!你這毒婦竟也來了代态?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤疹吃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后西雀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萨驶,經...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年艇肴,在試婚紗的時候發(fā)現(xiàn)自己被綠了腔呜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡再悼,死狀恐怖核畴,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情冲九,我是刑警寧澤谤草,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布跟束,位于F島的核電站,受9級特大地震影響丑孩,放射性物質發(fā)生泄漏冀宴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一温学、第九天 我趴在偏房一處隱蔽的房頂上張望略贮。 院中可真熱鬧,春花似錦仗岖、人聲如沸逃延。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽揽祥。三九已至,卻和暖如春紧帕,著一層夾襖步出監(jiān)牢的瞬間盔然,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工是嗜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留愈案,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓鹅搪,卻偏偏與公主長得像站绪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子丽柿,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內容

  • 九種基本數(shù)據類型的大小恢准,以及他們的封裝類。(1)九種基本數(shù)據類型和封裝類 (2)自動裝箱和自動拆箱 什么是自動裝箱...
    關瑋琳linSir閱讀 1,887評論 0 47
  • Java內存區(qū)域 Java虛擬機在運行程序時會把其自動管理的內存劃分為以上幾個區(qū)域甫题,每個區(qū)域都有的用途以及創(chuàng)建銷毀...
    架構師springboot閱讀 1,772評論 0 5
  • 一:java概述:1馁筐,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境坠非,java的開發(fā)工...
    ZaneInTheSun閱讀 2,650評論 0 11
  • 第二部分 自動內存管理機制 第二章 java內存異常與內存溢出異常 運行數(shù)據區(qū)域 程序計數(shù)器:當前線程所執(zhí)行的字節(jié)...
    小明oh閱讀 1,164評論 0 2
  • 2009年月28日敏沉,正在阿根廷參加南美洲國家聯(lián)盟特別首腦會議的哥倫比亞現(xiàn)任總統(tǒng)烏里韋出現(xiàn)了流感癥狀,他隨即回到首都...
    遠哥漫畫閱讀 417評論 1 0