關於Java中的static關鍵字


Java中的 static 關鍵字,確實是一個關鍵的字(key word),今天就來總結一下它的用法,說說為什么關鍵。

Java中的 static 關鍵字主要是用來做內存管理的。理解了這句話才能夠比較深入地理解static。

static 可以修飾:

  1. 變量(所謂 class variable)
  2. 方法(所謂 class method)
  3. 代碼塊(所謂 block)
  4. 內部類(所謂 nested class)

凡是被 static 修飾的這四種元素,都屬於class的元素,即類的,而不是類的實例的。

 

1) 靜態變量

在聲明變量的時候加上 static ,該變量即是靜態變量。

  • 什么時候該用 static 來修飾變量呢?該變量被該類的所有實例所共享。
  • 靜態變量在類被加載的時候初始化,且僅分配一次內存。

這樣做的好處就是內存利用率高,看下下面兩個demo:

1 // Understanding problem without static variable
2 class Student{  
3      int stuNo;  
4      String name;  
5      String college="ITS";  
6 }  

假設這個"niubility my brother" 的學校有500000000個學生,那么當每一個學生被創建的時候,都會初始化學號、姓名、學校,每個學生都有自己的學號和姓名,這樣做沒問題;但是每個學生的college字段都相同,如果每次都聲明一遍的話,是比較耗內存的。這里的college變量其實是被該類的所有實例所共享的,因此可以將它聲明為 static 的。

 1 //Program of static variable  
 2 class Student8{  
 3    int rollno;  
 4    String name;  
 5    static String college ="ITS";  
 6      
 7    Student8(int r,String n){  
 8    rollno = r;  
 9    name = n;  
10    }  
11  void display (){System.out.println(rollno+" "+name+" "+college);}  
12   
13  public static void main(String args[]){  
14  Student8 s1 = new Student8(111,"Karan");  
15  Student8 s2 = new Student8(222,"Aryan");  
16    
17  s1.display();  
18  s2.display();  
19  }  
20 }  
Output:111 Karan ITS
       222 Aryan ITS

看下實際內存分配情況:

靜態變量分配在了方法區,堆中該類的所有實例共享方法區中的college。

再看一下下面這個栗子:Counter 類中聲明了一個count變量,在構造函數中對其進行++操作,因為實例變量在對象被創建的時候分配內存,所有每一個對象都有一份自己的count副本,每個對象對各自count的++操作不會反應到其他對象上。

 1 class Counter{  
 2 int count=0;//will get memory when instance is created  
 3   
 4 Counter(){  
 5 count++;  
 6 System.out.println(count);  
 7 }  
 8   
 9 public static void main(String args[]){  
10   
11 Counter c1=new Counter();  
12 Counter c2=new Counter();  
13 Counter c3=new Counter();  
14   
15  }  
16 }  
Output:1
       1
       1

因為靜態變量僅僅在類加載的時候分配一次內存,所以如果將count修飾為static,那么該類的所有對象將會共享該變量,每一個對象對count的操作都會反應到其他對象上。

 1 class Counter2{  
 2 static int count=0;//will get memory only once and retain its value  
 3   
 4 Counter2(){  
 5 count++;  
 6 System.out.println(count);  
 7 }  
 8   
 9 public static void main(String args[]){  
10   
11 Counter2 c1=new Counter2();  
12 Counter2 c2=new Counter2();  
13 Counter2 c3=new Counter2();  
14   
15  }  
16 }
Output:1
       2
       3

 

2)靜態方法

在聲明方法的時候加上 static 關鍵字,即靜態方法:

  • 靜態方法屬於類而不是對象。
  • 靜態方法可以直接通過類名調用,而不需要創建類的對象。
  • 靜態方法可以修改靜態變量,而非靜態方法不可以。

一個靜態方法的栗子:

 1 //Program of changing the common property of all objects(static field).  
 2 class Student9{  
 3      int rollno;  
 4      String name;  
 5      static String college = "ITS";  
 6        
 7      static void change(){  
 8      college = "BBDIT";  
 9      }  
10   
11      Student9(int r, String n){  
12      rollno = r;  
13      name = n;  
14      }  
15   
16      void display (){System.out.println(rollno+" "+name+" "+college);}  
17   
18     public static void main(String args[]){  
19     Student9.change();  
20   
21     Student9 s1 = new Student9 (111,"Karan");  
22     Student9 s2 = new Student9 (222,"Aryan");  
23     Student9 s3 = new Student9 (333,"Sonoo");  
24   
25     s1.display();  
26     s2.display();  
27     s3.display();  
28     }  
29 }  
Output:111 Karan BBDIT
       222 Aryan BBDIT
       333 Sonoo BBDIT

靜態方法的第二顆栗子:

 1 //Program to get cube of a given number by static method  
 2 class Calculate{  
 3   static int cube(int x){  
 4   return x*x*x;  
 5   }  
 6   
 7   public static void main(String args[]){  
 8   int result=Calculate.cube(5);  
 9   System.out.println(result);  
10   }  
11 }  

靜態方法的兩個注意點:

  1. 靜態方法不能操作非靜態變量,也不能調用非靜態方法。(這個可以這樣理解:靜態方法屬於類,直接通過類名就可以調用,而此時可能沒有任何實例,更談不上操作實例變量和調用實例方法了。)
  2. 靜態方法中不能使用 thissuper 關鍵字。(道理同上)
1 class A{  
2  int a=40;//non static  
3    
4  public static void main(String args[]){  
5   System.out.println(a);  
6  }  
7 }   
Output:Compile Time Error

Q)為什么Java的main方法是static的?

Ans)為了使得在調用main方法之前不需要創建任何實例對象。

 

3)靜態代碼塊

為什么要有這個東西?干嘛用呢?

  • 用來初始化靜態變量。
  • 在類加載時,在執行main方法之前執行相關操作。

栗子:

1 class A2{  
2   static{System.out.println("static block is invoked");}  
3   public static void main(String args[]){  
4    System.out.println("Hello main");  
5   }  
6 }  
Output:static block is invoked
       Hello main

Q)沒有main方法的程序可以執行嗎?

Ans)可以,在JDK1.7之前執行如下代碼是可以的:

1 class A3{  
2   static{  
3   System.out.println("static block is invoked");  
4   System.exit(0);  
5   }  
6 }  
Output:static block is invoked (if not JDK7)

但是在JDK1.7會報如下錯誤:

Output:Error: Main method not found in class A3, please define the main method as:
public static void main(String[] args)

 

4)靜態內部類

被static修飾的類,並且處於某個類的內部。

  • 它可以訪問外部類的靜態成員,包括private成員。
  • 它不能訪問外部類的非靜態成員。(原因前面說過)

那么為什么要有靜態內部類呢?看下面的栗子:

 1 class TestOuter1{  
 2   static int data=30;  
 3   static class Inner{  
 4    void msg(){System.out.println("data is "+data);}  
 5   }  
 6   public static void main(String args[]){  
 7   TestOuter1.Inner obj=new TestOuter1.Inner();  
 8   obj.msg();  
 9   }  
10 }  
Output:data is 30

main方法中創建了一個靜態內部類的實例,並且調用了其msg() 方法。但是這里並沒有創建外部類的實例,因為這里的Inner類是static的,並且可以訪問外圍類的static成員。如果把Inner之前的static去掉,那么這里要這樣寫:

TestStaticInnerClass.Inner obj=new TestStaticInnerClass().new Inner();

需要先創建外一個部類實例,然后才能創建內部類實例。靜態內部類不僅高效利用內存,而且使得代碼簡潔。下面是static 內部類編譯后的樣子:

 1 // Internal class generated by the compiler
 2 import java.io.PrintStream;  
 3 static class TestOuter1$Inner  
 4 {  
 5 TestOuter1$Inner(){}  
 6 void msg(){  
 7 System.out.println((new StringBuilder()).append("data is ")  
 8 .append(TestOuter1.data).toString());  
 9 }    
10 } 

上例中,如果msg() 方法也是靜態的,那么內部類的實例也不需要創建了:

1 class TestOuter2{  
2   static int data=30;  
3   static class Inner{  
4    static void msg(){System.out.println("data is "+data);}  
5   }  
6   public static void main(String args[]){  
7   TestOuter2.Inner.msg();//no need to create the instance of static nested class  
8   }  
9 }  
Output:data is 30

 

以上是關於Java 中 static 關鍵字的理解,參考了:http://www.javatpoint.com/

 


免責聲明!

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



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