close
1 對象的生命周期
在這一小節中你可以學到怎樣創建和使用任何類型的對象,還討論了當對象不再需要的時候系統怎樣清除對象的。
典型的JAVA程序創建對象,對象之間的交互是通過發送消息來實現的。通過這些對象的交互,JAVA程序可以執行一個GUI、運行一個動畫或者通過網絡發送和接收信息。一旦對象已經完成了任務,它就被作為無用信息被回收,它的資源可以由其它對象回收利用。
以下是一個小的例子程CreateObjectDemo,它創建三個對象:一個是Point對象和兩個Rectange對象,你需要這三個源程序才可以編譯這個程序:
public class CreateObjectDemo {
public static void main(String[] args) {
//創建一個Point對象和兩個Rectangle對象
Point origin_one = new Point(23, 94);
Rectangle rect_one = new Rectangle(origin_one, 100, 200);
Rectangle rect_two = new Rectangle(50, 100);
// 顯示rect_one的寬、高以及面積
System.out.println("Width of rect_one: " + rect_one.width);
System.out.println("Height of rect_one: " + rect_one.height);
System.out.println("Area of rect_one: " + rect_one.area());
// 設置rect_two的位置
rect_two.origin = origin_one;
// 顯示rect_two的位置
System.out.println("X Position of rect_two: " + rect_two.origin.x);
System.out.println("Y Position of rect_two: " + rect_two.origin.y);
// 移動rect_two並且顯示它的新位置
rect_two.move(40, 72);
System.out.println("X Position of rect_two: " + rect_two.origin.x);
System.out.println("Y Position of rect_two: " + rect_two.origin.y);
}
}
一旦創建了對象,程序就可以操作對象並將它們有關的一些信息顯示出來,以下是這個程序的輸出結果:
Width of rect_one: 100
Height of rect_one: 200
Area of rect_one: 20000
X Position of rect_two: 23
Y Position of rect_two: 94
X Position of rect_two: 40
Y Position of rect_two: 72
這一節使用這個例子來在程序中描述對象的生命周期。從這你可以學到怎樣編寫代碼來創建、使用對象以及系統怎樣將它從內存中清除的。
2 對象的生命周期
下面主要分成幾部分來討論:
1. 創建對象
使用對象
清除沒有使用的對象
2.1 創建對象
眾所周知,可以從類來創建對象。下面的幾條語句都是用來創建對象的,它們都是來自上面程序CreateObjectDemo程序:
Point origin_one = new Point(23, 94);
Rectangle rect_one = new Rectangle(origin_one, 100, 200);
Rectangle rect_two = new Rectangle(50, 100);
上面第一條語句從Point類創建了一個對象,而第二條和第三條語句是從Rectangle類眾創建了對象。但是每條語句都有三部分組成:
1. 聲明:Point origin_one、Rectangle rect_one以及Rectangle rect_two都是變量的聲明,它們的格式是類型後加變量名。當你創建一個對象的時候,你不必聲明一個變量來引用它。然而,變量生命經常出現在創建對象代碼的相同行上。
實例化:new是JAVA運算符,它可以創建新的對象並且為對象分配了內存空間。
初始化:new運算符後跟著一個構造函數的調用。比如Point(23,94)就是一個Point類的構造函數的調用。這個構造函數初始化了這個新對象。
下頁也對這幾個部分逐個介紹:
2.1.1 聲明一個變量來引用對象
從前面的教程,你應該知道了如何聲明一個變量了,你可以這樣來編寫:
type name
其中type是數據類型,而name是變量名。
除了原始類型(比如int和boolean),JAVA平臺還直接提供了類和接口也是數據類型。這樣為了聲明一個變量來引用對象,你可以使用類或者接口的名字作為變量的類型。下面的例程使用了Point和Rectangle類作為類型來聲明變量:
Point origin_one = new Point(23, 94);
Rectangle rect_one = new Rectangle(origin_one, 100, 200);
Rectangle rect_two = new Rectangle(50, 100);
聲明沒有創建新對象。Point origin_one代碼沒有一個新的Point對象,它只是聲明一個變量orgin_one,它將用來引用Point對象。這個引用暫時是空的直到被賦值了。一個空的引用就是一個NULL引用。
2.1.2 實例化對象
為了創建一個對象你必須用new來實例化它。New運算符是通過為新對象分配內存來實例化一個類的。這個new運算符需要一個後綴參數,即構造函數的一個調用。構造函數的名字提供了要初始化類的名字。構造函數初始化了新的對象。
New運算符號返回一個引用給它創建的對象的。通常,這個引用被賦值為適當類型的變量。
2.1.3 初始化對象
以下是Point類的代碼:
public class Point {
public int x = 0;
public int y = 0;
//一個構造函數
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
這個類包含了一個構造函數。你可以識別這個構造函數因為它跟類的名字是相同名字的,它沒有任何的返回類型。這個在Point類中的構造函數有兩個整型參數,它是由代碼(int x, int y)來定義的。下面的整數23和94就是這個參數的數值:
Point origin_one = new Point(23, 94);
2.1.3 初始化對象
下面是Rectangle類的代碼,它包含了四個構造函數:
public class Rectangle {
public int width = 0;
public int height = 0;
public Point origin;
//四個構造函數
public Rectangle() {
origin = new Point(0, 0);
}
public Rectangle(Point p) {
origin = p;
}
public Rectangle(int w, int h) {
this(new Point(0, 0), w, h);
}
public Rectangle(Point p, int w, int h) {
origin = p;
width = w;
height = h;
}
//用於移動rectangle的方法
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
//用於計算矩形面積的方法
public int area() {
return width * height;
}
}
每一個構造函數可以讓你為矩形的各個方法提供初始數值,你可以設置矩形的原點、寬度和高度。如果一個類中有多個構造函數,它們的名字都是相同的只是它們有不同類型的參數或者不同數目的參數。JAVA平臺可以根據參數的不同數目和類型類來區分構造函數。當JAVA平臺遇到的代碼的時候,它就調用在Rectangle類中的構造函數,這個函數需要一個Point參數以及兩個整型參數:
Rectangle rect_one = new Rectangle(origin_one, 100, 200);
這個調用初始化了矩形的原點(orgin_one)。代碼也設置了矩形的寬度(100)和高度(200)。
2.1.3 初始化對象
多個引用可以引用相同的對象。下面的代碼行調用了需要兩個整型參數的構造函數,它為寬度和高度提供了初始化數值。如果你仔細看看這個代碼,你會發現它創建一個Point對象,它的x和y數值被初始化為0。
下面的Rectangle構造函數沒有任何參數:
Rectangle rect = new Rectangle();
如果一個類沒有顯性聲明任何構造函數,JAVA平臺自動提供一個沒有參數的構造函數,這是一個缺省的構造函數,它沒有完成任何事情。這樣,所有的類就至少有一個構造函數。
2.2 使用對象
一旦你創建了一個對象,你可能想使用它來做一些事情。你可能從它得到一些信息,或者想改變它的狀態或者讓它來完成一些動作。對象允許你做以下兩件事情:
1. 操作或者檢查它的變量。
調用它的方法。
2.2.1 引用對象的變量
下面是引用對象變量的基本形式,它是使用了有條件的名字即長名字:
objectReference.variableName
當實例變量處在作用域內的時候,你可以為實例變量使用一個簡單的名字,也就是說,在對象類的代碼中。處在對象類外面的代碼必須使用有條件的名字。比如,在CreateObjectDemo類中的代碼處在類Rectangle類代碼的外面。所以為了引用Rectangle對象rect_one的origin、width和height變量,CreateObjectDemo必須相應使用rect_one.origin、rect_one.width和rect_one.height。這個程序使用了rect_one的width和height:
System.out.println("Width of rect_one: " + rect_one.width);
System.out.println("Height of rect_one: " + rect_one.height);
如果直接使用在CreateObjectDemo類中的變量width和height,那就將產生一個編譯錯誤。在後面,程序還將使用類似的代碼來顯示關於rect_two的信息。相同類型的對象將有相同實例變量的副本。這樣,每一個Rectangle對象就都有變量origin、width和height了。當你通過對象引用來訪問實例變量的時候,你就引用了特定對象的變量。在CreateObjectDemo程序有兩個對象rect_one和rect_two,它們有不同的origin、width和height變量:
對象的長文件名的第一部分是對象引用,它必須是一個對象的引用。這裏你可以使用引用變量的名字,或者你可以使用任何的表達式來返回一個對象引用。重新調用這個new運算符可以返回一個對象的引用。這樣你可以使用從new返回的數值來訪問一個新的對象變量:
int height = new Rectangle().height;
這個語句創建了一個新的Rectangle對象並且得到它的height(高度)。從本質上講,這條語句計算了Rectangle缺省的高度。這裏註意,在這條語句被執行後,程序不再有創建了的Rectangle的引用,因為程序不再在變量中存儲這個引用。對象就被取消引用,而它的資源可以JAVA平臺重新使用。
2.2.2 關於變量訪問
利用其它對象和類對對象變量直接的操作是不允許的,因為有可能為變量設置的數值沒有任何的意義。比如,我們使用前面教程中的Rectangle類,你可以創建一個矩形,它的width和height都是負的,但是它是沒有意義的。
較好的做法是:不采用直接對變量進行操作,類提供一些方法,其它的對象可以通過這些方法來檢查或者改變變量。這些方法要確保變量的數值是有意義的。這樣,Rectangle類將提供setWidth、setHeight、getWidth以及getHeight方法來設置或者獲得寬度和高度。這些用於設置變量的方法將在調用者試圖將width和height設置為負數的時候匯報一個錯誤。使用方法而不使用直接變量訪問的好處還有:類可以改變變量的類型和名字來存儲width和height而沒有影響它的客戶程序。
但是,在實際情況下,有時允許對對象變量直接訪問。比如,通過定義Point類和Rectangle類為public,它們都允許對它們的成員變量自由訪問。
JAVA編程語言提供了一個反問控制機制,憑它,類可以決定什麽其它的類可以直接訪問它的變量。如果其它對象對類直接操作可能導致無意義的話,類可以保護變量。改變這些變量應該利用方法調用來控制。如果類授權訪問給它的變量,你可以檢查和改變這些變量而但不能造成不利的效果。
2.2.2 調用對象的方法
同樣你可以使用有限制的名字(長名字)來調用對象的方法。有限制的名字的格式是:在對象引用的後面加上點(.)再跟著方法的名字,即對象引用.方法名字。同樣你還可以利用圓括號(和)來為方法提供參數。如果方法不需要任何參數就留空它:
objectReference.methodName(argumentList);
or
objectReference.methodName();
Rectangle類有兩個方法:area和move,即計算矩形的面積和改變矩形的原點。這裏是CreateObjectDemo代碼,它調用這兩個方法:
System.out.println("Area of rect_one: " + rect_one.area());
...
rect_two.move(40, 72);
上面的第一條語句調用rect_one的area方法並顯示結果。第二條語句是移動rect_two,因為move方法為對象的原點坐標x和y賦了新值。其中objectReference 必須是一個對象的引用。你可以使用一個變量名字,而且你也可以使用任何表達式來返回對象的引用。而new運算符返回一個對象的引用,因此你可以使用從new返回的數值來調用一個新的對象方法:
new Rectangle(100, 50).area()
表達式new Rectangle(100,50)返回一個對象引用,它是引用一個Rectangle對象。上面已經提到,你可以使用點符號(.)來調用新的Rectangle的面積方法以計算新矩形的面積。另外方法area也返回一個數值。對於這些返回數值的方法,你可以使用在表達式中使用方法調用。你可以指定返回的數值給變量,參見如下的例子:
int areaOfRectangle = new Rectangle(100, 50).area();
這裏要提醒一下,在特定對象中調用一個方法跟發送一個信息給對象是相同的。
2.2.3 關於方法訪問
在Point和Rectangle類中的方法都被聲明為public,因此它們可以被任何其它的類所訪問。有時,類需要限制訪問它的方法。比如,一個類可能可能有一個方法,只有它的子類才能調用它。類可以在它用於控制訪問它的變量的時候,使用相同的機制來對它的方法進行控制訪問。
2.3 清除沒有使用的對象
有些面向對象語言需要保持對所有對象的跟蹤,所以需要在對象不再使用的使用來將它從內存中清除。管理內存是一個很沈悶的事情而且容易出錯。JAVA平臺允許你創建任意個對象(當然會受到系統的限制),所以你也不必要老是要將它清除。JAVA是在當對象不再使用的使用被清除的。這個過程就是所謂的“垃圾收集”。
當對象不再有引用的時候,對象就會被清除,即作為垃圾收集的對象。保留在變量中的引用通常在變量超出作用域的時候被清除。或者,你可以通過設置變量為NULL來清除對象引用。這裏註意,程序中同一個對象可以有多個引用,對象的所有引用必須在對象被作為垃圾收集對象清除之前清除。
下面講講垃圾收集器:
JAVA有一個立即收集器,它周期性地講不再被引用的對象從內存中清除。這個垃圾收集器是自動執行的,雖然有時候你可能想通過調用系統類的gc方法來顯性運行垃圾收集程序。比如,你可能想在創建大量垃圾代碼之後或者在需要大量內存代碼之前運行垃圾收集器。垃圾收集器從內存中清除不再被引用的對象的機制已經被要到了VB.net和C#中去了。
arrow
arrow
    文章標籤
    java 編程 開發
    全站熱搜

    成功运行 發表在 痞客邦 留言(0) 人氣()