1. 程式人生 > 其它 >static 和 final 的區別--面試必問!

static 和 final 的區別--面試必問!

技術標籤:Javajavajvm多執行緒設計模式面試

1.static

1)修飾變數:靜態變數隨著類載入時被完成初始化,記憶體中只有一個,且JVM也只會為它分配一次記憶體,所有類共享靜態變數。
2)修飾方法:在類載入的時候就存在,不依賴任何例項;static方法必須實現,不能用abstract修飾。
3)修飾程式碼塊:在類載入完之後就會執行程式碼塊中的內容。
4)執行順序:父類靜態程式碼塊->子類靜態程式碼塊->父類非靜態程式碼塊->父類構造方法->子類非靜態程式碼塊->子類非靜態方法->子類構造方法。請看如下程式碼:

class A{
    public
A(){ System.out.println("A的構造方法"); } private static A a = new A(); static{ System.out.println("A的static程式碼塊"); } { System.out.println("A的非靜態程式碼塊"); } } public class B extends A{ public B(){ System.out.println
("B的構造方法"); } public static void main(String[] args) { System.out.println("0000"); B b = new B(); System.out.println(); new B(); } }

輸出為:

A的非靜態程式碼塊
A的構造方法
A的static程式碼塊
0000
A的非靜態程式碼塊
A的構造方法
B的構造方法

A的非靜態程式碼塊
A的構造方法
B的構造方法

請讀者朋友自行分析為什麼是這個輸出順序,不懂的可以私信我,我會第一時間回覆。

2. final

1)修飾變數:
編譯期常量:類載入的過程中完成初始化,編譯後帶入到任何計算式中。只能是基本型別。
執行時常量:基本資料型別或引用資料型別。引用不可變,但引用的物件內容可變。如下,可以改變list的內容,但不能改變list引用物件:
在這裡插入圖片描述

3.final的好處:

1.final關鍵字提高了效能。JVM和Java應用都會快取final變數。
2.final變數可以安全的在多執行緒環境下進行共享,而不需要額外的同步開銷。
3.使用final關鍵字,JVM會對方法、變數及類進行優化。

4.static方法是否可以覆蓋?

static方法不能被覆蓋,因為方法覆蓋是基於執行時動態繫結的,而static方法是編譯時靜態繫結的。static方法跟類的任何例項都不相關,所以概念上不適用。

5.是否可以在static環境中訪問非static變數?

static變數在Java中是屬於類的,它在所有的例項中的值是一樣的。
當類被Java虛擬機器載入的時候,會對static變數進行初始化。
如果程式碼嘗試不用例項來訪問非static的變數,編譯器會報錯,因為這些變數還沒有被創建出來,還沒有跟任何例項關聯上。

6.static修飾的變數併發下怎麼保證變數的安全?

這是執行緒安全的問題,不懂的朋友可以去了解一下執行緒安全機制。執行緒安全性比較關鍵的兩個點:記憶體可見性和操作原子性
如果你不修改值,可以使用private static final int ,final可以保證記憶體可見性語義。對於原生變數,final修飾後不可更改,從而也不存在操作原子性的問題。
如果你只是想單純地進行賦值,而不進行復合操作,如i++,i=i+1之類的。那麼可以使用volatile int. volatile可以確保記憶體可見性,但是無法確保原子性,所以不支援複合操作的執行緒安全性。
如果你想進行復合操作,可以使用AtomicInteger這個原子類,支援CAS操作,可確保記憶體可見性和操作原子性。

7.static修飾的變數什麼時候賦值?

編譯器會收集所有靜態變數的賦值動作、所有靜態程式碼塊,合併產生一個方法。這個方法在類載入的初始化階段執行

8.static什麼時候使用?

1).static 靜態變數
靜態變數是固有的,可以直接被引用,其他成員變數僅僅在宣告、生成例項物件後才存在,才可以被引用。所以把靜態變數稱為類變數,非靜態變數稱為例項變數。靜態方法稱為類方法,非靜態方法稱為例項方法。
這裡的static 和c++裡面的 static 相似
當變數是公用的時候可以使用 static 來修飾。
靜態變數可以直接用類名引用。

2).當函式沒有訪問物件特有的資料時可以使用static 來修飾方法。

3).靜態程式碼塊:隨著類載入而執行,只執行一次 。用於給類進行初始化。