所謂物件,說得白話一點,可稱之為"東西"。這是個很抽象的名詞,我們若以它具體的特性來描述,會比較清楚:
屬於同一個Class的Object,會具有該Class所定義的以上三種特質。
除此之外,Class之間可以定義繼承(Inheritance)關係,子類別(Sub Class)繼承父類別(Super Class)的所有特性,子類別還可以定義其專屬的特性。
以Object-Oriented(物件導向) Language寫作程式時,寫作的主體是Class。Class定義了所有屬於該Class的Object的特性,這些特性可分類如下:
Java規定公共類別(public class)必須寫在該公共類別名稱的.java檔案內, 例如public class Example就必須寫在Example.java這個檔案內。Example.java裡面也可以定義其他的類別,但是只有class Example能夠宣告為public,其他Example.java裡的class都不能宣告為public。當Java Virtual Machine啟動時,它會去找命令列上所指定的class裡的public static void main(String[] argv)方法,當做是程式的進入點。這有點像是C語言的main, 不同處在於每個java class都可以定義自己的public static void main(String[] argv)。
java Example
啟動上述的JVM時, JVM會去執行class Example裡的public static void main(String[] argv)。以下範例Example.java說明如何定義Java的class。
class Vehicle { private int speed; // Object Variable private String direction; // Object Variable, direction is a reference to String Object private static int numVehicle = 0; // Class Variable public Vehicle() { // Constructor, called when new a Object this(0,"north"); // call another constructor to do initialization } public Vehicle(int s, String dir) { // Another Constructor. Use overloading to define two constructors float speed; // define a local variable speed = s; // the speed here refers to the above local variable this.speed = s; // If we want to set object variable, use this.speed to refer object variable speed direction = dir; // dir is a reference to object, not the object itself numVehicle++; // increase the Vehicle number } protected void finalize() { // Destructor, called when the object is garbage collected by JVM System.out.println("finalize has been called"); numVehicle--; } void setSpeed(int newSpeed) { // Object Method this.speed = newSpeed; } void setDir(String dir) { // Object Method this.direction = dir; } int getSpeed() { // Object Method return speed; } String getDir() { // Object Method return direction; } public static int totalVehicle() { // Class Method return numVehicle; } } public class Example { public static void main(String[] argv) { Vehicle v1 = new Vehicle(50, "west"); // new 敘述用來產生物件. 物件產生時需要呼叫Constructor來初始化物件 Vehicle v2; v1.setSpeed(30); v1.setDir("north"); System.out.println("V1: speed is "+v1.getSpeed()+", direction is "+v1.getDir()+".\n"); v2 = new Vehicle(40, "south"); System.out.println("There are "+Vehicle.totalVehicle()+" Vehicles in the world.\n"); v1 = v2; // let reference v1 point to where v2 is pointing System.out.println("V1: speed is "+v1.getSpeed()+", direction is "+v1.getDir()+".\n"); System.gc(); // force system to do garbage collection, the object previously pointed by v1 shall be destroyed System.out.println("There are "+Vehicle.totalVehicle()+" Vehicles in the world.\n"); } }
上述例子裡所用到的關鍵字或類別名稱說明如下:
Object Method的名稱如果和Class的名稱相同, 則表示該Method為Constructor。Constructor不能宣告傳回值。
要附帶說明的是, Java以new指令來產生物件, 但不像C++有提供相對應的delete指令來消滅物件。Java採用Garbage Collection的觀念,當系統於閒置期間自動呼叫或由使用者強制呼叫System.gc()時,沒有被任何reference指到的Object就會被回收。
Class裡面一定要定義一個以上的Constructor, 但為了方便起見,如果Compiler發現某Class沒有定義Constructor,則Compiler會幫我們產生一個不做任何事的Constructor:
public class A { }
就相當於
public class A { public A() {} }
同一個class裡的Method名稱可以重複使用,只要可以由Method的參數個數和型態來區分就可以了。這種觀念稱為overloading。
不只一般的method可以overloading, constructor也可以overloading。
public class Overloading { int data; public Overloading() { this(0); // call constructor Overloading(int) } public Overloading(int data) { this.data = data; } public void print() { this.print(0); // call method print(int) } public void print(int msg) { } public void print(float msg) { } public void print(int msg, String others) { } }
上面的例子裡說明constructor也可以overloading。要特別注意的是,傳回值並不能用來分辨要呼叫哪個method,因此若再加上public int print()的宣告,就會造成編譯錯誤了。
Class variable是在該類別載入JVM時進行初始化的, 因此寫作上經常在class variable的宣告後面加上初始化的動作。對Object Variable來說, 是在產生Object時進行初始化的, 但初始化的步驟可以寫在變數宣告後, 也可以寫在constructor內, 因此必須對其執行順序有所了解。步驟如下:
因此在如下的範例內
public class InitSequence { int data = 2; public InitSequence(int data) { this.data = data; } public static void main(String[] argv) { InitSequence s = new InitSequence(3); System.out.println(s.data); } }data的變化如下
因此最後執行的結果會在螢幕上印出數字3。
Java語言還可以定義static block:
public class StaticBlock { static { // this is a static block data = (int)(Math.random()*100); } static int data; public static void main(String[] argv) { System.out.println(data); } }
static block內的程式碼, 是在該class載入JVM之後, 進行class variable初始化之前的時間內執行。一般比較會使用static block的場合, 是該class用到一些非Java的程式庫, 需要透過System.loadLibrary(String libName)方法把外界的程式碼載入時。這樣寫的好處是只有當該class第一次被使用到時, 才會下載相關軟體, 以節省記憶體空間, 避免重複下載, 並可以把實作的細節和外界隔離開來。對沒有這種機制的C語言來說, 很可能就必須在主程式內寫上一堆很難懂的啟動程式碼。
class ClassNeedToLoadLibrary { static { System.loadLibrary("mylib"); } } public class Main { public static void main(String[] argv) { } }
final關鍵字用在變數宣告時,表示該變數的值只能在宣告時給定,然後就不能再更改了。
public class Main { public static final double PI = 3.14159; public final int x = 10; public static void main(String[] argv) { final int local = 10; Main m = new Main(); PI = 100; // Compile Error, final variable can only be set at initialization m.x = 10; // Compile Error local = 100; // Compile Error } }