盡管Box 類在說明一個類的必要的元素時是有用的,但它實際應用的價值并不大。為了顯示出類的真實的功能,本章將用一個更復雜的例子來說明類的強大功能。如果你回憶起在第2章中講過的面向對象編程的討論,你就會想起對象編程的最重要的好處之一是對數據和操作該數據的代碼的封裝。你已經知道,在Java 中,就是通過類這樣的機制來完成封裝性。在創建一個類時,你正在創建一種新的數據類型,不但要定義數據的屬性,也要定義操作數據的代碼。進一步,方法定義了對該類數據相一致的控制接口。因此,你可以通過類的方法來使用類,而沒有必要擔心它的實現細節或在類的內部數據實際上是如何被管理的。在某種意義上,一個類像“一臺數據引擎”。你可以通過操縱桿來控制使用引擎,而不需要知道引擎內是如何工作的。事實上,既然細節被隱蔽,當需要時,它的內部工作可以被改變。只要你的代碼通過類的方法來使用它,內部的細節可以改變而不會對類的外部帶來負面影響。
為了看看前面討論概念的一個實際的應用,讓我們開發一個封裝的典型例子:堆棧(stack)。堆棧用先進后出的順序存儲數據。堆棧通過兩個傳統的操作來控制:壓棧(push)和出棧(pop)。在堆棧的上面加入一項,用壓棧,從堆棧中取出一項,用出棧。你將看到,將整個堆棧機制封裝是很容易的。
下面是一個叫做Stack的類,實現整數的堆棧。
// This class defines an integer stack that can hold 10 values.
class Stack {int stck[] = new int[10]; int tos;
// Initialize top-of-stack
Stack() {
tos = -1;
}
// Push an item onto the stack void push(int item) {if(tos==9) System.out.println("Stack is full."); else stck[++tos] = item; }
// Pop an item from the stack int pop() {
if(tos < 0) { System.out.println("Stack underflow."); return 0;
}
else
return stck[tos--];
}
}
正如你看到的,Stack類定義了兩個數據項、三個方法。整數堆棧由數組stck存儲。該數組的下標由變量tos 控制,該變量總是包含堆棧頂層的下標。Stack()構造函數將tos 初始化為-1,它指向一個空堆棧。方法push() 將一個項目壓入堆棧。為了重新取回壓入堆棧的項目,調用pop()。既然存取數據通過push()和pop() ,數組中存儲堆棧的事實實際上和使用的堆棧不相關。例如,堆??梢员淮鎯υ谝粋€更復雜的數據結構中,例如一個鏈表,但push()和pop() 定義的接口仍然是一樣的。
下面示例的類TestStack,驗證了Stack類。該類產生兩個整數堆棧,將一些值存入,然后將它們取出。
class TestStack {
public static void main(String args[]) {
Stack mystack1 = new Stack();
Stack mystack2 = new Stack();
// push some numbers onto the stack
for(int i=0; i<10; i++) mystack1.push(i);
for(int i=10; i<20; i++) mystack2.push(i);
// pop those numbers off the stack
System.out.println("Stack in mystack1:");
for(int i=0; i<10; i++)
System.out.println(mystack1.pop());
System.out.println("Stack in mystack2:");
for(int i=0; i<10; i++)
System.out.println(mystack2.pop());
}
}
該程序產生的輸出如下:
Stack in mystack1:
9
8
7
6
5
4
3
2
1
0
Stack in mystack2:
19
18
17
16
15
14
13
12
11
10
你已經看到,每個堆棧中的內容是分離的。
關于Stack 類的最后一點。正如它現在執行的一樣,通過Stack 類外面的代碼可以改變保存堆棧的數組stck 。這樣的Stack 是開放的,容易誤用或損壞。在下一章中,你將會看到如何補救這種情況。
原文轉自:http://www.anti-gravitydesign.com