java static關鍵字的四種用法


最近在熟悉項目代碼時,看到了關於static的新用法,網上查找重新學習了一下關於static的用法,看到一篇好文章,記錄下

https://www.dazhuanlan.com/2020/03/26/5e7cb77177083/

 上一章說到了static關鍵字,static是Java中很重要的一個關鍵字,在一些場景下可以達到優化程序的效果。本文學習它的不同使用場景。在此之前先了解一下變量的類型。Java中變量分為兩種,按作用域分為成員變量和局部變量。成員變量是在類中聲明的,不屬於任何方法,當前類中有效。局部變量是聲明在方法中的,出了當前方法即超出作用域。接下來正文說一下static關鍵字的四中使用場景:

    static最常用的作用就是修飾成員變量,被static修飾的成員變量也叫做類變量。它與普通成員變量的區別是,它在內存中只有一份拷貝,Java虛擬機只為其分配一次內存。通俗的講就是,這個變量,不管被多少人使用,他們使用的都是同一個變量,彼此的修改會有影響。可以通過類名.變量的形式進行訪問。而普通的成員變量則是沒實例化一個對象就產生一個拷貝,虛擬機為每一個變量拷貝都分配了內存。所以類變量的用處一般在於進行變量共享的時候。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class {
private String name;
private int age;
public void print(){
System.out.println("Name:" + name + "---Age:" + age);
}
public static void main(String[] args) {
TestStatic ts1 = new TestStatic();
TestStatic ts2 = new TestStatic();
ts1.name = "zhangsan";
ts1.age = 22;
ts2.name = "lisi";
ts2.age = 33;
ts1.print();
ts2.print();
}
}

這是普通的成員變量的例子,ts1和ts2對於變量name和age分別擁有自己的副本,互相不影響,所以賦值之后,他們能得到他們期望的值。

png1

接下來將成員變量age修改為類變量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class {
private String name;
private static int age;
public void print(){
System.out.println("Name:" + name + "---Age:" + age);
}
public static void main(String[] args) {
TestStatic ts1 = new TestStatic();
TestStatic ts2 = new TestStatic();
ts1.name = "zhangsan";
ts1.age = 22;
ts2.name = "lisi";
ts2.age = 33;
ts1.print();
ts2.print();
}
}

這時由於age變成了類變量,因此ts1和ts2共用了一個變量副本,先賦值的會被后賦值的覆蓋掉。

png2

此外第二個示例代碼中,靜態成員變量使用了對象.變量的方式進行調用,這里編譯器會給出警告,使用類名.方法之后警告就會解除。

png3

二、修飾成員方法

    static另一個作用是修飾類中的方法,其目的是可以通過類名.方法的形式調用方法,而避免頻繁的創建對象。同時對於存儲空間來說也只有一個,不同對象調用的是同一個方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class {
private String name;
private static int age;
public static void print(){
System.out.println("Name:" + name + "---Age:" + age);
}
public static void main(String[] args) {
TestStatic ts1 = new TestStatic();
TestStatic ts2 = new TestStatic();
ts1.name = "zhangsan";
ts1.age = 22;
ts2.name = "lisi";
TestStatic.age = 33;
TestStatic.print();
TestStatic.print();
}
}

將之前代碼中的print方法改為使用static修飾之后,這個方法就可以不用對象.方法的形式調用了。

三、修飾代碼塊

    我們先看一下對象的初始化過程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Load {
public Load(String msg){
System.out.println(msg);
}
}
public class {
Load ld1 = new Load("普通變量1");
Load ld2 = new Load("普通變量2");
static Load ld3 = new Load("靜態變量3");
static Load ld4 = new Load("靜態變量4");
public (String msg){
System.out.println(msg);
}
public static void main(String[] args) {
TestStatic ts = new TestStatic("TestStatic 初始化");
}
}

    在類TestStatic中,我們初始化了兩個普通成員變量和兩個靜態成員變量,並在main函數開始的時候初始化了TestStatic對象。結果如下:

png4

    靜態成員變量最先被初始化,並且按照執行的先后順序進行初始化。其次初始化的是成員變量,最后初始化的是構造方法。所以在創建一個對象的時候,最先被初始化的是靜態成員變量。

    在看另外一個調用了靜態方法的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Load {
public Load(String msg){
System.out.println(msg);
}
}
public class TestStatic{
Load ld1 = new Load("普通變量1");
Load ld2 = new Load("普通變量2");
static Load ld3 = new Load("靜態變量3");
static Load ld4 = new Load("靜態變量4");
public TestStatic(String msg){
System.out.println(msg);
}
public static void staticFunc(){
System.out.println("靜態方法");
}
public static void main(String[] args) {
TestStatic.staticFunc();
System.out.println("@@@@@@@@@");
TestStatic ts = new TestStatic("TestStatic 初始化");
}
}

我們在創建對象之前先調用了靜態方法,結果如下:

png5

    我們可以看到,靜態成員的初始化發生在創建對象之前,確切的說是在調用靜態方法之前就已經被初始化了。並且,當我們創建對象的時候,原本被初始化過的靜態成員變量跟靜態方法沒有再次被初始化。

    這時我們的static的作用就是,修飾一段都需要被修飾為static的域。被static修飾的代碼域,域中所有的內容都被當成static變量,且優先初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Load {
public Load(String msg){
System.out.println(msg);
}
}
public class TestStatic{
Load ld1 = new Load("普通變量1");
Load ld2 = new Load("普通變量2");
static Load ld3;
static Load ld4;
static{
ld3 = new Load("靜態變量3");
ld4 = new Load("靜態變量4");
}

public TestStatic(String msg){
System.out.println(msg);
}
public static void staticFunc(){
System.out.println("靜態方法");
}
public static void main(String[] args) {
TestStatic.staticFunc();
System.out.println("@@@@@@@@@");
TestStatic ts = new TestStatic("TestStatic 初始化");
}
}

修改之前的代碼將靜態成員變量放在由static修飾的域中,結果如下:

png6

與分開修飾結果相同。

四、靜態導入

    前邊三種都是比較常用的場景,還有一種不是太常用,是JDK1.5之后新加入的功能,導入一個帶有靜態方法的包,並將包修飾為static,從而在當前類中直接調用修飾的靜態方法,就好像是自己的方法一樣:

1
2
3
4
5
6
package com.chenxyt.java.test;
public class Printer {
public static void print(String msg){
System.out.println(msg);
}
}

然后另一個包中使用import static導入這個類

1
2
3
4
5
6
7
package com.chenxyt.java.practice;
import static com.chenxyt.java.test.Printer.*;
public class TestStatic{
public static void main(String[] args) {
print("This is TestStatic");
}
}

運行結果:

png7

五、總結

    static是Java語言中的一個很重要的關鍵字,主要用途有三個方面修飾成員變量,修飾成員方法以及修飾代碼塊。使用static修飾的成員變量在類加載的時候就已經被初始化了,它屬於類變量,不屬於某個對象,所有該類的實例化對象擁有同一個靜態成員變量副本,常用的用途可以用它來做計數器。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM