Java中的static修飾int值做全局變量與static修飾詞初始化順序


先看一道題

 1 public class HasStatic{
 2   private static int x=100;
 3   public static void main(String args[]){
 4       HasStatic hs1=new HasStatic();
 5       hs1.x++;
 6       HasStatic hs2=new HasStatic();
 7       hs2.x++;
 8       hs1=new HasStatic();
 9       hs1.x++;
10       HasStatic.x--;
11       System.out.println("x="+x);
12   }      
13 }

這個題的考察點主要是在static關鍵字上面

static修飾的全局變量到底是在什么時候創建的?

這個題里面一共是有幾個不同對象的x屬性還是其他的什么呢?

下面附上一張我學JavaSE時候關於static關鍵字的PPT截圖

通過這個圖上面的知識點就很容易計算上面的題    無論哪個對象操作了x這個全局變量,x的值都是在改變的   x最后的取值應該為102

那么擴展起來這個知識點聯想一下   static修飾的方法  屬性  代碼塊都是什么時候創建的呢?   首先我們看java中類的生命周期

java中類的生命周期為裝載連接初始化使用卸載五個過程,如下圖所示:

1.加載
我們編寫一個java的源文件,經過編譯后生成一個后綴名為.class的文件,這結合四字節碼文件,
java虛擬機就識別這種文件,java的生命周期就是class文件從加載到消亡的過程。
關於加載,其實,就是將源文件的class文件找到類的信息將其加載到方法區中,
然后在堆區中實例化一個java.lang.Class對象,作為方法區中這個類的信息的入口。
但是這一功能是在JVM之外實現的,主要的原因是方便讓應用程序自己決定如何獲取這個類,
在不同的虛擬機實現的方式不一定相同,hotspot虛擬機是采用需要時在加載的方式,
也有其他是先預先加載的。
2.連接
一般會跟加載階段和初始化階段交叉進行,過程由三部分組成:驗證、准備和解析三步
(1)驗證:確定該類是否符合java語言的規范,有沒有屬性和行為的重復,繼承是否合理,總之,就是保證jvm能夠執行
(2)准備:主要做的就是為由static修飾的成員變量分配內存,並設置默認的初始值
默認初始值如下:

1.八種基本數據類型默認的初始值是0
2.引用類型默認的初始值是null
3.有static final修飾的會直接賦值,例如:static final int x=10;則默認就是10.
(3)解析:這一階段的任務就是把常量池中的符號引用轉換為直接引用,說白了就是jvm會將所有的類或接口名、字段名、方法名轉換為具體的內存地址。
3.初始化
這個階段就是將靜態變量(類變量)賦值的過程,即只有static修飾的才能被初始化,執行的順序就是:

父類靜態域或着靜態代碼塊,然后是子類靜態域或者子類靜態代碼塊
4.使用
在類的使用過程中依然存在三步:對象實例化、垃圾收集、對象終結

(1)對象實例化:就是執行類中構造函數的內容,如果該類存在父類JVM會通過顯示或者隱示的方式先執行父類的構造函數,在堆內存中為父類的實例變量開辟空間,並賦予默認的初始值,然后在根據構造函數的代碼內容將真正的值賦予實例變量本身,然后,引用變量獲取對象的首地址,通過操作對象來調用實例變量和方法
(2)垃圾收集:當對象不再被引用的時候,就會被虛擬機標上特別的垃圾記號,在堆中等待GC回收
(3)對象的終結:對象被GC回收后,對象就不再存在,對象的生命也就走到了盡頭
5.類卸載
即類的生命周期走到了最后一步,程序中不再有該類的引用,該類也就會被JVM執行垃圾回收,從此生命結束…

 1 package com.etc.test;
 2 class A{
 3     static int a;//類變量
 4     String name;
 5     int id;
 6     //靜態代碼塊
 7     static{
 8         a=10;
 9         System.out.println("這是父類的靜態代碼塊"+a);
10     }
11     //構造代碼塊
12     {
13         id=11;
14         System.out.println("這是父類的構造代碼塊id:"+id);
15     }
16     A(){
17         System.out.println("這是父類的無參構造函數");
18     }
19     A(String name){
20         System.out.println("這是父類的name"+name);
21     }
22 }
23 class B extends A{
24     String name;
25     static int b;
26     static{
27         b=12;
28         System.out.println("這是子類的靜態代碼塊"+b);
29     }
30      B(String name) {
31         super();
32         this.name = name;
33         System.out.println("這是子類的name:"+name);
34     }
35 }
36 public class Test666 {
37 public static void main(String[] args) {
38     B bb=new B("GG");
39 }
40 }

 

輸出的結果如下:

這是父類的靜態代碼塊10
這是子類的靜態代碼塊12
這是父類的構造代碼塊id:11
這是父類的無參構造函數
這是子類的name:GG

靜態代碼在類的初始化階段被初始化。

非靜態代碼則在類的使用階段(也就是實例化一個類的時候)才會被初始化。

  • 靜態變量

 

可以將靜態變量理解為類變量(與對象無關),而實例變量則屬於一個特定的對象。

靜態變量有兩種情況:

 

  • 靜態變量是基本數據類型,這種情況下在類的外部不必創建該類的實例就可以直接使用
  • 靜態變量是一個引用。這種情況比較特殊,主要問題是由於靜態變量是一個對象的引用,那么必須初始化這個對象之后才能將引用指向它。
  • 因此如果要把一個引用定義成static的,必須在定義的時候就對其對象進行初始化

 

 

 
1     public class TestForStaticObject{  
2     static testObject o = new testObject (); //定義一個靜態變量並實例化  
3     public static void main(String args[]){  
4     //在main中直接以“類名.靜態變量名.方法名”的形式使用testObject的方法  
5     }  
6     }  

 

 

 

  • 靜態方法

 

類變量不同,方法(靜態方法與實例方法)在內存中只有一份,無論該類有多少個實例,都共用一個方法

靜態方法與實例方法的不同主要有:

 

  • 靜態方法可以直接使用,而實例方法必須類實例化之后通過對象來調用
  • 外部調用靜態方法時,可以使用“類名.方法名”或者“對象名.方法名”的形式。
  • 實例方法只能使用這種方式對象名.方法名
  • 靜態方法只允許訪問靜態成員。而實例方法中可以訪問靜態成員和實例成員。
  • 靜態方法中不能使用this(因為this是與實例相關的)。

 

 

  • 靜態代碼塊

 

在java類中,可以將某一塊代碼聲明為靜態的。

 

 
1 static {  
2 //靜態代碼塊中的語句  
3 }

 

 

 

靜態代碼塊主要用於類的初始化它只執行一次,並且在同屬於一個類的main函數之前執行

靜態代碼塊的特點主要有:

 

  • 靜態代碼塊會在類被加載時自動執行
  • 靜態代碼塊只能定義在類里面不能定義在方法里面
  • 靜態代碼塊里的變量都是局部變量,只在塊內有效。
  • 一個類中可以定義多個靜態代碼塊,按順序執行。
  • 靜態代碼塊只能訪問類的靜態成員,而不允許訪問實例成員

 靜態代碼塊和靜態函數的區別

java 靜態代碼塊:

一般情況下,如果有些代碼必須在項目啟動前就執行的時候,需要使用靜態代碼塊,這種代碼是主動執行的,它只執行一次並且在同屬於一個類的main函數之前執行

靜態函數:

需要在項目啟動的時候就初始化,在不創建對象的情況下,其他程序來調用的時候,需要使用靜態方法,這種代碼是被動執行的.

 

注意:

(1)靜態變量是屬於整個類的變量而不是屬於某個對象的。注意不能把任何方法體內的變量聲明為靜態,例如:
fun()
{
static int i=0;//非法。
}

(2)一個類可以使用不包含在任何方法體中的靜態代碼塊,當類被載入時,靜態代碼塊被執行,且只被執行一次,靜態塊常用來執行類屬性的初始化。例如:
static
{
}

主程序類中的的靜態變量先於靜態代碼塊初始化,其后進入主函數類(程序入口處),其后根據靜態函數的調用情況,才能選擇性的初始化。

 

 

 

參考大神博客:https://www.cnblogs.com/lubocsu/p/5099558.html

                    https://www.cnblogs.com/ipetergo/p/6441310.html

 


免責聲明!

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



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