亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java中的static關鍵字用法總結

 更新時間:2023年11月10日 10:13:34   作者:老周聊架構  
這篇文章主要介紹了Java中的static關鍵字用法總結,static是Java50個關鍵字之一,static關鍵字可以用來修飾代碼塊表示靜態(tài)代碼塊,修飾成員變量表示全局靜態(tài)成員變量,修飾方法表示靜態(tài)方法,需要的朋友可以參考下

一、static 關鍵字的含義

static是Java50個關鍵字之一。static關鍵字可以用來修飾代碼塊表示靜態(tài)代碼塊,修飾成員變量表示全局靜態(tài)成員變量,修飾方法表示靜態(tài)方法。(注意:不能修飾普通類,除了內部類,這是為什么?)

class A {
	static {
		System.out.println("A : 靜態(tài)代碼塊");
	}
	static int i ;  // 靜態(tài)變量
	static void method() {
		System.out.println("A: 靜態(tài)方法");
	}
}

簡而言之,被static關鍵字修飾的內容都是靜態(tài)的。

靜態(tài)是相對于動態(tài)的,動態(tài)是指Java程序在JVM上運行時,JVM會根據(jù)程序的需要動態(tài)創(chuàng)建對象并存儲對象(分配內存),對象使命結束后,對象會被垃圾回收器銷毀,即內存回收由JVM統(tǒng)一管理并分配給其他新創(chuàng)建的對象;靜態(tài)是指Java程序還沒有運行時,JVM就會為加載的類分配空間存儲被static關鍵字修飾的內容;如靜態(tài)成員變量,Java類加載到JVM中,JVM會把類以及類的靜態(tài)成員變量存儲在方法區(qū),我們知道方法區(qū)是線程共享且很少發(fā)生GC的區(qū)域,所以被static關鍵字修飾的內容都是全局共享的,且只會為其分配一次存儲空間。 所以當類的某些內容不屬于對象,而由對象共享即屬于類的時候,就可以考慮是否用static關鍵字進行修飾。

二、static 關鍵字的用途

1、修飾代碼塊

類中用static關鍵字修飾的代碼塊稱為靜態(tài)代碼,反之沒有用static關鍵字修飾的代碼塊稱為實例代碼塊。

實例代碼塊會隨著對象的創(chuàng)建而執(zhí)行,即每個對象都會有自己的實例代碼塊,表現(xiàn)出來就是實例代碼塊的運行結果會影響當前對象的內容,并隨著對象的銷毀而消失(內存回收);而靜態(tài)代碼塊是當Java類加載到JVM內存中而執(zhí)行的代碼塊,由于類的加載在JVM運行期間只會發(fā)生一次,所以靜態(tài)代碼塊也只會執(zhí)行一次。

因為靜態(tài)代碼塊的主要作用是用來進行一些復雜的初始化工作,所以靜態(tài)代碼塊跟隨類存儲在方法區(qū)的表現(xiàn)形式是靜態(tài)代碼塊執(zhí)行的結果存儲在方法區(qū),即初始化量存儲在方法區(qū)并被線程共享。

2、修飾成員變量

類中用static關鍵字修飾的成員變量稱為靜態(tài)成員變量,因為static不能修飾局部變量(為什么?),因此靜態(tài)成員變量也能稱為靜態(tài)變量。靜態(tài)變量跟代碼塊類似,在類加載到JVM內存中,JVM會把靜態(tài)變量放入方法區(qū)并分配內存,也由線程共享。訪問形式是:類名.靜態(tài)成員名。

public class StaticTest {
	public static void main(String[] args) {
		System.out.println(D.i);
		System.out.println(new D().i);
	}
}
class D {
	static {
		i = 2;
		System.out.println("D : 靜態(tài)代碼塊1");
	}
	static int i;
}

運行結果:

D : 靜態(tài)代碼塊1
2
2

靜態(tài)變量存儲在類的信息中,且可以在線程間共享,那么它當然也屬于該類的每個對象,因此可以通過對象訪問靜態(tài)變量,但編譯器并不支持這么做,且會給出警告。

注意:

一個類的靜態(tài)變量和該類的靜態(tài)代碼塊的加載順序。類會優(yōu)先加載靜態(tài)變量,然后加載靜態(tài)代碼塊,但有多個靜態(tài)變量和多個代碼塊時,會按照編寫的順序進行加載。

public class Main {
	public static void main(String[] args) {
		System.out.println(new D().i);
	}
}
class D {
	static {
		i = 2;
		System.out.println("D : 靜態(tài)代碼塊1");
	}
	static {
		i = 6;
		System.out.println("D : 靜態(tài)代碼塊2");
	}
	static int i;
}

可以想一下運行的結果。

  • 靜態(tài)變量可以不用顯式的初始化,JVM會默認給其相應的默認值。如基本數(shù)據(jù)類型的byte為0,short為0,char為\u0000,int為0,long為0L,float為0.0f,double為0.0d,boolean為false,引用類型統(tǒng)一為null。
  • 靜態(tài)變量既然是JVM內存中共享的且可以改變,那么對它的訪問會引起線程安全問題(線程A改寫的同時,線程B獲取它的值,那么獲取的是修改前的值還是修改后的值呢?),所以使用靜態(tài)變量的同時要考慮多線程情況。如果能確保靜態(tài)變量不可變,那么可以用final關鍵字一起使用避免線程安全問題;否則需要采用同步的方式避免線程安全問題,如與volatile關鍵字一起使用等。
  • static關鍵不能修飾局部變量,包括實例方法和靜態(tài)方法,不然就會與static關鍵字的初衷-共享相違背。

3、修飾方法

static方法一般稱作靜態(tài)方法,由于靜態(tài)方法不依賴于任何對象就可以進行訪問,因此對于靜態(tài)方法來說,是沒有this的,因為它不依附于任何對象,既然都沒有對象,就談不上this了。并且由于這個特性,在靜態(tài)方法中不能訪問類的非靜態(tài)成員變量和非靜態(tài)成員方法,因為非靜態(tài)成員方法/變量都是必須依賴具體的對象才能夠被調用。

但是要注意的是,雖然在靜態(tài)方法中不能訪問非靜態(tài)成員方法和非靜態(tài)成員變量,但是在非靜態(tài)成員方法中是可以訪問靜態(tài)成員方法/變量的。舉個簡單的例子:

在這里插入圖片描述

在上面的代碼中,由于print2方法是獨立于對象存在的,可以直接用過類名調用。假如說可以在靜態(tài)方法中訪問非靜態(tài)方法/變量的話,那么如果在main方法中有下面一條語句:

MyObject.print2();

此時對象都沒有,str2根本就不存在,所以就會產生矛盾了。同樣對于方法也是一樣,由于你無法預知在print1方法中是否訪問了非靜態(tài)成員變量,所以也禁止在靜態(tài)成員方法中訪問非靜態(tài)成員方法。

而對于非靜態(tài)成員方法,它訪問靜態(tài)成員方法/變量顯然是毫無限制的。

因此,如果說想在不創(chuàng)建對象的情況下調用某個方法,就可以將這個方法設置為static。我們最常見的static方法就是main方法,至于為什么main方法必須是static的,現(xiàn)在就很清楚了。因為程序在執(zhí)行main方法的時候沒有創(chuàng)建任何對象,因此只有通過類名來訪問。

三、static 關鍵字的誤區(qū)

1、static關鍵字會改變類中成員的訪問權限嗎?

有些初學的朋友會將java中的static與C/C++中的static關鍵字的功能混淆了。在這里只需要記住一點:與C/C++中的static不同,Java中的static關鍵字不會影響到變量或者方法的作用域。在Java中能夠影響到訪問權限的只有private、public、protected(包括包訪問權限)這幾個關鍵字。看下面的例子就明白了:

在這里插入圖片描述

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

2、能通過this訪問靜態(tài)成員變量嗎?

雖然對于靜態(tài)方法來說沒有this,那么在非靜態(tài)方法中能夠通過this訪問靜態(tài)成員變量嗎?先看下面的一個例子,這段代碼輸出的結果是什么?

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關聯(lián),所以輸出結果是33。在這里永遠要記住一點:靜態(tài)成員變量雖然獨立于對象,但是不代表不可以通過對象去訪問,所有的靜態(tài)方法和靜態(tài)變量都可以通過對象訪問(只要訪問權限足夠)。

3、static能作用于局部變量么?

在C/C++中static是可以作用域局部變量的,但是在Java中切記:

static是不允許用來修飾局部變量。不要問為什么,這是Java語法的規(guī)定。

4、static關鍵字修飾內部類

static關鍵字雖然不能修飾普通類,但可以用static關鍵字修飾內部類使其變成靜態(tài)內部類。

static關鍵字本身的含義就是共享,而Java類加載到JVM內存的方法區(qū),也是線程共享的,所以沒必要用static關鍵字修飾普通類。

四、常見的筆試面試題

下面列舉一些面試筆試中經常遇到的關于static關鍵字的題目,僅供參考,如有補充歡迎下方留言。

1、下面這段代碼的輸出結果是什么?

public class Test extends Base{
    static{
        System.out.println("test static");
    }
    public Test(){
        System.out.println("test constructor");
    }
    public static void main(String[] args) {
        new Test();
    }
}
class Base{
    static{
        System.out.println("base static");
    }
    public Base(){
        System.out.println("base constructor");
    }
}

輸出結果:

base static
test static
base constructor
test constructor

至于為什么是這個結果,我們先不討論,先來想一下這段代碼具體的執(zhí)行過程,在執(zhí)行開始,先要尋找到main方法,因為main方法是程序的入口,但是在執(zhí)行main方法之前,必須先加載Test類,而在加載Test類的時候發(fā)現(xiàn)Test類繼承自Base類,因此會轉去先加載Base類,在加載Base類的時候,發(fā)現(xiàn)有static塊,便執(zhí)行了static塊。在Base類加載完成之后,便繼續(xù)加載Test類,然后發(fā)現(xiàn)Test類中也有static塊,便執(zhí)行static塊。在加載完所需的類之后,便開始執(zhí)行main方法。在main方法中執(zhí)行new Test()的時候會先調用父類的構造器,然后再調用自身的構造器。因此,便出現(xiàn)了上面的輸出結果。

2、這段代碼的輸出結果是什么?

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");
    }
}

輸出結果:

test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor

類似地,我們還是來想一下這段代碼的具體執(zhí)行過程。首先加載Test類,因此會執(zhí)行Test類中的static塊。接著執(zhí)行new MyClass(),而MyClass類還沒有被加載,因此需要加載MyClass類。在加載MyClass類的時候,發(fā)現(xiàn)MyClass類繼承自Test類,但是由于Test類已經被加載了,所以只需要加載MyClass類,那么就會執(zhí)行MyClass類的中的static塊。在加載完之后,就通過構造器來生成對象。而在生成對象的時候,必須先初始化父類的成員變量,因此會執(zhí)行Test中的Person person = new Person(),而Person類還沒有被加載過,因此會先加載Person類并執(zhí)行Person類中的static塊,接著執(zhí)行父類的構造器,完成了父類的初始化,然后就來初始化自身了,因此會接著執(zhí)行MyClass中的Person person = new Person(),最后執(zhí)行MyClass的構造器。

3、這段代碼的輸出結果是什么?

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

輸出結果:

test static 1
test static 2

雖然在main方法中沒有任何語句,但是還是會輸出,原因上面已經講述過了。

另外,static塊可以出現(xiàn)類中的任何地方(只要不是方法內部,記住,任何方法內部都不行),并且執(zhí)行是按照static塊的順序執(zhí)行的。

五、static關鍵字的缺點

封裝是Java類的三大特性之一,也是面向對象的主要特性。

因為不需要通過對象,而直接通過類就能訪問類的屬性和方法,這有點破壞類的封裝性;

所以除了Utils類,代碼中應該盡量少用static關鍵字修飾變量和方法。

到此這篇關于Java中的static關鍵字用法總結的文章就介紹到這了,更多相關Java的static關鍵字內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • springboot配置mysql連接的實例代碼

    springboot配置mysql連接的實例代碼

    這篇文章主要介紹了springboot配置mysql連接的實例代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • spring+hibernate 兩種整合方式配置文件的方法

    spring+hibernate 兩種整合方式配置文件的方法

    本篇文章主要介紹了spring+hibernate 兩種整合方式配置文件的方法,主要有兩種方式 1、注解方式 2、xml方式實現(xiàn),有興趣的可以了解一下。
    2017-04-04
  • SpringBoot MyBatis簡單快速入門例子

    SpringBoot MyBatis簡單快速入門例子

    MyBatis 是一款優(yōu)秀的持久層框架,它支持自定義 SQL、存儲過程以及高級映射。這篇文章主要介紹了SpringBoot MyBatis快速入門-簡單例子,需要的朋友可以參考下
    2021-07-07
  • Spring中@Autowired與@Resource的區(qū)別詳析

    Spring中@Autowired與@Resource的區(qū)別詳析

    @Autowired與@Resource都可以用來裝配bean,都可以寫在字段上,或寫在setter方法上,下面這篇文章主要給大家介紹了關于Spring中@Autowired與@Resource區(qū)別的相關資料,需要的朋友可以參考下
    2021-10-10
  • SpringBoot輕松整合MongoDB的全過程記錄

    SpringBoot輕松整合MongoDB的全過程記錄

    這篇文章主要給大家介紹了關于SpringBoot輕松整合MongoDB的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • Spring中的注解之@Override和@Autowired

    Spring中的注解之@Override和@Autowired

    看別人寫的代碼,經常會用到 @Override 和 @Autowired 這兩個注解.這邊總結一下這兩個注解的作用,對正在學習java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • Spring @Cacheable redis異常不影響正常業(yè)務方案

    Spring @Cacheable redis異常不影響正常業(yè)務方案

    這篇文章主要介紹了Spring @Cacheable redis異常不影響正常業(yè)務方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-02-02
  • Java字符編碼簡介_動力節(jié)點Java學院整理

    Java字符編碼簡介_動力節(jié)點Java學院整理

    這篇文章主要介紹了Java字符編碼簡介,本文主要包括以下幾個方面:編碼基本知識,Java,系統(tǒng)軟件,url,工具軟件等,感興趣的朋友一起看看吧
    2017-08-08
  • spring中的注解事務演示和添加步驟詳情

    spring中的注解事務演示和添加步驟詳情

    這篇文章主要介紹了spring中的注解事務演示和添加步驟詳情,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的朋友可以參考一下
    2022-07-07
  • SpringBoot3集成Redis的方法詳解

    SpringBoot3集成Redis的方法詳解

    緩存在項目開發(fā)中,基本上是必選組件之一,Redis作為一個key-value存儲系統(tǒng),具備極高的數(shù)據(jù)讀寫效率,并且支持的數(shù)據(jù)類型比較豐富,下面我們就來看看SpringBoot3是如何集成Redis的吧
    2023-08-08

最新評論