java的static關鍵字

 

一、在類中,用static聲明的成員變量爲靜態成員變量,他爲該類的公用變量,在第一次使用時被初始化,對於該類的全部對象來講static成員變量只有一份函數

二、用static聲明的方法爲靜態方法,在調用該方法時,不會將對象的引用傳遞給他,因此在static方法中不可訪問非static的成員佈局

  靜態方法不在是針對某個對象調用,因此不能訪問非靜態成員性能

三、能夠經過對象引用或類名(不須要實例化)訪問靜態成員學習

static 方法:優化

  static 修飾的方法稱爲靜態方法,能夠不用建立對象便可使用,對於靜態方法來講沒有this的,由於它不依附於任何對象,既然沒有對象就談不上this,而且這個因爲特性,在靜態方法中不能訪問類的非靜態成員變量和非靜態方法,由於非靜態成員方法/變量都是必須依賴於具體的對象才能夠被調用,注意:在靜態方法中不能訪問非靜態成員方法和非靜態成員變量,可是在非靜態成員方法中能夠訪問靜態成員方法/變量的this

下面例子:spa

在上面的代碼中,因爲print2方法是獨立於對象存在的,能夠直接用過類名調用。假如說能夠在靜態方法中訪問非靜態方法/變量的話,那麼若是在main方法中有下面一條語句:code

  MyObject.print2();對象

  此時對象都沒有,str2根本就不存在,因此就會產生矛盾了。一樣對於方法也是同樣,因爲你沒法預知在print1方法中是否訪問了非靜態成員變量,因此也禁止在靜態成員方法中訪問非靜態成員方法。blog

  而對於非靜態成員方法,它訪問靜態成員方法/變量顯然是毫無限制的。

  所以,若是說想在不建立對象的狀況下調用某個方法,就能夠將這個方法設置爲static。咱們最多見的static方法就是main方法,至於爲何main方法必須是static的,如今就很清楚了。由於程序在執行main方法的時候沒有建立任何對象,所以只有經過類名來訪問。

static變量:

  static變量也稱做靜態變量,靜態變量和非靜態變量的區別是:靜態變量被全部的對象所共享,在內存中只有一個副本,它當且僅當在類初次加載時會被初始化。而非靜態變量是對象所擁有的,在建立對象的時候被初始化,存在多個副本,各個對象擁有的副本互不影響。

  static成員變量的初始化順序按照定義的順序進行初始化。

static代碼塊:

  static關鍵字還有一個比較關鍵的做用就是 用來造成靜態代碼塊以優化程序性能。static塊能夠置於類中的任何地方,類中能夠有多個static塊。在類初次被加載的時候,會按照static塊的順序來執行每一個static塊,而且只會執行一次。

  爲何說static塊能夠用來優化程序性能,是由於它的特性:只會在類加載的時候執行一次。下面看個例子:

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

isBornBoomer是用來這我的是不是1946-1964年出生的,而每次isBornBoomer被調用的時候,都會生成startDate和birthDate兩個對象,形成了空間浪費,若是改爲這樣效率會更好:

class Person{
    private Date birthDate;
    private static Date startDate,endDate;
    static{
        startDate = Date.valueOf("1946");
        endDate = Date.valueOf("1964");
    }
     
    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }
     
    boolean isBornBoomer() {
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

static關鍵字的誤區:

1.static關鍵字不會改變類中成員的訪問權限

  Java中的static關鍵字不會影響到變量或者方法的做用域。在Java中可以影響到訪問權限的只有private、public、protected(包括包訪問權限)這幾個關鍵字。看下面的例子就明白了:

  

  提示錯誤"Person.age 不可視",這說明static關鍵字並不會改變變量和方法的訪問權限。

2.能經過this訪問靜態成員變量嗎?

public class Main {  
    static int value = 33;
 
    public static void main(String[] args) throws Exception{
        new Main().printValue();
    }
 
    private void printValue(){
        int value = 3;
        System.out.println(this.value);
    }
}

輸出33

這裏面主要考察隊this和static的理解。this表明什麼?this表明當前對象,那麼經過new Main()來調用printValue的話,當前對象就是經過new Main()生成的對象。而static變量是被對象所享有的,所以在printValue中的this.value的值毫無疑問是33。在printValue方法內部的value是局部變量,根本不可能與this關聯,因此輸出結果是33。在這裏永遠要記住一點:靜態成員變量雖然獨立於對象,可是不表明不能夠經過對象去訪問,全部的靜態方法和靜態變量均可以經過對象訪問(只要訪問權限足夠)。

3.static能做用於局部變量麼?

  static是不容許用來修飾局部變量。

下面利用畫內存學習更加深入的需東西這一小節:

package satic;
public class Cat {
    private static int sid = 0; // sid是靜態的能夠直接用類名變量名直接用

private String name; //Cat類私有的屬性name 初始值爲0 int id; //變量 Cat(String name) { this.name = name; //將調用Cat方法時傳入的值賦值給name屬性 id = sid++; //將sid的值賦值給id而且sid自增1 } //info方法輸入name和id的值 public void info(){ System.out.println ("My name is "+name+" No."+id); } public static void main(String arg[]){ Cat.sid = 100; //將sid的值變爲100 /* * 調用Cat 方法更改name與id的值並打印 * */ Cat mimi = new Cat("mimi"); Cat pipi = new Cat("pipi"); mimi.info(); pipi.info(); } }

 先從main函數入口開始,

  Cat.sid = 100在數據區當中有一個sid,被賦值爲100,Cat mimi = new Cat("mimi")時,在棧內存當中有一個叫mimi的內存具體內容不知,但他指向堆內存當中的一塊內存,在堆內存當中有兩個分別是id和name的屬性,而mimi這個字符串是存儲在數據區的,字符串也是個引用類型,因此說字符串能夠看做是一個對象,執行

Cat(String name) {
        this.name = name;  //將調用Cat方法時傳入的值賦值給name屬性
        id = sid++; //將sid的值賦值給id而且sid自增1
 }
時在棧內存裏面有一個name的內存而後,這個"mimi"的引用交到name中,如今name指向"mimi"字符串,this.name = name,這句話中
將棧內存的name的值賦值給堆內存中mimi這個對象的name,也就是mimi這個對象的name也指向數據區裏面的「mimi」字符串,而後將sid的
值賦值給id,sid自身+1,這時候的內存中的圖以下:

 

 

而後構造方法執行完畢,給這個構造方法分配的局部變量所佔的內存空間所有消失,因此位於棧內存的name這塊內存消失了,棧內存裏面指向數據區裏面的字符串對象"mimi"的引用也隨之消失,此時只剩下堆內存裏面的字符串對象「mimi」的引用沒有消失,此時的內存佈局以下

 

執行Cat pipi  = new Cat("pipi"),執行過程u第一次同樣,這裏就不過多解釋了,此時的內存佈局以下圖:

The result is:

My name is mimi No.100
My name is pipi No.2000

 

 由此能夠看出這個靜態的sid能夠計數用的

這裏調用構造方法Cat(String name) 建立出兩隻貓,首先在棧內存裏面分配兩小塊空間mimi和pipi,裏面分別裝着能夠找到這兩隻貓的地址,mimi和pipi對應着堆內存裏面的兩隻貓的引用。這裏的構造方法聲明有字符串類型的變量,字符串常量是分配在數據區裏面的,因此這裏會把傳過來的字符串mimi和pipi都存儲到數據區裏面。因此數據區裏面分配有存儲字符串mimi和pipi的兩小塊內存,裏面裝着字符串「mimi」和「pipi」,字符串也是引用類型,除了那四類8種的基礎數據類型以外,其餘全部的數據類型都是引用類型。因此能夠認爲字符串也是一個對象。

  這裏是new了兩隻貓出來,這兩隻貓都有本身的id和name屬性,因此這裏的id和name都是非靜態成員變量,即沒有static修飾。因此每new出一隻新貓,這隻新貓都有屬於它本身的id和name,即非靜態成員變量id和name是每個對象都有單獨的一份。但對於靜態成員變量來講,只有一份,無論new了多少個對象,哪怕不new對象,靜態成員變量在數據區也會保留一份。如這裏的sid同樣,sid存放在數據區,不管new出來了多少隻貓在堆內存裏面,sid都只有一份,只在數據區保留一份。

  靜態成員變量是屬於整個類的,它不屬於專門的某個對象。那麼如何訪問這個靜態成員變量的值呢?首先第一點,任何一個對象均可以訪問這個靜態的值,訪問的時候訪問的都是同一塊內存。第二點,即使是沒有對象也能夠訪問這個靜態的值,經過「類名.靜態成員變量名」來訪問這個靜態的值,因此之後看到某一個類名加上「.」再加上後面有一個東西,那麼後面這個東西必定是靜態的,如」System.out」,這裏就是經過類名(System類)再加上「.」來訪問這個out的,因此這個out必定是靜態的

下面再看這段代碼:

package satic;
public class Cat {
    /*
     * 這裏的sid不在是靜態的了
     */
    private  int sid = 0; 
    /*
     * 這裏的name和id是非靜態的成員變量
     * 
     */
    private String name;  //Cat類私有的屬性name 初始值爲0
    int id; //變量
    Cat(String name) {
        this.name = name;  //將調用Cat方法時傳入的值賦值給name屬性
        id = sid++; //將sid的值賦值給id而且sid自增1
    }
    //info方法輸入name和id的值
    public void info(){
        System.out.println
               ("My name is "+name+" No."+id);
    }
    public static void main(String arg[]){

        //Cat.sid = 100;   上面的sid不在是靜態的了,因此不能這樣來訪問了
        
        /*
         * 調用Cat 方法更改name與id的值並打印
         * 
         */
        Cat mimi = new Cat("mimi"); 
        mimi.sid = 2000;
        Cat pipi = new Cat("pipi");
        mimi.info(); 
        pipi.info();
    }
}

這段代碼與上面的代碼不一樣的是,將sid變成了非靜態的,就再也不有計數功能了,sid和name與id同樣都屬於屬性,固然在面的代碼當中也不能使用Cat.sid訪問了,把Cat.sid那行去掉便可,這樣的話,內存圖就變成了下面的:

 

 成員變量(屬性)與局部變量的區別在於,成員變量(屬性)初始的值爲0,而局部變量沒有初始化不能使用,因此,每次執行Cat方法,sid由0變爲1,這樣sid就沒有了計數的功能

在一個靜態方法裏,若是想訪問一個非靜態的成員變量,是不能直接訪問的,必須在靜態方法裏new一個對象出來才能訪問。若是是加了static的成員變量,那麼這個成員變量就是一個靜態的成員變量,就能夠在main方法裏面直接訪問了。

  main方法是一個靜態的方法,main方法要執行的時候不須要new一個對象出來。

 動態方法是針對於某一個對象調用的,靜態方法不會針對某一個對象來調用,沒有對象照樣能夠用。因此可使用」classname.method()」.的形式來調用靜態方法。因此想在main方法裏面訪問非靜態成員變量是不能夠的,想在main方法裏面訪問非靜態方法也是不能夠的,由於非靜態方法只能針對於某個對象來調用,沒有對象,就找不到方法的執行者了。

成員變量只有在new出一個對象來的時候纔在堆內存裏面分配存儲空間。局部變量在棧內存裏面分配存儲空間。

  靜態方法再也不是針對某一個對象來調用,因此不能訪問非靜態的成員。

  非靜態成員專屬於某一個對象,想訪問非靜態成員必須new一個對象出來才能訪問。

  靜態的變量能夠經過對象名去訪問,也能夠經過類名去訪問,二者訪問的都是同一塊內存。

相關文章
相關標籤/搜索