這節教程將開(kāi)始討論對象的生命周期。包括怎樣創(chuàng )建對象、怎樣使用它以及在不使用它的時(shí)候將它從系統中清除。下面一個(gè)一個(gè)介紹:
4.1 對象的生命周期
在這一小節中你可以學(xué)到怎樣創(chuàng )建和使用任何類(lèi)型的對象,還討論了當對象不再需要的時(shí)候系統怎樣清除對象的。
典型的JAVA程序創(chuàng )建對象,對象之間的交互是通過(guò)發(fā)送消息來(lái)實(shí)現的。通過(guò)這些對象的交互,JAVA程序可以執行一個(gè)GUI、運行一個(gè)動(dòng)畫(huà)或者通過(guò)網(wǎng)絡(luò )發(fā)送和接收信息。一旦對象已經(jīng)完成了任務(wù),它就被作為無(wú)用信息被回收,它的資源可以由其它對象回收利用。
以下是一個(gè)小的例子程CreateObjectDemo,它創(chuàng )建三個(gè)對象:一個(gè)是Point對象和兩個(gè)Rectange對象,你需要這三個(gè)源程序才可以編譯這個(gè)程序:
public class CreateObjectDemo {
public static void main(String[] args) {
//創(chuàng )建一個(gè)Point對象和兩個(gè)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);
// 移動(dòng)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);
}
}
一旦創(chuàng )建了對象,程序就可以操作對象并將它們有關(guān)的一些信息顯示出來(lái),以下是這個(gè)程序的輸出結果:
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
這一節使用這個(gè)例子來(lái)在程序中描述對象的生命周期。從這你可以學(xué)到怎樣編寫(xiě)代碼來(lái)創(chuàng )建、使用對象以及系統怎樣將它從內存中清除的。
4.1 對象的生命周期
下面主要分成幾部分來(lái)討論:
1. 創(chuàng )建對象
使用對象
清除沒(méi)有使用的對象
4.1.1 創(chuàng )建對象
眾所周知,可以從類(lèi)來(lái)創(chuàng )建對象。下面的幾條語(yǔ)句都是用來(lái)創(chuàng )建對象的,它們都是來(lái)自上面程序CreateObjectDemo程序:
Point origin_one = new Point(23, 94);
Rectangle rect_one = new Rectangle(origin_one, 100, 200);
Rectangle rect_two = new Rectangle(50, 100);
上面第一條語(yǔ)句從Point類(lèi)創(chuàng )建了一個(gè)對象,而第二條和第三條語(yǔ)句是從Rectangle類(lèi)眾創(chuàng )建了對象。但是每條語(yǔ)句都有三部分組成:
1. 聲明:Point origin_one、Rectangle rect_one以及Rectangle rect_two都是變量的聲明,它們的格式是類(lèi)型后加變量名。當你創(chuàng )建一個(gè)對象的時(shí)候,你不必聲明一個(gè)變量來(lái)引用它。然而,變量生命經(jīng)常出現在創(chuàng )建對象代碼的相同行上。
實(shí)例化:new是JAVA運算符,它可以創(chuàng )建新的對象并且為對象分配了內存空間。
初始化:new運算符后跟著(zhù)一個(gè)構造函數的調用。比如Point(23,94)就是一個(gè)Point類(lèi)的構造函數的調用。這個(gè)構造函數初始化了這個(gè)新對象。
下頁(yè)也對這幾個(gè)部分逐個(gè)介紹:
4.1.1.1 聲明一個(gè)變量來(lái)引用對象
從前面的教程,你應該知道了如何聲明一個(gè)變量了,你可以這樣來(lái)編寫(xiě):
type name
其中type是數據類(lèi)型,而name是變量名。
除了原始類(lèi)型(比如int和boolean),JAVA平臺還直接提供了類(lèi)和接口也是數據類(lèi)型。這樣為了聲明一個(gè)變量來(lái)引用對象,你可以使用類(lèi)或者接口的名字作為變量的類(lèi)型。下面的例程使用了Point和Rectangle類(lèi)作為類(lèi)型來(lái)聲明變量:
Point origin_one = new Point(23, 94);
Rectangle rect_one = new Rectangle(origin_one, 100, 200);
Rectangle rect_two = new Rectangle(50, 100);
聲明沒(méi)有創(chuàng )建新對象。Point origin_one代碼沒(méi)有一個(gè)新的Point對象,它只是聲明一個(gè)變量orgin_one,它將用來(lái)引用Point對象。這個(gè)引用暫時(shí)是空的直到被賦值了。一個(gè)空的引用就是一個(gè)NULL引用。
4.1.1.2 實(shí)例化對象
為了創(chuàng )建一個(gè)對象你必須用new來(lái)實(shí)例化它。New運算符是通過(guò)為新對象分配內存來(lái)實(shí)例化一個(gè)類(lèi)的。這個(gè)new運算符需要一個(gè)后綴參數,即構造函數的一個(gè)調用。構造函數的名字提供了要初始化類(lèi)的名字。構造函數初始化了新的對象。
New運算符號返回一個(gè)引用給它創(chuàng )建的對象的。通常,這個(gè)引用被賦值為適當類(lèi)型的變量。
4.1.1.3 初始化對象
以下是Point類(lèi)的代碼:
public class Point {
public int x = 0;
public int y = 0;
//一個(gè)構造函數
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
這個(gè)類(lèi)包含了一個(gè)構造函數。你可以識別這個(gè)構造函數因為它跟類(lèi)的名字是相同名字的,它沒(méi)有任何的返回類(lèi)型。這個(gè)在Point類(lèi)中的構造函數有兩個(gè)整型參數,它是由代碼(int x, int y)來(lái)定義的。下面的整數23和94就是這個(gè)參數的數值:
Point origin_one = new Point(23, 94);
4.1.1.3 初始化對象
下面是Rectangle類(lèi)的代碼,它包含了四個(gè)構造函數:
public class Rectangle {
public int width = 0;
public int height = 0;
public Point origin;
//四個(gè)構造函數
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;
}
//用于移動(dòng)rectangle的方法
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
//用于計算矩形面積的方法
public int area() {
return width * height;
}
}
每一個(gè)構造函數可以讓你為矩形的各個(gè)方法提供初始數值,你可以設置矩形的原點(diǎn)、寬度和高度。如果一個(gè)類(lèi)中有多個(gè)構造函數,它們的名字都是相同的只是它們有不同類(lèi)型的參數或者不同數目的參數。JAVA平臺可以根據參數的不同數目和類(lèi)型類(lèi)來(lái)區分構造函數。當JAVA平臺遇到的代碼的時(shí)候,它就調用在Rectangle類(lèi)中的構造函數,這個(gè)函數需要一個(gè)Point參數以及兩個(gè)整型參數:
Rectangle rect_one = new Rectangle(origin_one, 100, 200);
這個(gè)調用初始化了矩形的原點(diǎn)(orgin_one)。代碼也設置了矩形的寬度(100)和高度(200)。
4.1.1.3 初始化對象
多個(gè)引用可以引用相同的對象。下面的代碼行調用了需要兩個(gè)整型參數的構造函數,它為寬度和高度提供了初始化數值。如果你仔細看看這個(gè)代碼,你會(huì )發(fā)現它創(chuàng )建一個(gè)Point對象,它的x和y數值被初始化為0。
下面的Rectangle構造函數沒(méi)有任何參數:
Rectangle rect = new Rectangle();
如果一個(gè)類(lèi)沒(méi)有顯性聲明任何構造函數,JAVA平臺自動(dòng)提供一個(gè)沒(méi)有參數的構造函數,這是一個(gè)缺省的構造函數,它沒(méi)有完成任何事情。這樣,所有的類(lèi)就至少有一個(gè)構造函數。
4.1.2 使用對象
一旦你創(chuàng )建了一個(gè)對象,你可能想使用它來(lái)做一些事情。你可能從它得到一些信息,或者想改變它的狀態(tài)或者讓它來(lái)完成一些動(dòng)作。對象允許你做以下兩件事情:
1. 操作或者檢查它的變量。
調用它的方法。
4.1.2.1 引用對象的變量
下面是引用對象變量的基本形式,它是使用了有條件的名字即長(cháng)名字:
objectReference.variableName
當實(shí)例變量處在作用域內的時(shí)候,你可以為實(shí)例變量使用一個(gè)簡(jiǎn)單的名字,也就是說(shuō),在對象類(lèi)的代碼中。處在對象類(lèi)外面的代碼必須使用有條件的名字。比如,在CreateObjectDemo類(lèi)中的代碼處在類(lèi)Rectangle類(lèi)代碼的外面。所以為了引用Rectangle對象rect_one的origin、width和height變量,CreateObjectDemo必須相應使用rect_one.origin、rect_one.width和rect_one.height。這個(gè)程序使用了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類(lèi)中的變量width和height,那就將產(chǎn)生一個(gè)編譯錯誤。在后面,程序還將使用類(lèi)似的代碼來(lái)顯示關(guān)于rect_two的信息。相同類(lèi)型的對象將有相同實(shí)例變量的副本。這樣,每一個(gè)Rectangle對象就都有變量origin、width和height了。當你通過(guò)對象引用來(lái)訪(fǎng)問(wèn)實(shí)例變量的時(shí)候,你就引用了特定對象的變量。在CreateObjectDemo程序有兩個(gè)對象rect_one和rect_two,它們有不同的origin、width和height變量:
對象的長(cháng)文件名的第一部分是對象引用,它必須是一個(gè)對象的引用。這里你可以使用引用變量的名字,或者你可以使用任何的表達式來(lái)返回一個(gè)對象引用。重新調用這個(gè)new運算符可以返回一個(gè)對象的引用。這樣你可以使用從new返回的數值來(lái)訪(fǎng)問(wèn)一個(gè)新的對象變量:
int height = new Rectangle().height;
這個(gè)語(yǔ)句創(chuàng )建了一個(gè)新的Rectangle對象并且得到它的height(高度)。從本質(zhì)上講,這條語(yǔ)句計算了Rectangle缺省的高度。這里注意,在這條語(yǔ)句被執行后,程序不再有創(chuàng )建了的Rectangle的引用,因為程序不再在變量中存儲這個(gè)引用。對象就被取消引用,而它的資源可以JAVA平臺重新使用。
4.1.2.2 關(guān)于變量訪(fǎng)問(wèn)
利用其它對象和類(lèi)對對象變量直接的操作是不允許的,因為有可能為變量設置的數值沒(méi)有任何的意義。比如,我們使用前面教程中的Rectangle類(lèi),你可以創(chuàng )建一個(gè)矩形,它的width和height都是負的,但是它是沒(méi)有意義的。
較好的做法是:不采用直接對變量進(jìn)行操作,類(lèi)提供一些方法,其它的對象可以通過(guò)這些方法來(lái)檢查或者改變變量。這些方法要確保變量的數值是有意義的。這樣,Rectangle類(lèi)將提供setWidth、setHeight、getWidth以及getHeight方法來(lái)設置或者獲得寬度和高度。這些用于設置變量的方法將在調用者試圖將width和height設置為負數的時(shí)候匯報一個(gè)錯誤。使用方法而不使用直接變量訪(fǎng)問(wèn)的好處還有:類(lèi)可以改變變量的類(lèi)型和名字來(lái)存儲width和height而沒(méi)有影響它的客戶(hù)程序。
但是,在實(shí)際情況下,有時(shí)允許對對象變量直接訪(fǎng)問(wèn)。比如,通過(guò)定義Point類(lèi)和Rectangle類(lèi)為public,它們都允許對它們的成員變量自由訪(fǎng)問(wèn)。
JAVA編程語(yǔ)言提供了一個(gè)反問(wèn)控制機制,憑它,類(lèi)可以決定什么其它的類(lèi)可以直接訪(fǎng)問(wèn)它的變量。如果其它對象對類(lèi)直接操作可能導致無(wú)意義的話(huà),類(lèi)可以保護變量。改變這些變量應該利用方法調用來(lái)控制。如果類(lèi)授權訪(fǎng)問(wèn)給它的變量,你可以檢查和改變這些變量而但不能造成不利的效果。
4.1.2.2 調用對象的方法
同樣你可以使用有限制的名字(長(cháng)名字)來(lái)調用對象的方法。有限制的名字的格式是:在對象引用的后面加上點(diǎn)(.)再跟著(zhù)方法的名字,即對象引用.方法名字。同樣你還可以利用圓括號(和)來(lái)為方法提供參數。如果方法不需要任何參數就留空它:
objectReference.methodName(argumentList);
or
objectReference.methodName();
Rectangle類(lèi)有兩個(gè)方法:area和move,即計算矩形的面積和改變矩形的原點(diǎn)。這里是CreateObjectDemo代碼,它調用這兩個(gè)方法:
System.out.println("Area of rect_one: " + rect_one.area());
...
rect_two.move(40, 72);
上面的第一條語(yǔ)句調用rect_one的area方法并顯示結果。第二條語(yǔ)句是移動(dòng)rect_two,因為move方法為對象的原點(diǎn)坐標x和y賦了新值。其中objectReference 必須是一個(gè)對象的引用。你可以使用一個(gè)變量名字,而且你也可以使用任何表達式來(lái)返回對象的引用。而new運算符返回一個(gè)對象的引用,因此你可以使用從new返回的數值來(lái)調用一個(gè)新的對象方法:
new Rectangle(100, 50).area()
表達式new Rectangle(100,50)返回一個(gè)對象引用,它是引用一個(gè)Rectangle對象。上面已經(jīng)提到,你可以使用點(diǎn)符號(.)來(lái)調用新的Rectangle的面積方法以計算新矩形的面積。另外方法area也返回一個(gè)數值。對于這些返回數值的方法,你可以使用在表達式中使用方法調用。你可以指定返回的數值給變量,參見(jiàn)如下的例子:
int areaOfRectangle = new Rectangle(100, 50).area();
這里要提醒一下,在特定對象中調用一個(gè)方法跟發(fā)送一個(gè)信息給對象是相同的。
4.1.2.3 關(guān)于方法訪(fǎng)問(wèn)
在Point和Rectangle類(lèi)中的方法都被聲明為public,因此它們可以被任何其它的類(lèi)所訪(fǎng)問(wèn)。有時(shí),類(lèi)需要限制訪(fǎng)問(wèn)它的方法。比如,一個(gè)類(lèi)可能可能有一個(gè)方法,只有它的子類(lèi)才能調用它。類(lèi)可以在它用于控制訪(fǎng)問(wèn)它的變量的時(shí)候,使用相同的機制來(lái)對它的方法進(jìn)行控制訪(fǎng)問(wèn)。
4.1.3 清除沒(méi)有使用的對象
有些面向對象語(yǔ)言需要保持對所有對象的跟蹤,所以需要在對象不再使用的使用來(lái)將它從內存中清除。管理內存是一個(gè)很沉悶的事情而且容易出錯。JAVA平臺允許你創(chuàng )建任意個(gè)對象(當然會(huì )受到系統的限制),所以你也不必要老是要將它清除。JAVA是在當對象不再使用的使用被清除的。這個(gè)過(guò)程就是所謂的“垃圾收集”。
當對象不再有引用的時(shí)候,對象就會(huì )被清除,即作為垃圾收集的對象。保留在變量中的引用通常在變量超出作用域的時(shí)候被清除?;蛘?,你可以通過(guò)設置變量為NULL來(lái)清除對象引用。這里注意,程序中同一個(gè)對象可以有多個(gè)引用,對象的所有引用必須在對象被作為垃圾收集對象清除之前清除。
下面講講垃圾收集器:
JAVA有一個(gè)立即收集器,它周期性地講不再被引用的對象從內存中清除。這個(gè)垃圾收集器是自動(dòng)執行的,雖然有時(shí)候你可能想通過(guò)調用系統類(lèi)的gc方法來(lái)顯性運行垃圾收集程序。比如,你可能想在創(chuàng )建大量垃圾代碼之后或者在需要大量?jì)却娲a之前運行垃圾收集器。垃圾收集器從內存中清除不再被引用的對象的機制已經(jīng)被要到了VB.net和C#中去了。
最后介紹對象finalize方法:
在一個(gè)對象得到垃圾收集之前,垃圾收集器在對象自己調用對象的finalize方法之后給對象一個(gè)機會(huì )來(lái)從內存中清除掉。這個(gè)過(guò)程就是所說(shuō)的最后處理。
絕大部分的程序員不得不關(guān)系這個(gè)finalize方法的執行。在少數情況下,程序員不得不執行finalize方法來(lái)釋放資源。
Finalize方法是一個(gè)對象類(lèi)的成員函數,它處在JAVA平臺類(lèi)分級結構的頂部,而且是所有類(lèi)的子類(lèi)。這個(gè)類(lèi)重載了finalize方法來(lái)完成對象的最后處理工作。
4.2字符和字符串
字符數據(不管是單一字符或者一系列的字符)可以利用java.lang三個(gè)類(lèi)來(lái)儲存和操作,這三個(gè)類(lèi)分別為:Character、String和StringBuffer。
JAVA平臺包含了三個(gè)類(lèi),在處理字符數據的時(shí)候你可以使用這三個(gè)類(lèi):
1. Character:這個(gè)類(lèi)的實(shí)例可以容納單一的字符數值。這個(gè)同樣定義了簡(jiǎn)潔的方法來(lái)操作或者檢查單一字符數據。
String:這個(gè)類(lèi)用于處理由多個(gè)字符組成的不可變數據。
StringBuffer:這個(gè)類(lèi)用于存儲和操作由多個(gè)字符組成的可變數據。
下面開(kāi)始詳細介紹字符:
字符類(lèi)型的對象包含了單一字符數值。你可以在對象需要的時(shí)候使用一個(gè)字符對象取代原始字符類(lèi)型。比如,當傳遞一個(gè)字符給改變數值的方法或者當放置一個(gè)字符到一個(gè)數據結構中,比如一個(gè)矢量等等。下面的例程序CharacterDemo創(chuàng )建了一些字符對象并顯示一些信息。
這個(gè)程序的數據結果為:
a is less than b.
a is equal to a2.
The character a is lowercase.
4.2字符和字符串
CharacterDemo程序調用以下由Character類(lèi)提供的構造函數和方法:
Character(char)
Character類(lèi)只是構造函數,它創(chuàng )建了一個(gè)Character對象包含了由參數提供的數值。一旦Character對象被創(chuàng )建,它包含的數值就不能改變。
compareTo(Character)
一個(gè)實(shí)例方法比較了由兩個(gè)Character對象容納的數值:方法被調用的對象(即例子中的a)以及方法的參數(即例子中的b)。這個(gè)方法返回一個(gè)整數表明在當前對象中的數值是否大于、等于或者小于參數給定的數值。如果字母的數值較大那么這個(gè)字母就較大。
equals(Object)
一個(gè)實(shí)例方法,它比較當前對象容納的數值和由其它容納的數值。這個(gè)方法在兩個(gè)對象容納的數值相等的時(shí)候返回true。
toString()
一個(gè)實(shí)例方法,它將對象轉換為字符串。結果的字符串在長(cháng)度上就是一個(gè)Character對象并且它包含了有這個(gè)Character對象容納的數值。
charValue()
一個(gè)實(shí)例方法,它返回由Character對象容納的數值作為原始字符數值。
isUpperCase(char)
類(lèi)方法決定是否原始字符數值為大寫(xiě)。這個(gè)是許多Character類(lèi)方法中的一個(gè),它可以檢查或者操作字符數據。
下面我們再談?wù)動(dòng)趕tring(字符串)有關(guān)的幾個(gè)問(wèn)題:
1. 為什么有兩個(gè)String類(lèi):String 和StringBuffer
創(chuàng )建Strings 和StringBuffers
存取器函數
修改StringBuffers
將對象轉換為Strings
將String轉換為數字
Strings和JAVA編譯器
下頁(yè)接著(zhù)一個(gè)一個(gè)加以細講。
1)為什么有兩個(gè)String類(lèi):String 和StringBuffer
JAVA平臺提供了兩個(gè)類(lèi):String和StringBuffer,它們可以?xún)Υ婧筒僮髯址?,即包含多個(gè)字符的字符數據。這個(gè)String類(lèi)提供了數值不可改變的字符串。比如,如果你編寫(xiě)一個(gè)方法,它需要字符串數據并且方法不能修改字符串,而要將一個(gè)String對象傳遞給方法。而這個(gè)StringBuffer類(lèi)提供的字符串進(jìn)行修改。當你直到字符數據要改變的時(shí)候你就可以使用StringBuffer。典型地,你可以使用StringBuffers來(lái)動(dòng)態(tài)構造字符數據。比如,從一個(gè)文件讀文本數據。因為Strings是常量,所以它用起來(lái)比StringBuffers更有效,并且可以共享。因此在允許的情況下還是使用Strings。
下面是一個(gè)例程StringsDemo,它反轉了字符串中的字符。這個(gè)程序同時(shí)使用了String和StringBuffer:
public class StringsDemo {
public static void main(String[] args) {
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
StringBuffer dest = new StringBuffer(len);
for (int i = (len - 1); i >= 0; i--) {
dest.append(palindrome.charAt(i));
}
System.out.println(dest.toString());
}
}
這個(gè)程序的輸出為:
doT saw I was toD
2)創(chuàng )建Strings 和StringBuffers
字符串經(jīng)常是由雙引號括起的一系列字符組成。比如,當有以下的字符串,JAVA平臺就創(chuàng )建一個(gè)String對象,它的數值為Goodluck。
"Goodluck"
這個(gè)StringsDemo程序使用這個(gè)記述來(lái)創(chuàng )建字符串,它是由palindrome變量引用的:
String palindrome = "Dot saw I was Tod";
同樣你可以利用其它方法來(lái)創(chuàng )建String對象:使用new關(guān)鍵字和構造函數。String類(lèi)提供了幾個(gè)構造函數,它允許你提供字符串的初始值,它們是使用不同的資源的,比如字符的數組、字節的數組或者一個(gè)StringBuffer。
char[] helloArray = { ‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘ };
helloString = new String(helloArray);
System.out.println(helloString);
上面的這段程序輸出為:hello。
你必須使用new來(lái)創(chuàng )建一個(gè)StringBuffer。StringsDemo程序創(chuàng )建了SringBuffer,它是由dest引用的,這里使用了設置緩沖區容量的構造函數。
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
StringBuffer dest = new StringBuffer(len);
這個(gè)代碼創(chuàng )建了一個(gè)字符串的緩沖區,這個(gè)緩沖區的容量等于被palindrome引用的字符串的長(cháng)度。這個(gè)確保了為dest只分配一個(gè)內存,因為它只有包含被復制的字符串那么大的空間。通過(guò)初始化字符串的緩沖區的容量,你最小化必須分配的內存空間。這就使得你的代碼更加有效,因為內存分配是相對高級的操作。
(3)存取器函數
首先講解一下獲得String或者StringBuffer的長(cháng)度:
獲得有關(guān)對象信息的方法稱(chēng)為存取器函數。你可以用在字符串和字符串緩沖區的一個(gè)存取器方法是length方法,它可以包含在字符串或者字符串緩沖區的字符的個(gè)數。下面給出一個(gè)例程,當這個(gè)程序執行后,len就將等于17:
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
除了length,StringBuffer類(lèi)還有一個(gè)方法叫做capacity,它是返回為字符串緩沖區分配的空間大小而不是空間使用了多少。比如,字符串緩沖區的容量在StringsDemo例程中被dest引用時(shí),它是不能改變的,雖然它的長(cháng)度在每次的循環(huán)中增加1。如圖15,給出了在dest里面已經(jīng)有9個(gè)字符之后的容量和長(cháng)度。
(圖15)
一個(gè)字符串緩沖區的長(cháng)度是它包含的字符的個(gè)數。一個(gè)字符串緩沖區的容量是被分配的字符空間的數量。而String類(lèi)沒(méi)有capacity方法,因為字符串不能改變。
下面講講索引String或者String Buffer得到字符:
你可以通過(guò)使用charAt存取器來(lái)在一個(gè)特定的位置索引一個(gè)字符串或者字符串緩沖區以得到字符串。第一個(gè)字符的索引是0,最后一個(gè)字符的索引是length()-1。比如,下面的代碼在字符串中得到索引為9的字符:
String anotherPalindrome = "Niagara. O roar again!";
char aChar = anotherPalindrome.charAt(9);
因為索引是從0開(kāi)始的,所以索引為9的字符為‘O‘,如圖16所示:
(圖16)
使用charAt方法來(lái)在特定的索引下得到字符。如圖16所示給處了計算字符串最后一個(gè)字符的索引的方法,你必須將length方法返回的數值減去1才得到最后一個(gè)字符的索引。
(3)存取器函數
如果你想從一個(gè)字符串或者字符串緩沖區得到多個(gè)字符,你可以使用substring方法。這個(gè)substring方法有兩個(gè)版本,如下表所示:
方法
描述
String substring(int)
返回一個(gè)新的字符串,它是這個(gè)字符串或者字符串緩沖區的一個(gè)子串。第一個(gè)整數參數指定了第一個(gè)字符的索引。第二個(gè)整數參數是最后字符-1的索引。這個(gè)子串的長(cháng)度就是第二個(gè)整數減去第一個(gè)整數。如果第二個(gè)整數沒(méi)有,那么substring就擴展到整個(gè)字符串的結尾。
String substring(int,int)
下面的代碼是得到字符串"Niagara. O roar again!"從索引為11到索引為15之間的子串,結果得到單詞"roar":
String anotherPalindrome = "Niagara. O roar again!";
String roar = anotherPalindrome.substring(11, 15);
如圖17所示:
(圖17)
使用substring方法來(lái)得到字符串或者字符串緩沖區的一部分。這里一定要記住索引是從0開(kāi)始的。
(4)修改StringBuffers
reverseIt方法使用StringBuffer的append方法來(lái)增加一個(gè)字符到dest字符串末尾:
class ReverseString {
public static String reverseIt(String source) {
int i, len = source.length();
StringBuffer dest = new StringBuffer(len);
for (i = (len - 1); i >= 0; i--) {
dest.append(source.charAt(i));
}
return dest.toString();
}
}
如果這個(gè)被增加的字符導致StringBuffer的大小超過(guò)當前的容量,這個(gè)StringBuffer就會(huì )為它分配更多的內存。因為內存分配示相對高級的操作,所以你可以同時(shí)初始化StringBuffer的容量為較合理的大小來(lái)使你的代碼更有效率。比如reverseIt方法以初始的容量來(lái)構造StringBuffer等于源字符串的長(cháng)度,以只為dest分配一次內存。
4)修改StringBuffers
用在reverseIt的append方法只是一個(gè)StringBuffer方法的其中一種,它在StringBuffer末尾增補了一個(gè)數據。有幾種append方法來(lái)增補各個(gè)類(lèi)型的數據(比如float、int、boolean以及對象)到StringBuffer末尾。但是在增補操作之前,數據都要先轉換為字符串。
下面講講插入字符:
有時(shí)候,你可能想插入數據到StringBuffer中間。你可以使用StringBuffer的insert方法來(lái)實(shí)現。以下的這個(gè)例子就是介紹如何將一個(gè)字符串插入到StringBuffer中去的:
StringBuffer sb = new StringBuffer("Drink Java!");
sb.insert(6, "Hot ");
System.out.println(sb.toString());
這些代碼將輸出:
Drink Hot Java!
利用StringBuffer的許多insert方法,你可以在插入數據之前指定索引。在上面的例子中,"Hot "要插到"Java"的‘J‘之前。因為索引是從0開(kāi)始的,所以‘J‘的索引為6。為了插入數據到StringBuffer之前,使用索引0.為了在StringBuffer的末尾插入數據,你可以將所以等于StringBuffer的長(cháng)度或者使用append方法來(lái)增補。
下面討論設置字符:
另外一個(gè)有用的StringBuffer修改量是setCharAt,它在StringBuffer的指定位置用參數列表中的指定字符來(lái)替換字符。SetCharAt在你想重新使用StringBuffer的時(shí)候是很有用的。
(5)將對象轉換為Strings
首先介紹toString方法:
經(jīng)常需要將一個(gè)對象轉換為String,因為你需要將它傳遞給方法,而這個(gè)方法只接收String數值。前面我們使用reverseIt方法使用了StringBuffer的toString方法來(lái)將StringBuffer轉換為String對象。
class ReverseString {
public static String reverseIt(String source) {
int i, len = source.length();
StringBuffer dest = new StringBuffer(len);
for (i = (len - 1); i >= 0; i--) {
dest.append(source.charAt(i));
}
return dest.toString();
}
}
所有的類(lèi)從對象類(lèi)繼承了toString,并且在java.lang包的許多類(lèi)重載了這個(gè)方法來(lái)提供一個(gè)很有意義的方法
下面說(shuō)說(shuō)valueOf方法:
簡(jiǎn)單起見(jiàn),String類(lèi)提供了一個(gè)類(lèi)方法valueOf。你可以使用valueOf來(lái)轉換不同類(lèi)型的變量為String。比如,為了打印pi的數值,你可以這樣來(lái)編寫(xiě)代碼:
System.out.println(String.valueOf(Math.PI));
6)將String轉換為數字
String類(lèi)本身沒(méi)有提供任何的方法來(lái)轉換String為浮點(diǎn)型、整型或者其它的數值類(lèi)型。但是,"type wrapper"類(lèi)的四種類(lèi)型(integer、Double、Float和Long)提供了一個(gè)類(lèi)方法valueOf來(lái)將String轉換為那個(gè)類(lèi)型的對象。舉例如下:
String piStr = "3.14159";
Float pi = Float.valueOf(piStr);
(7)Strings和JAVA編譯器
JAVA編譯器使用了String和StringBuffer類(lèi)來(lái)處理字符串和字符串的連接。
下面先講講Strings:
在JAVA種,你可以在雙引號之間指定字符串,如:
"Hello World!"
你可以在任何使用String對象的地方使用字符串。比如,System.out.println接收一個(gè)String參數,所以你可以在這里使用字符串了。
System.out.println("Might I add that you look lovely today.");
同樣,你可以使用從字符串直接使用String方法,比如:
int len = "Goodbye Cruel World".length();
因為編譯器自動(dòng)為字符串創(chuàng )建了一個(gè)新的String對象,你可以使用字符串來(lái)初始化一個(gè)String對象:
String s = "Hola Mundo";
上面的這條語(yǔ)句等價(jià)于下面的語(yǔ)句:
String s = new String("Hola Mundo");
最后講講字符串的連接以及+運算符:
在JAVA種,你可以使用+來(lái)連接字符串,比如:
String cat = "cat";
System.out.println("con" + cat + "enation");
這條語(yǔ)句看起來(lái)有點(diǎn)問(wèn)題,因為我們直到Strings是不能改變的。但是,在這條語(yǔ)句的背后,編譯器卻使用了StringBuffers來(lái)執行字符串的連接。上面的語(yǔ)句實(shí)際上編譯為:
String cat = "cat";
System.out.println(new StringBuffer().append("con").
append(cat).append("enation").toString());
同樣你可以使用+運算符號來(lái)增不一個(gè)String:
System.out.println("Java‘s Number " + 1);
在JAVA中,在執行字符串連接操作之前編譯器講非String的數值(如本例的整數1)轉化為一個(gè)String對象。
4.3 數字
為了處理數值類(lèi)型,你可以使用Number類(lèi)。這個(gè)Number類(lèi)是所有在JAVA平臺中所有數字類(lèi)的父類(lèi)。它的子類(lèi)包括Float、Interger等等。
本節教程將討論java.lang和它的子類(lèi)中的Number類(lèi)。特別地,這節教程要討論為什么你需要這些類(lèi),并指出通用的方法和類(lèi)變量,以及向你介紹如何將實(shí)例轉換為字符串。
此外,這節教程還討論你需要的其它類(lèi)來(lái)處理數字。比如,如果你需要以某個(gè)特殊格式來(lái)顯示數字的時(shí)候,你可以使用在java.test中的NumberFormat和DecimalFormat類(lèi)來(lái)格式化它。同時(shí),java.lang中的Math包含了類(lèi)方法來(lái)執行數學(xué)函數。這個(gè)類(lèi)還有用于三角函數、指數函數等等的方法。如圖18所示:
(圖18)
數字類(lèi)包含:
1. Number :這個(gè)抽象類(lèi)Number是Byte、Double、Float、Integer、Long和Short的父類(lèi)。Number的子類(lèi)必須提供將數值轉換為byte、double、float、int、long以及short的方法。
Byte:這個(gè)類(lèi)是Number的子類(lèi),它是用于字節數值的標準wrapper。
Double:這個(gè)Double類(lèi)在對象中包裝了原始類(lèi)型double。Double類(lèi)的對象包含單一類(lèi)型(double)的對象。另外,這個(gè)類(lèi)提供了幾個(gè)用于將double轉換為String或者將String轉換為double的方法。
Float :這個(gè)Float類(lèi)在對象中包裝了原始類(lèi)型Float。Float類(lèi)的對象包含單一類(lèi)型(Float)的對象。另外,這個(gè)類(lèi)提供了幾個(gè)用于將Float轉換為String或者將String轉換為Float的方法。
Integer:這個(gè)Integer類(lèi)在對象中包裝了原始類(lèi)型Integer。Integer類(lèi)的對象包含單一類(lèi)型(Integer)的對象。另外,這個(gè)類(lèi)提供了幾個(gè)用于將Integer轉換為String或者將String轉換為Integer的方法。
Long :這個(gè)Long類(lèi)在對象中包裝了原始類(lèi)型Long。Long類(lèi)的對象包含單一類(lèi)型(Long)的對象。另外,這個(gè)類(lèi)提供了幾個(gè)用于將Long轉換為String或者將String轉換為L(cháng)ong的方法。
Short:這個(gè)類(lèi)是用于short數值的標準wrapper。
4.3 數字
8. BigDecimal:不可變的、任意精度的有符號的十進(jìn)制數字。BigDecimal包含了任意精度的整型數和非負的32位的整型數,BigDecimal 提供了用于基本算術(shù)運算、比較、格式轉換等等的操作。這個(gè)BigDecimal類(lèi)給了用戶(hù)對舍入行為的完全控制,并且強迫用戶(hù)為舍棄精度的操作顯性指定一個(gè)舍入行為?;谶@個(gè)目的有八種舍入模式。對BigDecimal有兩種類(lèi)型的操作:比例/舍入操作和十進(jìn)制點(diǎn)移動(dòng)操作。比例/舍入操作返回一個(gè)BigDecimal,它的數值大約或者精確地等于運算對象,但是它的數值范圍要指定,也就是說(shuō),它們可以對它的數值最小的影響來(lái)增加或者減少數字的精度。十進(jìn)制點(diǎn)移動(dòng)操作(movePointLeft和movePointRight)返回一個(gè)由運算對象創(chuàng )建的BigDecima,它是通過(guò)在指定方向和指定距離來(lái)移動(dòng)十進(jìn)制點(diǎn)的。為了達到簡(jiǎn)短和清晰的目的,偽代碼用在了BigDecimal方法的描述中。比如偽代碼表達式(i j)就代表了“BigDecimal的數值是由BigDecimal i加上BigDecimal j的數值”。而偽代碼表達式(i="=j)代表“當且僅當BigDecimal" i的數值與BigDecimal j相同的時(shí)候才為true”。其它的偽代碼表達式也有類(lèi)似的解釋。
BigInteger:不可變任意精度的整型數。BigInteger為所有的Java原始整型操作以及所有在java.lang.Math中的相關(guān)方法提供相似的操作。另外BigInteger偽模數運算、GCD計算、位操作等等提供了運算。算術(shù)運算的語(yǔ)義模仿了定義在JAVA語(yǔ)言規范中的Java的整型算術(shù)運算。比如,如果除數為0就會(huì )導致ArithmeticException(算術(shù)異常)等等。所有在規范中的溢出都將被忽略,因為BigIntegers將盡量適應運算結果的需要。而移位操作擴展了Java的移位操作,它允許負方向的移位。以負的位距來(lái)往右移就相當于往左移位。而無(wú)符號的右移運算符(>>>)這里就不再使用。 而按位邏輯操作跟Java的按位操作是相似的。比較運算執行有符號的整型比較,它跟Java的是相似的。模數算術(shù)運算提供計算余數、執行乘冪等方法。這些方法總是返回一個(gè)非零的結果(介于0到-1之間)。為了簡(jiǎn)潔和清晰的目的,偽代碼也用在BigInteger方法中。這個(gè)偽代碼表達式(i j)代表了“等于BigInteger i加上BigInteger j的BigInteger數值”。而偽代碼表達式(i="=j)代表了“當且僅當BigInteger" i等于BigInteger j的時(shí)候才返回true”。
4.3 數字
其它的數據類(lèi)型:
1. Boolean :這個(gè)Boolean類(lèi)在對象中包裝了原始類(lèi)型Boolean。Boolean類(lèi)的對象包含單一類(lèi)型(double)的對象。另外,這個(gè)類(lèi)提供了幾個(gè)用于將Boolean轉換為String或者將String轉換為Boolean的方法。
Character :這個(gè)Character類(lèi)在對象中包裝了原始類(lèi)型Character。Character類(lèi)的對象包含單一類(lèi)型(Character)的對象。另外,這個(gè)類(lèi)提供了幾個(gè)用于將字符由小寫(xiě)轉換為大寫(xiě)或者由大寫(xiě)轉換為小寫(xiě)的方法。
Void:這個(gè)Void類(lèi)是一個(gè)占位符類(lèi),它保留對代表原始JAVA類(lèi)void的引用。
非基本算術(shù)類(lèi)型Math:
這個(gè)Math類(lèi)包含了用于執行數值操作的方法,比如初步的指數、對數、平反根以及三角函數。不象StrictMath類(lèi)中的有些數值函數,這個(gè)Math類(lèi)的所有函數不是定義為返回bit-for-bit相同的結果。這允許更好的執行,因為嚴格的再現情已經(jīng)不需要了。
缺省地,許多Math函數簡(jiǎn)單代表了在StrictMath中的等價(jià)函數。代碼發(fā)生器支持使用特殊平臺的本地庫或者微處理器指令以提供性能更高的Math函數實(shí)行。這樣高性能的執行必須符合Math的規范。
4.4 數組
在任何的編程語(yǔ)言中,數組都是一個(gè)重要的數據結構。數組是一個(gè)固定長(cháng)度的結構,它存儲多個(gè)相同類(lèi)型的數值。你可以在數組中集合相同類(lèi)型的數值。數組直接被JAVA編程語(yǔ)言所支持,所以沒(méi)有一個(gè)數組類(lèi)。數組是一個(gè)Object類(lèi)的一個(gè)不明顯的擴展,所以你可以指定一個(gè)數組給一個(gè)類(lèi)型定義為Object的變量。
JAVA平臺集合了它的類(lèi)到功能包中。不是編寫(xiě)你自己的類(lèi),你可以使用有平臺提供的類(lèi)。這節教程中要討論的絕大多數的類(lèi)都是java.lang包的成員函數。所有java.lang中的類(lèi)對你的程序都是有效的。
數組的長(cháng)度在數組創(chuàng )建的時(shí)候就已經(jīng)確定。一旦創(chuàng )建以后,數組就有了固定長(cháng)度的結構,如圖19所示:
(圖19)
數組元素就是數組中的一個(gè)數值,可以通過(guò)數組中的位置來(lái)訪(fǎng)問(wèn)它。
如果你想在一個(gè)結構中存儲不同類(lèi)型的數據,或者如果你需要一個(gè)長(cháng)度可以動(dòng)態(tài)改變的結構,可以使用Collection,比如Vector而不用數組。
本教程中將討論以下的幾個(gè)方法:
1. 創(chuàng )建和使用數組合
對象的數組
數組的數組
復制數組
4.4.1 創(chuàng )建和使用數組合
以下是個(gè)簡(jiǎn)單的程序ArrayDemo,它創(chuàng )建了一個(gè)數組,并放置了一些數值在上面,然后進(jìn)行顯示:
public class ArrayDemo {
public static void main(String[] args) {
int[] anArray; // 聲明一個(gè)整型數組
anArray = new int[10]; // 創(chuàng )建一個(gè)整型數組
// 為每一個(gè)數組元素賦值并打印出來(lái)
for (int i = 0; i < anArray.length; i++) {
anArray[1] = i;
System.out.print(anArray[1] + " ");
}
System.out.println();
}
}
這節教程覆蓋了以下這些內容:
1. 聲明一個(gè)變量來(lái)引用一個(gè)數組
創(chuàng )建一個(gè)數組
訪(fǎng)問(wèn)數組元素
獲得數組的大小
數組初始化程序
下一頁(yè)將加以詳細說(shuō)明。
4.4.1 創(chuàng )建和使用數組合
(1)聲明一個(gè)變量來(lái)引用一個(gè)數組
以下的代碼是聲明一個(gè)數組變量:
int[] anArray; // 聲明整型的數組
象聲明其它類(lèi)型的變量,一個(gè)數組聲明有兩個(gè)組件:數組的類(lèi)型和數組的名字。數組的類(lèi)型是這樣來(lái)寫(xiě)的type[],其中type可以是float、boolean、Object、String等,而[]代表了這是一個(gè)數組。這里記住在數組中的所有元素都是相同類(lèi)型的。上面的例程中使用了int[],所以數組anArray就將容納整型數據了。以下是聲明其它類(lèi)型的數組:
float[] anArrayOfFloats;
boolean[] anArrayOfBooleans;
Object[] anArrayOfObjects;
String[] anArrayOfStrings;
就象聲明其它類(lèi)型的變量,聲明數組變量也沒(méi)有為數組元素分配任何內存。所以必須在引用數組之前被數組賦值。
4.4.1 創(chuàng )建和使用數組合
(2)創(chuàng )建一個(gè)數組
你可以使用JAVA的new運算符來(lái)創(chuàng )建一個(gè)數組。下面的語(yǔ)句是為10個(gè)整型元素分配一個(gè)數組內存:
anArray = new int[10]; // create an array of integers
總得說(shuō)來(lái),當創(chuàng )建數組的時(shí)候,你可以使用new操作符,后面跟著(zhù)數組元素的數據類(lèi)型然后就是用方括號[和]括起來(lái)的元素的數目,格式如下所示:
new elementType[arraySize]
如果在上面的例程中new語(yǔ)句沒(méi)有的話(huà),編譯器將打印除一個(gè)如下的錯誤是的編譯發(fā)生錯誤:
ArrayDemo.java:4: Variable anArray may not have been initialized(變量anArray 可能還沒(méi)有初始化。)
(3)訪(fǎng)問(wèn)數組元素
既然已經(jīng)給數組分配了內存,我們來(lái)為數組元素賦值吧:
for (int i = 0; i < anArray.length; i++) {
anArray[1] = i;
System.out.print(anArray[1] + " ");
}
這部分的代碼給出了怎樣引用一個(gè)數組元素,或者示為它賦予一個(gè)數值,或者訪(fǎng)問(wèn)數值。在方括號之間的數值指示了要訪(fǎng)問(wèn)的元素的索引。在JAVA中,數組的索引是從0開(kāi)始的并且以-1結束。
4.4.1 創(chuàng )建和使用數組合
(4)獲得數組的大小
為了獲得數組的大小,你可以使用下面的代碼:
arrayname.length
這里還提醒一下:JAVA的新手可能會(huì )在length后面加一個(gè)圓括號(和)。這樣是否錯誤的,因為length不是一個(gè)方法。Length是由JAVA平臺為所有數組提供的一個(gè)屬性。
在上面的例程中的for循環(huán)在anArray的每一個(gè)元素進(jìn)行循環(huán),并給每個(gè)元素賦值。這個(gè)for循環(huán)使用了anArray.length來(lái)決定什么時(shí)候終止循環(huán)。
(5)數組初始化程序
JAVA編程語(yǔ)言為創(chuàng )建和初始化數組提供了簡(jiǎn)捷的語(yǔ)法。一下是這個(gè)語(yǔ)法的例子:
boolean[] answers = { true, false, true, true, false };
數組的length(長(cháng)度)是由大括號{和}之間的數值的數目決定的。
4.4.2 對象的數組
數組可以保留引用類(lèi)型。你可以用創(chuàng )建原始類(lèi)型數組的方法來(lái)創(chuàng )建這樣一個(gè)數組。以下是一個(gè)小的程序ArrayOfStringsDemo,它創(chuàng )建了一個(gè)數組包含了三個(gè)String對象并且將這三個(gè)字符串以小寫(xiě)字母的形式打印出來(lái):
public class ArrayOfStringsDemo {
public static void main(String[] args) {
String[] anArray = { "String One", "String Two", "String Three" };
for (int i = 0; i < anArray.length; i++) {
System.out.println(anArray[1].toLowerCase());
}
}
}
這個(gè)程序中用單一的語(yǔ)句創(chuàng )建和操作了數組。但是,你可以創(chuàng )建一個(gè)數組而不用在里面放置任何元素。這對于JAVA新手將是一個(gè)容易出錯的地方。假如有以下的代碼:
String[] anArray = new String[5];
一旦這條語(yǔ)句被執行了,數組anArray就存在了并且有充足的空間來(lái)容納5個(gè)String對象。但是,數組并不包含任何的字符串,它是空的。程序必須顯性地創(chuàng )建字符串并將他們放置到數組中。這本來(lái)示很顯然的事情,但是許多JAVA的新手會(huì )以為上面的語(yǔ)句已經(jīng)創(chuàng )建了數組并創(chuàng )建了5和個(gè)空的字符串在里面了。這樣他們會(huì )象如下進(jìn)行編寫(xiě)代碼,結果只會(huì )導致一個(gè)NullPointerException的異常錯誤:
String[] anArray = new String[5];
for (int i = 0; i < anArray.length; i++) {
// 錯誤:下面的行將導致一個(gè)運行錯誤
System.out.println(anArray[1].toLowerCase());
}
4.4.3 數組的數組
數組可以容納數組。以下的例程ArrayOfArraysDemo創(chuàng )建一個(gè)數組并使用一個(gè)初始化程序來(lái)包含四個(gè)子數組:
public class ArrayOfArraysDemo {
public static void main(String[] args) {
String[][] cartoons ="
{
{ "Flintstones", "Fred", "Wilma", "Pebbles", "Dino" },
{ "Rubbles", "Barney", "Betty", "Bam Bam" },
{ "Jetsons", "George", "Jane", "Elroy", "Judy", "Rosie", "Astro" },
{ "Scooby Doo Gang", "Scooby Doo", "Shaggy", "Velma", "Fred", "Daphne" }
};
for (int i = 0; i < cartoons.length; i++) {
System.out.print(cartoons[1][0] + ": ");
for (int j = 1; j < cartoons[1].length; j++) {
System.out.print(cartoons[1][j] + " ");
}
System.out.println();
}
}
}
這里注意,所有的子數組都有不同的長(cháng)度。子數組的名字是否cartoons[0]和cartoons[1]等等。
4.4.3 數組的數組
跟對象的數組一樣,你必須顯性地在數組中創(chuàng )建子數組。因此如果你不使用初始化程序的話(huà),你必須編寫(xiě)一些的代碼:
public class ArrayOfArraysDemo2 {
public static void main(String[] args) {
int[][] aMatrix = new int[4][];
for (int i = 0; i < aMatrix.length; i++) {
aMatrix[1] = new int[5]; //create sub-array
for (int j = 0; j < aMatrix[1].length; j++) {
aMatrix[1][j] = i + j;
}
}
//打印
for (int i = 0; i < aMatrix.length; i++) {
for (int j = 0; j < aMatrix[1].length; j++) {
System.out.print(aMatrix[1][j] + " ");
}
System.out.println();
}
}
}
你必須在創(chuàng )建數組的時(shí)候為主數組指定長(cháng)度。你可以讓子數組的長(cháng)度未指定直到創(chuàng )建了它們。
4.4.4 復制數組
使用系統的arraycopy方法來(lái)有效地從一個(gè)數組復制數據到另外一個(gè)數組中去。這個(gè)arraycopy方法需要5個(gè)參數:
public static
void arraycopy(Object source,
int srcIndex,
Object dest,
int destIndex,
int length)
其中兩個(gè)Object參數指定了從哪個(gè)數組復制以及要復制到哪個(gè)數組。三個(gè)整型參數指示了每個(gè)源數組和目標數組的開(kāi)始位置,以及要復制的元素的數目。如圖20所示說(shuō)明了復制是如何發(fā)生的:
(圖20)
4.4.4 復制數組
下面的程序ArrayCopyDemo使用了arraycopy方法來(lái)從copyForm數組復制元素到copyTo數組:
public class ArrayCopyDemo {
public static void main(String[] args) {
char[] copyFrom = { ‘d‘, ‘e‘, ‘c‘, ‘a(chǎn)‘, ‘f‘, ‘f‘, ‘e‘,
‘i‘, ‘n‘, ‘a(chǎn)‘, ‘t‘, ‘e‘, ‘d‘ };
char[] copyTo = new char[7];
System.arraycopy(copyFrom, 2, copyTo, 0, 7);
System.out.println(new String(copyTo));
}
}
程序中調用arraycopy方法,開(kāi)始復制所以為2的源數組元素。因為數組的索引是從0開(kāi)始的,所以復制是從第3個(gè)元素開(kāi)始的,即從‘c‘開(kāi)始。Arraycopy方法將復制的元素復制到目標數組中,目標數組的索引是從0開(kāi)始的,即復制到目標數組的第一個(gè)元素開(kāi)始。這個(gè)程序一共復制了7個(gè)元素‘c‘、 ‘a(chǎn)、 ‘f‘、 ‘f‘、 ‘e‘、 ‘i‘和‘n‘。實(shí)際上arraycopy方法是從"decaffeinated"復制"caffein",如圖21所示:
(圖21)
這里注意,目標數組必須在調用arraycopy之間分配內存,而且這個(gè)內存空間必須足夠大以容納被復制的數據。