之前幾節我們一直在說static關鍵字所修飾的靜態,那么在程序運行時,內存中static是如何體現的呢?這一節我們就來看一看。
我們還是先看一個例子,希望我們通過對這個例子的分析讓我們初學者們對static所修飾的靜態在內存中的具體體現有一個深刻的理解。
~~~
class Person
{
String name;//姓名,這是一個成員變量
int age;
static String country = "美國";//國籍,這是一個靜態變量
Person(String name,int age)//構造函數
{
this.name = name;
this.age = age;
}
public void printInfo()//非靜態函數
{
System.out.println(name+":"+age);
}
public static void printCoun()//靜態函數,打印靜態變量country
{
System.out.println(Person.country);
}
}
class StaticTest
{
public static void main(String[] args)
{
Person.printCoun();
Person p = new Person("科比",37);
p.printInfo();
}
}
~~~
我們先來看運行結果,然后再一步步分析:

例子很簡單,結果也很明顯,我們之前在7.9中談成員變量與靜態變量的區別時提到了一個區別就是成員變量是存儲在堆內存中的對象中,而靜態變量則存儲在方法區中的靜態區中。
這里,我們就引入了內存的一個新區域,那就是方法區,對于方法,當程序運行時,都會被存儲在這個區域。
那么我們就對上面的代碼運行過程和內存變化進行分析,當然在我們分析之前,我們必須明確一個常識,那就是**當我們執行類時,類就會進入內存。**
**
**
那么對于上面的代碼,分析過程就會很清晰了:
1.當我們運行程序時,StaticTest類進入內存,虛擬機會在方法區的非靜態區中分配空間存儲StaticTest(){}默認構造函數,同時在方法區的靜態中分配空間存儲static main(){……}主函數,當然包括主函數的所有代碼的字節碼。
2.靜態區的main函數進棧內存,main方法中有一個對象變量p。
3.執行Person.printCoun(){}方法,Person類進入內存,方法區的非表態區分配空間存放構造函數Person(name,age){……}和非靜態函數void printInfo(){……},在方法區的靜態區中分配空間存儲靜態變量country="美國"和靜態方法printCoun(){……}。
4.靜態區的printCoun()方法進棧內存,并從靜態區找到靜態變量country并打印,控制臺輸出:“美國”。
5.printCoun()方法執行結束,跳出方法,printCoun()方法出棧內存。
6.執行Person p = new Person("科比",37),此時堆內存中創建空間存儲對象,這里假設地址為0x0056,則所屬this=0x0056,并有成員變量name和age。
7.非靜態區的構造函數Person(name,age)進棧內存,對對象進行初始化,為堆內存中的對象進行初始化,name=科比,age=37。
8.初始化完成,把地址0x0056賦值給對象p,p=0x0056。
9.構造函數出棧內存,釋放參數name和age。
10.執行p.printInfo()語句,非表態區的printInfo()方法進棧內存,this=0x0056。
11.打印this所指向的成員變量this.name和this.age,控制臺輸出:科比:37。
12.printInfo()方法執行結束,跳出方法,方法出棧內存。
13.main()函數執行結束,跳出,函數出棧內存。
14.程序運行結束。
上面我們對例子中的代碼進行了逐步分析,基本上明晰了static關鍵字所修飾的靜態在程序運行時在內存中的具體變化,希望在以后的實際開發過程中有所幫助。
最后我們再說一個小知識點:**存儲在方法區中的變量和方法都會對象所共享,所以方法區又稱為共享區。**
**
**
- 前言
- 1.1 基本常識
- 1.2 Java語言概述
- 1.3 Java語言的環境搭建
- 1.4 Java程序開發之初體驗--Hello World
- 2.1 關鍵字
- 2.2 標識符
- 2.3 注釋
- 2.4 常量
- 2.5 進制掃盲
- 2.6 變量和數據類型(1)
- 2.7 變量和數據類型(2)
- 2.8 運算符
- 3.1 if語句
- 3.2 switch語句
- 3.3 while和do-while語句
- 3.4 for語句
- 3.5 for循環的嵌套
- 3.6 break語句與continue語句
- 4.1 函數的定義
- 4.2 定義函數的兩個明確
- 4.3 函數的內存加載過程
- 4.4 函數的重載
- 5.1 數組的定義
- 5.2 數組的內存分配及特點
- 5.3 數組操作中常見問題
- 5.4 數組常用操作(1)
- 5.5 數組常用操作(2)
- 5.6 二維數組
- 6.1 面向對象的概述
- 6.2 類與對象的關系
- 6.3 對象的內存體現
- 6.4 成員變量與局部變量
- 6.5 類類型參數與匿名對象
- 6.6 基本數據類型參數與引用數據類型參數的傳遞過程
- 6.7 封裝
- 7.1 構造函數概述與默認構造函數
- 7.2 構造函數與一般函數的區別
- 7.3 構造函數的重載
- 7.4 構造函數的內存加載
- 7.5 構造函數需要注意的幾個細節
- 7.6 this關鍵字的原理
- 7.7 this關鍵字的細節與應用
- 8.1 static關鍵字之特點
- 8.2 成員變量與靜態變量的區別
- 8.3 static關鍵字使用的注意細節
- 8.4 main函數的解析與細節
- 8.5 static關鍵字的使用場景
- 8.6 靜態的內存加載
- 8.7 靜態代碼塊
- 8.8 構造代碼塊
- 9.1 繼承
- 9.2 單繼承與多重繼承
- 9.3 子父類中成員變量特征體現