欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的static關(guān)鍵字用法總結(jié)

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

一、static 關(guān)鍵字的含義

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

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

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

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

二、static 關(guān)鍵字的用途

1、修飾代碼塊

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

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

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

2、修飾成員變量

類中用static關(guān)鍵字修飾的成員變量稱為靜態(tài)成員變量,因?yàn)閟tatic不能修飾局部變量(為什么?),因此靜態(tài)成員變量也能稱為靜態(tài)變量。靜態(tài)變量跟代碼塊類似,在類加載到JVM內(nèi)存中,JVM會(huì)把靜態(tài)變量放入方法區(qū)并分配內(nèi)存,也由線程共享。訪問形式是:類名.靜態(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;
}

運(yùn)行結(jié)果:

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

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

注意:

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

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

可以想一下運(yùn)行的結(jié)果。

  • 靜態(tài)變量可以不用顯式的初始化,JVM會(huì)默認(rèn)給其相應(yīng)的默認(rèn)值。如基本數(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內(nèi)存中共享的且可以改變,那么對(duì)它的訪問會(huì)引起線程安全問題(線程A改寫的同時(shí),線程B獲取它的值,那么獲取的是修改前的值還是修改后的值呢?),所以使用靜態(tài)變量的同時(shí)要考慮多線程情況。如果能確保靜態(tài)變量不可變,那么可以用final關(guān)鍵字一起使用避免線程安全問題;否則需要采用同步的方式避免線程安全問題,如與volatile關(guān)鍵字一起使用等。
  • static關(guān)鍵不能修飾局部變量,包括實(shí)例方法和靜態(tài)方法,不然就會(huì)與static關(guān)鍵字的初衷-共享相違背。

3、修飾方法

static方法一般稱作靜態(tài)方法,由于靜態(tài)方法不依賴于任何對(duì)象就可以進(jìn)行訪問,因此對(duì)于靜態(tài)方法來說,是沒有this的,因?yàn)樗灰栏接谌魏螌?duì)象,既然都沒有對(duì)象,就談不上this了。并且由于這個(gè)特性,在靜態(tài)方法中不能訪問類的非靜態(tài)成員變量和非靜態(tài)成員方法,因?yàn)榉庆o態(tài)成員方法/變量都是必須依賴具體的對(duì)象才能夠被調(diào)用。

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

在這里插入圖片描述

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

MyObject.print2();

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

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

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

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

1、static關(guān)鍵字會(huì)改變類中成員的訪問權(quán)限嗎?

有些初學(xué)的朋友會(huì)將java中的static與C/C++中的static關(guān)鍵字的功能混淆了。在這里只需要記住一點(diǎn):與C/C++中的static不同,Java中的static關(guān)鍵字不會(huì)影響到變量或者方法的作用域。在Java中能夠影響到訪問權(quán)限的只有private、public、protected(包括包訪問權(quán)限)這幾個(gè)關(guān)鍵字??聪旅娴睦泳兔靼琢耍?/p>

在這里插入圖片描述

提示錯(cuò)誤"Person.age 報(bào)紅",這說明static關(guān)鍵字并不會(huì)改變變量和方法的訪問權(quán)限。

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

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

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

輸出結(jié)果:

33

這里面主要考察隊(duì)this和static的理解。this代表什么?this代表當(dāng)前對(duì)象,那么通過new Main()來調(diào)用printValue的話,當(dāng)前對(duì)象就是通過new Main()生成的對(duì)象。而static變量是被對(duì)象所享有的,因此在printValue中的this.value的值毫無疑問是33。在printValue方法內(nèi)部的value是局部變量,根本不可能與this關(guān)聯(lián),所以輸出結(jié)果是33。在這里永遠(yuǎn)要記住一點(diǎn):靜態(tài)成員變量雖然獨(dú)立于對(duì)象,但是不代表不可以通過對(duì)象去訪問,所有的靜態(tài)方法和靜態(tài)變量都可以通過對(duì)象訪問(只要訪問權(quán)限足夠)。

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

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

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

4、static關(guān)鍵字修飾內(nèi)部類

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

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

四、常見的筆試面試題

下面列舉一些面試筆試中經(jīng)常遇到的關(guān)于static關(guān)鍵字的題目,僅供參考,如有補(bǔ)充歡迎下方留言。

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

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

輸出結(jié)果:

base static
test static
base constructor
test constructor

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

2、這段代碼的輸出結(jié)果是什么?

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

輸出結(jié)果:

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

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

3、這段代碼的輸出結(jié)果是什么?

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

輸出結(jié)果:

test static 1
test static 2

雖然在main方法中沒有任何語(yǔ)句,但是還是會(huì)輸出,原因上面已經(jīng)講述過了。

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

五、static關(guān)鍵字的缺點(diǎn)

封裝是Java類的三大特性之一,也是面向?qū)ο蟮闹饕匦浴?/p>

因?yàn)椴恍枰ㄟ^對(duì)象,而直接通過類就能訪問類的屬性和方法,這有點(diǎn)破壞類的封裝性;

所以除了Utils類,代碼中應(yīng)該盡量少用static關(guān)鍵字修飾變量和方法。

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

相關(guān)文章

  • springboot配置mysql連接的實(shí)例代碼

    springboot配置mysql連接的實(shí)例代碼

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

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

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

    SpringBoot MyBatis簡(jiǎn)單快速入門例子

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

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

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

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

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

    Spring中的注解之@Override和@Autowired

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

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

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

    Java字符編碼簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

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

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

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

    SpringBoot3集成Redis的方法詳解

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

最新評(píng)論