1. 程式人生 > >Java不得不說的事之Static關鍵字

Java不得不說的事之Static關鍵字

紙上得來終覺淺,絕知此事要躬行

本文主要用於學習內容的記錄和整理,如有不正請儘量指正。

static關鍵字

本文以static的五個用法作為思路進行整理。

 靜態變數
 靜態方法
靜態程式碼段
靜態匯入

一、靜態變數

我們把java中的變數且分成靜態變數以及非靜態變數來理解。

靜態變數屬於類,非靜態變數屬於物件 我們怎麼理解這句話呢?先來一個非靜態變數的例子。

//Demo1_非靜態變數賦值
public class Book {
    String name;
    int price;
    
    public String toString() {
        return
"Name:" + name + ", Price:" + price; } public static void main(String[] args) { Book p1 = new Book(); b1.name = "Math"; p1.price = 10; Book p2 = new Book(); p2.name = "History"; p2.price = 12; System.out.println(p1); System.
out.println(p2); } /**Output * Name:Math, Price:10 * Name:History, Price:12 *///~ }

Animal這個物件中的屬性各自進行賦值,不會相互干擾,各個物件對應的屬性的值各不相同。下面是一份靜態變數的例子。

//demo2_靜態變數
public class Person {
    String name;
    static int age;
    
 public String toString() {
        return "Name:" + name + ", Price:"
+ price; } public static void main(String[] args) { Book p1 = new Book(); b1.name = "Math"; p1.price = 10; Book p2 = new Book(); p2.name = "History"; p2.price = 12; System.out.println(p1); System.out.println(p2); } /**Output * Name:Math, Price:12 * Name:History, Price:12 *///~ }

可以發現與非靜態變數的區別在於demo2的price變數被static修飾了。在二次賦值的時候會影響到其他物件的price屬性。 接下來我們從記憶體儲存過程的原因來分析為什麼出現這個情況。 在這裡插入圖片描述

非靜態變數price這個屬性值,屬於Book1或者book2物件,當price被static修飾之後,price移到了靜態儲存區,屬於book類

在這裡插入圖片描述 經過上圖以及程式碼的分析,我們已經可以清楚,當給price屬性加上static之後,Book物件就不再擁有price這個屬性了,這個屬性就統一交給Book類去管理了,即有多個book物件也將只有一個price值。

靜態變數有什麼用?

有某個變數在程式的任何地方都可能用到,可以將這個變數設定成靜態變數,避免每次使用到這個變數的時候都要建立一個對應的物件,浪費記憶體空間。

二、靜態方法

我依然把JAVA中的方法區分成靜態方法以及非靜態方法。 靜態方法:類的方法,用Class.MethodName進行呼叫 非靜態方法:物件的方法,用Object.MethodName進行呼叫

使用靜態方法的一個好處是可以直接使用類名.方法名的形式進行呼叫,可以不必頻繁New新的物件。

static方法中不能使用this和super關鍵字,不能呼叫非static方法,只能訪問所屬類的靜態變數和靜態方法。因為當static方法被呼叫的時候,這個類的物件可能還沒有建立,即使已經被建立了,也無法確認呼叫那個物件的方法。不能訪問非靜態方法同理。

static修飾的變數是可以用private限定的,這種情況下的變數可以出現在靜態程式碼塊中,或者類的其他靜態方法中使用,當然非靜態方法也可以。但是不能再其他類中通過類名來直接引用。需要清楚的是private是訪問許可權限定,static代表的不需要例項就可以使用,二者不衝突所以可以配合使用。

三、靜態程式碼塊

首先我們先理清一下什麼叫做程式碼塊。下來是百度知道的解釋,非常清楚了。 程式碼塊是一種常見的程式碼形式。他用大括號“{}”將多行程式碼封裝在一起,形成一個獨立的程式碼區,這就構成了程式碼塊。 在Java中程式碼塊主要分為四種:普通程式碼塊,靜態程式碼塊,同步程式碼塊和構造程式碼塊。

  • 普通程式碼塊

方法名後面用{}括起來的程式碼段。普通程式碼塊是不能夠單獨存在的,它必須要緊跟在方法名後面。同時也必須要使用方法名呼叫它

  • 靜態程式碼塊

靜態程式碼塊就是用static修飾的用{}括起來的程式碼段,它的主要目的就是對靜態屬性進行初始化。靜態程式碼塊可以有多個,位置可以隨便放,它不在任何的方法體內,JVM載入類時會執行這些靜態的程式碼塊,如果static程式碼塊有多個,JVM將按照它們在類中出現的先後順序依次執行它們,每個程式碼塊只會被執行一次。

  • 同步程式碼塊

使用 synchronized 關鍵字修飾,並使用“{}”括起來的程式碼片段,它表示同一時間只能有一個執行緒進入到該方法塊中,是一種多執行緒保護機制。

  • 構造程式碼塊

在類中直接定義沒有任何修飾符、字首、字尾的程式碼塊即為構造程式碼塊。我們明白一個類必須至少有一個建構函式,建構函式在生成物件時被呼叫。構造程式碼塊和建構函式一樣同樣是在生成一個物件時被呼叫,那麼構造程式碼在什麼時候被呼叫?如何呼叫的呢?

在CSDN上看到一個非常好的文章中找到一個很好的程式碼樣例

public class CodeBlock {
    private int a = 1;
    private int b ;
    private int c ;
    //靜態程式碼塊
    static {
        int a = 4;
        System.out.println("我是靜態程式碼塊1");
    }
    //構造程式碼塊
    {
        int a = 0;
        b = 2;
        System.out.println("構造程式碼塊1");
    }

    public CodeBlock(){
        this.c = 3;
        System.out.println("建構函式");
    }

    public int add(){

        System.out.println("count a + b + c");
        return a + b + c;
    }
    //靜態程式碼塊
    static {
        System.out.println("我是靜態程式碼塊2,我什麼也不做");
    }
    //構造程式碼塊
    {
        System.out.println("構造程式碼塊2");
    }
    public static void main(String[] args) {
        CodeBlock c = new CodeBlock();
        System.out.println(c.add());

        System.out.println();
        System.out.println("*******再來一次*********");
        System.out.println();

        CodeBlock c1 = new CodeBlock();
        System.out.println(c1.add());
    }
}
//結果:
//我是靜態程式碼塊1
//我是靜態程式碼塊2,我什麼也不做
//構造程式碼塊1
//構造程式碼塊2
//建構函式
//count a + b + c
//6
//
//*******再來一次*********
//
//構造程式碼塊1
//構造程式碼塊2
//建構函式
//count a + b + c
//6

可以得到如下結論

- 靜態程式碼塊只會執行一次。有多個靜態程式碼塊時按順序依次執行。
- 構造程式碼塊每次建立新物件時都會執行。有多個時依次執行。
- 執行順序:靜態程式碼塊 > 構造程式碼塊 > 建構函式。
- 構造程式碼塊和靜態程式碼塊有自己的作用域,作用域內部的變數不影響作用域外部。

四、靜態導包

這個內容在整理static關鍵字之前我完全不知道有這麼一個知識點。看來整理還是有點用處的。 寫法:import static com.xxx.xxx.*; 下面用程式碼來解釋

package com.boom.static;

public class BoomHelper {
    public static void print(Object o){
        System.out.println(o);
    }
}
import static com.boom.static.BoomHelper.*;

public class test
{
    public static void main( String[] args )
    {
        print("Hello World!");
    }
    /**Output
     * Hello World!
     *///~
}

在使用靜態匯入之後呼叫匯入的方法時無需使用類名.方法名的形式進行,可以更加簡潔的直接使用方法名進行呼叫方法。

總結

static是java中非常重要的一個關鍵字,而且它的用法也很豐富,主要有四種用法:

用來修飾成員變數,將其變為類的成員,從而實現所有物件對於該成員的共享;
用來修飾成員方法,將其變為類方法,可以直接使用“類名.方法名”的方式呼叫,常用於工具類;
靜態塊用法,將多個類成員放在一起初始化,使得程式更加規整,其中理解物件的初始化過程非常關鍵;
靜態導包用法,將類的方法直接匯入到當前類中,從而直接使用“方法名”即可呼叫類方法,更加方便。