国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java技術——Java中的static關鍵字解析

2019-11-08 00:51:57
字體:
來源:轉載
供稿:網友

0. 前言  

static是java中的重要的一個點。也是面試的時候經常被問到的點,如果理解不夠很容易給面試官語言基礎不扎實的印象。本文從static方法、static內部類、static變量、以及static代碼塊四個角度分別解析static關鍵字。轉載請注明出處為SEU_Calvin的博客。

 

1.  static方法

《Java編程思想》里有這么一句話——“static方法就是沒有this的方法。在static方法內部不能調用非靜態方法,反過來是可以的。而且可以在沒有創建任何對象的前提下,僅僅通過類本身來調用static方法。這實際上正是static方法的主要用途。”

 

static方法一般稱作靜態方法,由于靜態方法不依賴于任何對象、僅通過類名就可以進行訪問,前提是類被加載。也因此在靜態方法中不能訪問類的非靜態成員方法/變量,因為非靜態成員方法/變量都是必須依賴具體的對象才能夠被調用,如果通過類名調用靜態方法,而該方法內部有非靜態變量,此時對象都還沒有創建,就會產生錯誤,因此Java設置了這樣的限制。當然反過來,在非靜態成員方法中是可以訪問靜態成員方法/變量的。

 

我們最常見的static方法就是main方法,另外還有,即使沒有顯示地聲明為static,類的構造器實際上也是靜態方法。

還有就是需要注意,如果你沒必要訪問對象外部,那么就把你的方法成為靜態方法,因為它會比實例方法更快的調用(后者為了實現多態需維護一個虛擬函數導向表)。

 

2.  static內部類

靜態內部類和非靜態內部類是我們在開發中都經常用到的,那么兩者之間到底有什么不同呢?

這里主要總結一下兩者的區別,順便提出在使用static內部類時需要注意的一些性質:

(1)內部靜態類不需要有指向外部類的引用,但非靜態內部類需要持有對外部類的引用。這也是很多非靜態內部類經常默認Android Activity外部類的引用,從而間接導致內存泄漏的原因。

(2)非靜態內部類能夠訪問外部類的靜態和非靜態成員,顯然一個非靜態內部類不能脫離外部類實體被創建,而靜態類不能訪問外部類的非靜態成員,它只能訪問外部類的靜態成員。這一點和上面static方法的性質類似。

 

3.  static變量

同樣介紹靜態變量和非靜態變量的區別:

靜態變量被所有的對象所共享,在內存中只有一個副本,它當且僅當在類初次加載時會被初始化。而非靜態變量是對象所擁有的,在創建對象的時候被初始化,存在多個副本,各個對象擁有的副本互不影響。靜態成員變量雖然獨立于對象,但是不代表不可以通過對象去訪問,所有的靜態方法和靜態變量都可以通過對象訪問。

 

需要注意的是,不論是static方法還是static變量,通過類名直接調用時,也會判斷該方法/變量是否被修飾為PRivate,如果是,仍然是無法獲取到的,這說明static關鍵字無法改變成員的訪問權限。

 

4.  static代碼塊

首先看看下面程序會輸出什么呢?

public class Test {    static{ System.out.println("test static 1");}    public static void main(String[] args) {}    static{ System.out.println("test static 2");}}

雖然在main方法中沒有任何語句,但是還是會輸出"test static 1"、"test static 2",static塊可以置于類中的任何地方,只要不是方法內部,類中也可以有多個static塊。在類初次被加載的時候,會按照static塊的順序來執行每個static塊,并且只會執行一次。

根據只會執行一次的特性,靜態代碼塊可以用以優化程序性能。實例如下:

class Person{    private Date birthDate;    public Person(Date birthDate) {        this.birthDate = birthDate;    }    boolean isBirthdaySuitable() {        Date startDate = Date.valueOf("1990");        Date endDate = Date.valueOf("1999");        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) <= 0;    }}

這個實例用于判斷該Person是否是90后孤寡老人。每次isBirthdaySuitable()被調用的時候,都會生成startDate和endDate兩個對象,造成了空間浪費,使用static靜態塊優化如下:

class Person{    private Date birthDate;private static Date startDate,endDate;//一次性的初始化操作放在static代碼塊中進行    static{        startDate = Date.valueOf("1990");        endDate = Date.valueOf("1999");    }    public Person(Date birthDate) {        this.birthDate = birthDate;    }    boolean isBirthdaySuitable () {        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) <=0;    }}

5.  static代碼塊的執行順序

先看看下面程序會輸出什么?

public class Test {    Person person = new Person("Test");    static{        System.out.println("test static");    }         public Test() {        System.out.println("test constructor");    }         public static void main(String[] args) {        new MyClass();    }} class Person{    static{        System.out.println("person static");    }    public Person(String str) {        System.out.println("person "+str);    }}  class MyClass extends Test {    Person person = new Person("MyClass");    static{        System.out.println("myclass static");    }         public MyClass() {        System.out.println("myclass constructor");    }}

我們來分析一下這段代碼的執行過程:

(1)首先加載Test類,因此會先執行Test類中的static塊。

(2)接著執行main函數中的newMyClass(),而MyClass類還沒有被加載,因此需要加載MyClass類。在加載MyClass類的時候,發現MyClass類繼承自Test類,但是由于Test類已經被加載過了,所以只需要加載MyClass類,那么就會執行MyClass類的中的static塊。

(3)在加載完之后,就通過構造器來生成對象。而在生成對象的時候,必須先初始化父類的成員變量,因此會執行Test中的Personperson = new Person(),而Person類還沒有被加載,因此會先加載Person類并執行Person類中的static塊,接著執行父類的構造器,完成了父類的初始化。

(4)最后初始化MyClass,因此會先接著執行MyClass中的Person person = new Person(),最后執行MyClass的構造器。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 迁安市| 泰州市| 卫辉市| 秦皇岛市| 景泰县| 交口县| 米泉市| 临朐县| 深水埗区| 禄丰县| 台北县| 徐汇区| 岱山县| 尼玛县| 车致| 河南省| 高密市| 漯河市| 嫩江县| 安平县| 两当县| 苍溪县| 奉新县| 固阳县| 潜江市| 玉龙| 屯昌县| 扬中市| 修武县| 无极县| 垦利县| 马关县| 承德县| 固镇县| 巨鹿县| 财经| 大方县| 隆回县| 乌审旗| 固始县| 宁明县|