static 關鍵字詳解java
final關鍵字主要用在三個地方:變量、方法、類。函數
static 關鍵字主要有如下四種使用場景:性能
類名.靜態變量名
類名.靜態方法名()
import static
這兩個關鍵字連用能夠指定導入某個類中的指定靜態資源,而且不須要使用類名調用類中靜態成員,能夠直接使用類中靜態成員變量和成員方法。this關鍵字用於引用類的當前實例。 例如:測試
class Manager { Employees[] employees; void manageEmployees() { int totalEmp = this.employees.length; System.out.println("Total employees: " + totalEmp); this.report(); } void report() { } }
在上面的示例中,this關鍵字用於兩個地方:優化
此關鍵字是可選的,這意味着若是上面的示例在不使用此關鍵字的狀況下表現相同。 可是,使用此關鍵字可能會使代碼更易讀或易懂。this
super關鍵字用於從子類訪問父類的變量和方法。 例如:spa
public class Super { protected int number; protected showNumber() { System.out.println("number = " + number); } } public class Sub extends Super { void bar() { super.number = 10; super.showNumber(); } }
在上面的例子中,Sub 類訪問父類成員變量 number 並調用其其父類 Super 的 showNumber()
方法。
使用 this 和 super 要注意的問題:
super()
調用父類中的其餘構造方法時,該語句必須處於構造器的首行,不然編譯器會報錯。另外,this 調用本類中的其餘構造方法時,也要放在首行。簡單解釋一下:
被 static 修飾的成員屬於類,不屬於單個這個類的某個對象,被類中全部對象共享。而 this 表明對本類對象的引用,指向本類對象;而 super 表明對父類對象的引用,指向父類對象;因此, this和super是屬於對象範疇的東西,而靜態方法是屬於類範疇的東西。
被 static 修飾的成員屬於類,不屬於單個這個類的某個對象,被類中全部對象共享,能夠而且建議經過類名調用。被static 聲明的成員變量屬於靜態成員變量,靜態變量 存放在 Java 內存區域的方法區。
方法區與 Java 堆同樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。雖然Java虛擬機規範把方法區描述爲堆的一個邏輯部分,可是它卻有一個別名叫作 Non-Heap(非堆),目的應該是與 Java 堆區分開來。
HotSpot 虛擬機中方法區也常被稱爲 「永久代」,本質上二者並不等價。僅僅是由於 HotSpot 虛擬機設計團隊用永久代來實現方法區而已,這樣 HotSpot 虛擬機的垃圾收集器就能夠像管理 Java 堆同樣管理這部份內存了。可是這並非一個好主意,由於這樣更容易遇到內存溢出問題。
調用格式:
若是變量或者方法被 private 則表明該屬性或者該方法只能在類的內部被訪問而不能在類的外部被訪問。
測試方法:
public class StaticBean { String name; 靜態變量 static int age; public StaticBean(String name) { this.name = name; } 靜態方法 static void SayHello() { System.out.println(Hello i am java); } @Override public String toString() { return StaticBean{ + name=' + name + ''' + age + age + '}'; } }
public class StaticDemo { public static void main(String[] args) { StaticBean staticBean = new StaticBean(1); StaticBean staticBean2 = new StaticBean(2); StaticBean staticBean3 = new StaticBean(3); StaticBean staticBean4 = new StaticBean(4); StaticBean.age = 33; StaticBean{name='1'age33} StaticBean{name='2'age33} StaticBean{name='3'age33} StaticBean{name='4'age33} System.out.println(staticBean+ +staticBean2+ +staticBean3+ +staticBean4); StaticBean.SayHello();Hello i am java } }
靜態代碼塊定義在類中方法外, 靜態代碼塊在非靜態代碼塊以前執行(靜態代碼塊—非靜態代碼塊—構造方法)。 該類無論建立多少對象,靜態代碼塊只執行一次.
靜態代碼塊的格式是
static { 語句體; }
一個類中的靜態代碼塊能夠有多個,位置能夠隨便放,它不在任何的方法體內,JVM加載類時會執行這些靜態的代碼塊,若是靜態代碼塊有多個,JVM將按照它們在類中出現的前後順序依次執行它們,每一個代碼塊只會被執行一次。
靜態代碼塊對於定義在它以後的靜態變量,能夠賦值,可是不能訪問.
靜態內部類與非靜態內部類之間存在一個最大的區別,咱們知道非靜態內部類在編譯完成以後會隱含地保存着一個引用,該引用是指向建立它的外圍類,可是靜態內部類卻沒有。沒有這個引用就意味着:
Example(靜態內部類實現單例模式)
public class Singleton { 聲明爲 private 避免調用默認構造方法建立對象 private Singleton() { } 聲明爲 private 代表靜態內部該類只能在該 Singleton 類中被訪問 private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getUniqueInstance() { return SingletonHolder.INSTANCE; } }
當 Singleton 類加載時,靜態內部類 SingletonHolder 沒有被加載進內存。只有當調用 getUniqueInstance()
方法從而觸發 SingletonHolder.INSTANCE
時 SingletonHolder 纔會被加載,此時初始化 INSTANCE 實例,而且 JVM 能確保 INSTANCE 只被實例化一次。
這種方式不只具備延遲初始化的好處,並且由 JVM 提供了對線程安全的支持。
格式爲:import static
這兩個關鍵字連用能夠指定導入某個類中的指定靜態資源,而且不須要使用類名調用類中靜態成員,能夠直接使用類中靜態成員變量和成員方法
Math. --- 將Math中的全部靜態資源導入,這時候能夠直接使用裏面的靜態方法,而不用經過類名進行調用 若是隻想導入單一某個靜態方法,只須要將換成對應的方法名便可 import static java.lang.Math.; 換成import static java.lang.Math.max;具備同樣的效果 public class Demo { public static void main(String[] args) { int max = max(1,2); System.out.println(max); } }
靜態方法屬於類自己,非靜態方法屬於從該類生成的每一個對象。 若是您的方法執行的操做不依賴於其類的各個變量和方法,請將其設置爲靜態(這將使程序的佔用空間更小)。 不然,它應該是非靜態的。
Example
class Foo { int i; public Foo(int i) { this.i = i; } public static String method1() { return An example string that doesn't depend on i (an instance variable); } public int method2() { return this.i + 1; Depends on i } }
你能夠像這樣調用靜態方法:Foo.method1()
。 若是您嘗試使用這種方法調用 method2 將失敗。 但這樣可行:Foo bar = new Foo(1);bar.method2();
總結:
相同點: 都是在JVM加載類時且在構造方法執行以前執行,在類中均可以定義多個,定義多個時按定義的順序執行,通常在代碼塊中對一些static變量進行賦值。
不一樣點: 靜態代碼塊在非靜態代碼塊以前執行(靜態代碼塊—非靜態代碼塊—構造方法)。靜態代碼塊只在第一次new執行一次,以後再也不執行,而非靜態代碼塊在每new一次就執行一次。 非靜態代碼塊可在普通方法中定義(不過做用不大);而靜態代碼塊不行。
通常狀況下,若是有些代碼好比一些項目最經常使用的變量或對象必須在項目啓動的時候就執行的時候,須要使用靜態代碼塊,這種代碼是主動執行的。若是咱們想要設計不須要建立對象就能夠調用類中的方法,例如:Arrays類,Character類,String類等,就須要使用靜態方法, 二者的區別是 靜態代碼塊是自動執行的而靜態方法是被調用的時候才執行的.
Example
public class Test { public Test() { System.out.print(默認構造方法!--); } 非靜態代碼塊 { System.out.print(非靜態代碼塊!--); } 靜態代碼塊 static { System.out.print(靜態代碼塊!--); } public static void test() { System.out.print(靜態方法中的內容! --); { System.out.print(靜態方法中的代碼塊!--); } } public static void main(String[] args) { Test test = new Test(); Test.test();靜態代碼塊!--靜態方法中的內容! --靜態方法中的代碼塊!-- }
當執行 Test.test();
時輸出:
靜態代碼塊!--靜態方法中的內容! --靜態方法中的代碼塊!--
當執行 Test test = new Test();
時輸出:
靜態代碼塊!--非靜態代碼塊!--默認構造方法!--
非靜態代碼塊與構造函數的區別是: 非靜態代碼塊是給全部對象進行統一初始化,而構造函數是給對應的對象初始化,由於構造函數是能夠多個的,運行哪一個構造函數就會創建什麼樣的對象,但不管創建哪一個對象,都會先執行相同的構造代碼塊。也就是說,構造代碼塊中定義的是不一樣對象共性的初始化內容。