深化Java基礎之——對象與內存控制

Java是一門面嚮對象語言,作爲Java程序員,對於對象的使用一定不陌生,本文就總結一下創建對象時發生的一些事情。

1.實例變量和類變量

  看到這個標題大家一定想到的是static關鍵字,沒錯,被static關鍵字修飾的變量,方法,內部類,初始化塊,這些都屬於類,而不具體屬於某個實例對象,可以直接通過類名來調用。關於static可能造成的內存泄漏,在後面的JVM文章裏總結。這裏我就簡單通過兩個程序總結一下類成員和實例成員的區別,以及創建一個對象後初始化的順序。

  實例變量屬於對象,每實例化一個對象,就會爲其在內存中分配一塊空間。類變量只會在第一次使用該類時爲其分配一份內存空間,無論創建了多少個該類的對象,static變量永遠只有一份內存空間。一個類在使用之前,就會在JVM中對該類進行加載-連接-初始化,在連接時就會給類變量分配相應的內存空間。

 1 public class B extends A {
 2     public int m = method3();
 3     public static int n = method4();
 4     public int t = 0;
 5     public B(){
 6         System.out.println(4);
 7     }
 8     public int method3(){
 9         System.out.println(5);
10         return 5;
11     }
12     public static int method4(){
13         System.out.println(6);
14         return 6;
15     }
16     public static void main(String[] args) {
17         System.out.println(7);
18         A a = new B();
19     }
20 }
21 
22 class A {
23     public int i = method();
24     public static int j = method2();
25     public int k = 0;
26     public A(){
27         System.out.println(1);
28     }
29     public int method(){
30         System.out.println(2);
31         return 2;
32     }
33     public static int method2(){
34         System.out.println(3);
35         return 3;
36     }
37 }

A、7 3 2 1 6 4 5        B、3 6 7 2 1 5 4         C、7 3 6 2 1 5 4        D、3 2 1 7 6 5 4

看看上述代碼的輸出結果應該選哪個呢?

讓我們一步一步來分析:A類是B類的父類,在執行程序時,A類先被加載,並且爲其類變量分配內存空間,所以先爲24行的 j 分配內存,初始化爲methond2()方法的返回值,這裏的method2()也必須被static修飾,才能被調用,所以先輸出3;同理,接下來爲B類的類變量分配空間,輸出6;然後執行16行main()方法,輸出7;實例化B類的對象,先執行其父類(A)的非靜態初始化(代碼23行),method()方法輸出2;然後是父類(A)的構造方法,輸出1;然後是B類同理,依次輸出5和4,程序結束,所以最終答案是B。

這個代碼大家可以複製下來進行單步debug來細細體會。

 

再來看一個有趣的代碼,細細品味。

 1 public class PriceTest {
 2 
 3     public static void main(String[] args) {
 4         System.out.println(Price.instance.currentPrice);
 5         //顯示的創建Price對象
 6         Price p = new Price(2.8);
 7         System.out.println(p.currentPrice);
 8     }
 9 }
10 
11 class Price{
12     //類變量
13     final static Price instance = new Price(2.8);
14     //類變量
15     static double initPrice = 20;
16     //實例變量
17     double currentPrice;
18     public Price(double discount){
19         currentPrice = initPrice - discount;
20     }
21 }

上述代碼輸出了兩次currentPrice,而且都是通過new Price(2.8)來創建實例,看起來應該是輸出兩次17.2,親自運行一下這個代碼,會發現結果卻是-2.8和17.2。

下面從內存層面上來看看到底發生了什麼,當然,首先還是先爲Price類的類變量分配內存空間,這個時候兩個static變量instance和initPrice值爲null和0.0,接下來按這個順序爲它們初始化,instance的值爲new Price(2.8),立即執行18行,所以這時的currentPrice是等於0.0 - 2.8的,instance初始化完畢,然後是initPrice初始化爲20。所以第4行輸出-2.8,執行第6行時,類變量initPrice已經爲20,所以第7行輸出17.2。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章