1. 程式人生 > >Java中記憶體,成員變數,區域性變數

Java中記憶體,成員變數,區域性變數

一 java記憶體分配

這裡只是在網上找的一些資料;
Java 中的資料型別分為
1. 基本型別(原始資料型別) byte short int long float double char boolean
基本型別的變數持有原始值。
2. 符合資料型別(引用型別),引用型別持有引用值(即對某個物件的引用,而非物件本身)。

一般Java在記憶體分配時會涉及到以下區域:
1. 暫存器:我們在程式中無法控制
2. 棧:存放基本型別的資料和物件的引用但物件本身不存放在棧中,而是存放在堆中
3. 堆:存放用new產生的資料
4. 靜態域:存放在物件中用static定義的靜態成員
5. 常量池:存放常量
6. 非RAM儲存:硬碟等永久儲存空間
其中主要是堆,棧的儲存。

堆,棧

  1. 函式中定義的一些基本型別的資料變數物件的引用變數都在函式的棧記憶體中分配。
    棧的優勢是存取速度比堆要快,僅次於直接位於CPU 的暫存器,而且資料可以共享
    存在棧中的資料大小與生存週期必須是確定的。因此裡面的變數通常是區域性變數、函式引數等。
    當在一段程式碼塊定義一個變數時(區域性變數),Java就在棧中 為這個變數分配記憶體空間,當該變數退出該作用域後,Java會自動釋放掉為該變數所分配的記憶體空間,該記憶體空間可以立即被另作他用。

  2. 堆記憶體用來存放由new建立的物件和陣列。 在堆中分配的記憶體,由Java虛擬機器的自動垃圾回收器來管理。

在堆中產生了一個數組或物件後,還可以 在棧中定義一個特殊的變數,讓棧中這個變數的取值等於陣列或物件在堆記憶體中的首地址,棧中的這個變數就成了陣列或物件的引用變數。


引用變數是普通的變數,定義時在棧中分配,引用變數在程式執行到其作用域之外後被釋放。而陣列和物件本身在堆中分配,即使程式 執行到使用 new 產生陣列或者物件的語句所在的程式碼塊之外,陣列和物件本身佔據的記憶體不會被釋放,陣列和物件在沒有引用變數指向它的時候,才變為垃圾,不能在被使用,但仍 然佔據記憶體空間不放,在隨後的一個不確定的時間被垃圾回收器收走(釋放掉)。

棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的儲存區。裡面的變數通常是區域性變數、函式引數等。

堆,就是那些由new分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用程式去控制,一般一個new就要對應一個delete。如果程式設計師沒有釋放掉,那麼在程式結束後,作業系統會自動回收。

二 成員變數,區域性變數

class A 
{ 
int a;//成員變數 
public static void main(String[] args) 
{ 
//類變數
static int c;
int b;//區域性變數 
} 
}

成員變數:作為類的成員而存在,直接存在於類中。

類變數:static 修飾,靜態變數儲存在方法區。

區域性變數:方法內部,塊內部都是區域性,執行指令退出那個區域性,區域性變數自動清除。

1.成員變數可以被public,protect,private,static等修飾符修飾,而區域性變數不能被控制修飾符及static修飾;兩者都可以定義成final型

2.成員變數儲存在堆,區域性變數儲存在棧

3.存在時間不同

4.成員變數有預設值,(被final修飾且沒有static的必須顯式賦值),區域性變數不會自動賦值,區域性變數在使用前必須被程式設計師主動的初始化,然後才能使用。

看下面對比成員變數區域性變數:

public class Variable { 
int i; 
void test() { 
   int j=8; 
   if(j==i) 
    System.out.println("相等"); 
   else 
    System.out.println("不相等"); 
} 
public static void main(String[] args) { 
   Variable v=new Variable(); 
   v.test(); 
} 
}

程式二:

public class Variable { 
   void test() { 
   int i; 
   int j=8;
   //這裡 i 被使用了,但是還沒有賦值,所以報錯 
   if(j==i) 
    System.out.println("相等"); 
   else 
    System.out.println("不相等"); 
} 
public static void main(String[] args) 
{ 
   Variable v=new Variable(); 
   v.test(); 
} 
}

第一個程式很正常,編譯時不會出錯。第二個程式編譯時會錯誤,因為區域性變數沒有初始化。成員變數有預設值,(被final修飾且沒有static的必須顯式賦值),區域性變數不會自動賦值

public static int transeInt(String s){

        //digit不會報錯,result 會報錯
        int digit;
        int result;

        if(s.length()==0||s==null)
            System.out.println("錯誤字串");

        for(int i=0;i<s.length();i++){
            //這裡digit被顯示的賦值了(所以不一定是建立之後就被賦值)
            digit = s.charAt(i)-'0';
            //result*10   還未被賦值就被使用了,所以報錯
            result = result*10+digit;
        }

        return result;
    }