2012年12月16日 星期日

JVM記憶體圖-類別的載入與執行

寫好的程式編譯成class之後
透過class loader啟動放到記憶體
class 類別檔就好比是一個設計藍圖
藍圖內有static的method或者field都配置在Method area內
可以整個程式使用
物件(Object)則配置在Heap區
JVM stack則是放變數的起始位置

檔案的讀取

寫一個程式,把文件檔的內容讀取出來

import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;

class Print{
    public static void main(String[] args) throws IOException{
      
        FileReader f =new FileReader("d:\\MyWriter.txt");
        FileReader f1 =new FileReader("d:\\MyWriter.txt");
        BufferedReader b = new BufferedReader(f);
        BufferedReader b1 = new BufferedReader(f1);

        String s;
        int i=0;
        int j=0;
        while((s = b.readLine())!=null){
            ++i;
        }
        b.close();
//用變數i來統計總共幾筆資料

        String[][] t =new String[10][];
        while((s = b1.readLine())!=null){
            t[j]=s.split(":");
            ++j;
        }
        b1.close();
//逐行讀取,切割分開後用陣列方式存放

        for(int k=0;k<i;k++){
            System.out.println(t[k][0]+":"+t[k][1]);
        }
    }
}

執行結果:
jack:10
mary:20
tom:30
mark:40


透過把檔案丟到陣列再進行讀取,但實際上不用用到這麼麻煩

import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;

class Print{
    public static void main(String[] args) throws IOException{
      
        FileReader f =new FileReader("d:\\MyWriter.txt");
        BufferedReader b = new BufferedReader(f);
        String s;

        while((s = b.readLine())!=null){
            System.out.println(s);
        }
        b.close();
//這邊改為判斷檔案非空值就列印,如此也可以做到印出整個文件
    }
}

執行結果:
jack:10
mary:20
tom:30
mark:40



檔案的寫入

寫一個程式,可以儲存人名和成績

import java.util.Scanner;
import java.io.FileWriter;
import java.io.IOException;

class Write{
    public static void main(String[] args)throws IOException{
   
        FileWriter f = new FileWriter("d:\\MyWriter.txt", true);
//透過FileWriter來指定位置跟存入一個檔案
   
        Scanner s = new Scanner(System.in);

        System.out.println("請輸入性名");
        String name = s.nextLine();
        System.out.println("請輸入分數");
        int sc = s.nextInt();
       
        f.write(name+":"+sc+"\n");
        f.close();
    }
}

執行後生成一個檔案
檔案內容:
jack:10
mary:20
tom:30
mark:40


多載(Overload)

多載的方式可以用在類別和建構式內,讓程式依照輸入參數的不同去選擇適當的處理方式執行
例如:買蘋果

class apple{
    int app1;
    int app2;
    int sum;
   
    apple(){
        app1 = 0;
        app2 = 0;
    }
//沒有給參數的建構式

    apple(int a, int b){
        app1 = a;
        app2 = b;
    }
//有給參數的建構式

    public void show(){
        sum=app1*15+app2*12;
        System.out.println("共買富士蘋果"+app1+"顆,梨山蘋果"+app2+"顆");
        System.out.println("一共是"+sum+"元");       
    }
   
}

public class Buy{
    public static void main(String[] args){
        apple x = new apple();
        x.show();
       
        apple y = new apple(10,20);
        y.show();
    }
}

執行結果:
共買富士蘋果0顆,梨山蘋果0顆
一共是0元
共買富士蘋果10顆,梨山蘋果20顆
一共是390元


可以觀察到程式自動根據有無參數去呼叫適當的建構式使用了


建構式(Constructor)

建構式的用法,是在建立物件的起始值
例如:寫一個程式做簡單計算第幾次執行

class X{
    int num;
   
    public X(){
        num = 0;
        System.out.println("開始執行");
    }

//Constructor做為初始值
//一定使用class的名稱做為Constructor的名稱
//建構式不能有傳回值
    public void show(){
        num++;
        System.out.println("第"+num+"次執行");
    }
}

public class Constructor{
    public static void main(String[] args){
        X a=new X();
//建立一個新的物件a
        a.show();
        a.show();
    }
}

執行結果:
開始執行
第1次執行
第2次執行


但若是沒有定義Constructor,在java程式會自動準備一個沒有參數的建構式來使用
像是改成:
    public X(){

            }

也是可以被執行

結果如下:
第1次執行
第2次執行

方法的類型(method)

method分為兩種類型

instance method
class test{
    void ln(){
        System.out.println("Hello");
    }
}

public class Imethod{
    public static void main(String[] args){
        test a=new test();
        a.ln();

//要先建立新物件後才能使用
    }
}
class method
class test{
    static void ln(){
        System.out.println("Hello");
    }
}

public class Cmethod{
    public static void main(String[] args){
        test.ln();
//不需要建立物件就可以使用
    }
}

兩者差別在於,class method有用static宣告
instance method再使用前要先建立物件,class method則不用,可以立即被使用
並且class method只能使用class field

變數的類型(Field)

基本上分三類
Class Field (Static)
class vclass {
  static int a=100;
// class field
  static void va(){
     System.out.println(++a);
  }
}

不在method內,前面有static宣告,置於method area
classfield可以被整個運作中的java程式使用,所以又稱為全域變數
再使用上也可以不用給初值

Instance Field (Heap)
public class vinstance {
    int a=100; 
}
 
沒有寫在method內,也沒有static宣告,再JVM記憶體內配置在heap
有效的範圍只在整個class內

Local Field (Stack)  
class vlocal {
  void z(){
     int  b; 
// b 沒有設定初值, 這行單獨編譯是會成功
     System.out.println(b); 
// 編譯時出現 vlocal.java:4: variable b might not have been initialized
  }
}
 
在method內宣告的變數,再JVM記憶體內配置在stack 
在使用上,一定要有初值
而且不能有static宣告