我這段時間也在跟老公辦理隨遷,也真是給氣得不行。
前樓主是寫得是很詳細(xì),但我想再問一下計劃生育證明,去派出所交資料就說差計劃生育證明,但我去深圳的我戶口的街道辦去辦理,又要說要老公老家當(dāng)?shù)貞艨谒诘氐挠媱澤C明,深圳這邊的才能開。還需要我戶口本的首頁。要不我這邊的街道辦不給開計劃生育證明。
所以請各位知道的能盡快幫忙告訴。非常的感謝。
re: JXL操作Excel[未登錄] 蘋果 2008-05-29 11:49
簡練!精煉!易懂! 好東西,值得學(xué)習(xí)!
謝謝,也給我發(fā)一份吧!
steven.yj@163.com
Map:關(guān)心唯一標(biāo)識符。把唯一鍵(ID)映射為具體值,當(dāng)然,鍵和值二者都是對象。這里,位于Map中的鍵基于鍵的散列碼,因此,hashCode()設(shè)計越有效,訪問性能越好。
HashMap:未分類未排序
適合:需要Map,而不關(guān)心其順序(當(dāng)遍歷它時),則HashMap是一種方法,其他映射增加更多的開銷。HashMap允許在一個集合中有一個null鍵和在一個集合中有多個null值。
Hashtable:是HashMap的同步版本。
記住:不要同步類,所謂同步,是指同步該類的主要方法。HashMap允許有null值和一個null鍵,但是Hashtable不允許有任何內(nèi)容為null。
LinkedHashMap:維護(hù)插入順序(或者訪問順序)。添加和刪除元素比HashMap慢,但是遍歷得更快。
TreeMap:分類排序。
所謂的有序就是你能夠按照某種特定的(而不是隨機(jī)的)順序遍歷這個集合。所謂的分類是指按照自然順序分類的集合。排序的集合如果使用自然順序或者在分類集合的構(gòu)造函數(shù)中定義排序規(guī)則,就認(rèn)為是分類的。
Set:關(guān)心唯一性——它不允許重復(fù)。equals()方法確定兩個對象是否完全相同。
HashSet: 未排序未分類,它使用被插入對象的散列碼。因此,hashCode()設(shè)計越有效,訪問性能越好。
適合:需要集合不具有任何重復(fù)值,并且遍歷它不關(guān)心順序時。
LinkedHashSet:LinkedHashSet是HashSet的排序版本。可以構(gòu)造一個按元素的訪問順序排序而不是插入順序排序的LinkedHashSet。
適合:當(dāng)關(guān)心遍歷順序時。如果想建立最近最少使用緩存
TreeSet: 排序、分類。使用一種Red-Black樹結(jié)構(gòu),并保證元素將按照元素的自然順序(可以在構(gòu)造函數(shù)里提供規(guī)則)進(jìn)行升序排列。
List: List只關(guān)心索引。所有三種List設(shè)計都是按照索引位置排序
ArrayLsit:
可以看做一個可增長的數(shù)組,特點(diǎn)是快速遍歷和快速隨機(jī)訪問。排序但沒有分類。
適合場所:需要快速遍歷但不可能做大量的插入和刪除
Vector:
基本與ArrayList相同,但是,為了安全起見,Vector()方法被同步了。通常會使用ArrayList而不是Vector,以免不必要的性能損失。如果確實(shí)需要線程安全,在Collections類中有些實(shí)用方法能夠解決。
LinkedList:按照索引位置排序,它象ArrayList一樣,除了元素相互之間是雙鏈接之外。這種鏈接為從頭到尾添加和刪除提供新的方法(除了List接口得到的之外),適合用于設(shè)計棧和隊列。
LinkedList遍歷可能比ArrayList慢,適合:需要快速插入和刪除。
re: 【Java面試題集錦系列一】 蘋果 2005-06-24 15:11
垃圾收集器
java的垃圾收集器為內(nèi)存管理提供了一種自動解決方案。在多數(shù)情況下,它把你從必須為應(yīng)用程序添加所有內(nèi)存管理中解脫出來。自動垃圾收集的缺點(diǎn)是不能完全控制它什么時候執(zhí)行以及什么時候不執(zhí)行。
堆是java對象所在的內(nèi)存部分,它是垃圾收集處理所涉及的一塊也是唯一的一塊內(nèi)存。所有的垃圾收集考慮的是要確保堆有盡可能多的自由空間。問題的核心就是要刪除運(yùn)行的java程序不能再到達(dá)的任何對象。當(dāng)垃圾收集器運(yùn)行時,其目的時查找和刪除不能被訪問的對象,如果把java程序看作是處于一個這樣的固定循環(huán)中:創(chuàng)建它所需的對象(這要占用堆上的空間),之后當(dāng)不再需要他們時廢棄它們,創(chuàng)建新的對象,再廢棄它們,如此循環(huán),這個問題中缺少的一部分是垃圾收集器。當(dāng)它運(yùn)行時,它從內(nèi)存中查找那些被廢棄的對象,并刪除它們,這樣使使用內(nèi)存和釋放內(nèi)存的循環(huán)能夠繼續(xù)。
1。垃圾收集器什么時候運(yùn)行?
垃圾收集器受JVM控制,JVM決定什么時候運(yùn)行垃圾收集器。從Java程序內(nèi)可以請求JVM運(yùn)行垃圾收集器,但是,在任何情況下都無法保障JVM會答應(yīng)你的請求。JVM通常會在它感到內(nèi)存減少時運(yùn)行垃圾收集器。經(jīng)驗(yàn)告訴我們:當(dāng)java程序請求進(jìn)行垃圾收集時,JVM通常會在短期內(nèi)響應(yīng)請求,但這沒有任何保障。剛好在你認(rèn)為可以依靠它時,JVM可能會忽略你的請求。
2.GC怎樣工作?
什么時候?qū)ο笞兊梅侠占瘲l件?每個java程序有一個或多個線程,每個線程都有其自己的小執(zhí)行棧。通常,在一個java程序中至少要運(yùn)行一個線程,即棧底部main()方法的線程。出了有其自己的小執(zhí)行棧外,每個線程都有其自己的生命周期。線程可以是死的或活的,當(dāng)沒有任何活線程能夠訪問一個對象時,該對象就符合垃圾收集條件。
根據(jù)這一定義,GC做一些不可思議的未知操作,當(dāng)它發(fā)現(xiàn)一個對象不能被任何活線程訪問時,它將認(rèn)為該對象符合刪除條件,它可能在某時刪除它(它也可能不刪除它)。所謂到達(dá)一個對象,實(shí)際上是有一個可到達(dá)的引用變量引用所討論的對象。如果我們的java程序有一個引用變量引用一個對象,并且該引用變量可用于一個活線程,則該對象被認(rèn)為是可到達(dá)的。
注意:一個java程序能夠耗盡內(nèi)存。垃圾收集系統(tǒng)嘗試在對象不被使用時把它們從內(nèi)存中刪除。然而,如果保持太多活對象(被其他活對象引用的對象),系統(tǒng)則會耗盡內(nèi)存。垃圾收集不能保證有足夠的內(nèi)存,它只能保證可以使用的內(nèi)存將盡可能被有效地管理。
3.編寫代碼明確使對象符合搜集條件
怎樣使對象符合垃圾收集條件,怎樣在必要時強(qiáng)制執(zhí)行垃圾收集,怎樣執(zhí)行額外地清理?
1)空引用 把引用該對象的引用變量設(shè)置為null,使沒有對它的可到達(dá)引用
public class GarbageTruck {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("hello");
System.out.println(sb);
//The StringBuffer object is not eligible for collection
sb = null;
//Now the StringBuffer object is eligible for collection
}
}
2)重新為引用變量賦值
可以通過設(shè)置引用變量引用另一個對象來解除該引用變量與一個對象間的引用關(guān)系。
class GarbageTruck {
public static void main(String [] args) {
StringBuffer s1= new StringBuffer("hello");
StringBuffer s2= new StringBuffer(goodbye");
System.out.println(s1);
//At this point the StringBuffer "hello" is not eligible
s1=s2;//Redirects s1 to refer to the "goodbye" object
//Now the StringBuffer "hello" is eligible for collection
在方法內(nèi)創(chuàng)建對象也要考慮一下。當(dāng)調(diào)用方法時,所創(chuàng)建的任何局部變量只在該方法期間存在。一旦該方法返回,在這個方法那創(chuàng)建的對象就符合垃圾收集條件。然而,有一種明顯的例外情況,如果一個對象從一個方法被返回,其引用可能在調(diào)用它的方法內(nèi)被賦予一個引用變量,因此它不符合搜集條件。請看下面代碼:
import java.util.Date;
public class GarbageFactory {
public static void main(String[] args) {
Date d = getDate();
doComplicatedStuff();
System.out.println("d = "+d);
}
public static getDate() {
Date d2 = new Date();
String now = d2.toString();
System.out.println(now);
return d2;
}
}
在方法getDate()中,創(chuàng)建了兩個對象,一個Date對象和一個包含日期信息的String對象。因?yàn)樵摲椒ǚ祷谼ate對象,所以它將不符合搜集條件,即使在該方法完成之后。然而String對象將符合條件,即使沒有明確把now變量設(shè)置為null。
3.隔離引用
一般來說,我們把正在計算機(jī)中執(zhí)行的程序叫做"進(jìn)程"(Process) ,而不將其
稱為程序(Program)。所謂"線程"(Thread),是"進(jìn)程"中某個單一順序的控制流。
新興的操作系統(tǒng),如Mac,Windows NT,Windows 95等,大多采用多線程的概念,把線
程視為基本執(zhí)行單位。線程也是Java中的相當(dāng)重要的組成部分之一。
甚至最簡單的Applet也是由多個線程來完成的。在Java中,任何一個Applet的
paint()和update()方法都是由AWT(Abstract Window Toolkit)繪圖與事件處理線
程調(diào)用的,而Applet 主要的里程碑方法——init(),start(),stop()和destory()
——是由執(zhí)行該Applet的應(yīng)用調(diào)用的。
單線程的概念沒有什么新的地方,真正有趣的是在一個程序中同時使用多個線
程來完成不同的任務(wù)。某些地方用輕量進(jìn)程(Lightweig ht Process)來代替線程
,線程與真正進(jìn)程的相似性在于它們都是單一順序控制流。然而線程被認(rèn)為輕量是
由于它運(yùn)行于整個程序的上下文內(nèi),能使用整個程序共有的資源和程序環(huán)境。
作為單一順序控制流,在運(yùn)行的程序內(nèi)線程必須擁有一些資源作為必要的開銷
。例如,必須有執(zhí)行堆棧和程序計數(shù)器。在線程內(nèi)執(zhí)行的代碼只在它的上下文中起
作用,因此某些地方用"執(zhí)行上下文"來代替"線程"。
2.線程屬性
為了正確有效地使用線程,必須理解線程的各個方面并了解Java 實(shí)時系統(tǒng)。
必須知道如何提供線程體、線程的生命周期、實(shí)時系統(tǒng)如 何調(diào)度線程、線程組、
什么是幽靈線程(Demo nThread)。
(1)線程體
所有的操作都發(fā)生在線程體中,在Java中線程體是從Thread類繼承的run()方
法,或?qū)崿F(xiàn)Runnable接口的類中的run()方法。當(dāng)線程產(chǎn)生并初始化后,實(shí)時系統(tǒng)調(diào)
用它的run()方法。run()方法內(nèi)的代碼實(shí)現(xiàn)所產(chǎn)生線程的行為,它是線程的主要部
分。
(2)線程狀態(tài)
附圖表示了線程在它的生命周期內(nèi)的任何時刻所能處的狀態(tài)以及引起狀態(tài)改
變的方法。這圖并不是完整的有限狀態(tài)圖,但基本概括了線程中比較感興趣和普遍
的方面。以下討論有關(guān)線程生命周期以此為據(jù)。
●新線程態(tài)(New Thread)
產(chǎn)生一個Thread對象就生成一個新線程。當(dāng)線程處于"新線程"狀態(tài)時,僅僅是
一個空線程對象,它還沒有分配到系統(tǒng)資源。因此只能啟動或終止它。任何其他操
作都會引發(fā)異常。
●可運(yùn)行態(tài)(Runnable)
start()方法產(chǎn)生運(yùn)行線程所必須的資源,調(diào)度線程執(zhí)行,并且調(diào)用線程的run
()方法。在這時線程處于可運(yùn)行態(tài)。該狀態(tài)不稱為運(yùn)行態(tài)是因?yàn)檫@時的線程并不
總是一直占用處理機(jī)。特別是對于只有一個處理機(jī)的PC而言,任何時刻只能有一個
處于可運(yùn)行態(tài)的線程占用處理 機(jī)。Java通過調(diào)度來實(shí)現(xiàn)多線程對處理機(jī)的共享。
●非運(yùn)行態(tài)(Not Runnable)
當(dāng)以下事件發(fā)生時,線程進(jìn)入非運(yùn)行態(tài)。
①suspend()方法被調(diào)用;
②sleep()方法被調(diào)用;
③線程使用wait()來等待條件變量;
④線程處于I/O等待。
●死亡態(tài)(Dead)
當(dāng)run()方法返回,或別的線程調(diào)用stop()方法,線程進(jìn)入死亡態(tài) 。通常Appl
et使用它的stop()方法來終止它產(chǎn)生的所有線程。
(3)線程優(yōu)先級
雖然我們說線程是并發(fā)運(yùn)行的。然而事實(shí)常常并非如此。正如前面談到的,當(dāng)
系統(tǒng)中只有一個CPU時,以某種順序在單CPU情況下執(zhí)行多線程被稱為調(diào)度(schedu
ling)。Java采用的是一種簡單、固定的調(diào)度法,即固定優(yōu)先級調(diào)度。這種算法是
根據(jù)處于可運(yùn)行態(tài)線程的相對優(yōu)先級來實(shí)行調(diào)度。當(dāng)線程產(chǎn)生時,它繼承原線程的
優(yōu)先級。在需要時可對優(yōu)先級進(jìn)行修改。在任何時刻,如果有多條線程等待運(yùn)行,
系統(tǒng)選擇優(yōu)先級最高的可運(yùn)行線程運(yùn)行。只有當(dāng)它停止、自動放棄、或由于某種
原因成為非運(yùn)行態(tài)低優(yōu)先級的線程才能運(yùn)行。如果兩個線程具有相同的優(yōu)先級,它
們將被交替地運(yùn)行。
Java實(shí)時系統(tǒng)的線程調(diào)度算法還是強(qiáng)制性的,在任何時刻,如果一個比其他線
程優(yōu)先級都高的線程的狀態(tài)變?yōu)榭蛇\(yùn)行態(tài),實(shí)時系統(tǒng)將選擇該線程來運(yùn)行。
(4)幽靈線程
任何一個Java線程都能成為幽靈線程。它是作為運(yùn)行于同一個進(jìn)程內(nèi)的對象
和線程的服務(wù)提供者。例如,HotJava瀏覽器有一個稱為" 后臺圖片閱讀器"的幽靈
線程,它為需要圖片的對象和線程從文件系統(tǒng)或網(wǎng)絡(luò)讀入圖片。
幽靈線程是應(yīng)用中典型的獨(dú)立線程。它為同一應(yīng)用中的其他對象和線程提供
服務(wù)。幽靈線程的run()方法一般都是無限循環(huán),等待服務(wù)請求。
(5)線程組
每個Java線程都是某個線程組的成員。線程組提供一種機(jī)制,使得多個線程集
于一個對象內(nèi),能對它們實(shí)行整體操作。譬如,你能用一個方法調(diào)用來啟動或掛起
組內(nèi)的所有線程。Java線程組由ThreadGroup類實(shí)現(xiàn)。
當(dāng)線程產(chǎn)生時,可以指定線程組或由實(shí)時系統(tǒng)將其放入某個缺省的線程組內(nèi)。
線程只能屬于一個線程組,并且當(dāng)線程產(chǎn)生后不能改變它所屬的線程組。
3.多線程程序
對于多線程的好處這就不多說了。但是,它同樣也帶來了某些新的麻煩。只要
在設(shè)計程序時特別小心留意,克服這些麻煩并不算太困難。
(1)同步線程
許多線程在執(zhí)行中必須考慮與其他線程之間共享數(shù)據(jù)或協(xié)調(diào)執(zhí)行狀態(tài)。這就
需要同步機(jī)制。在Java中每個對象都有一把鎖與之對應(yīng)。但Java不提供單獨(dú)的lo
ck和unlock操作。它由高層的結(jié)構(gòu)隱式實(shí)現(xiàn), 來保證操作的對應(yīng)。(然而,我們注
意到Java虛擬機(jī)提供單獨(dú)的monito renter和monitorexit指令來實(shí)現(xiàn)lock和unlo
ck操作。)
synchronized語句計算一個對象引用,試圖對該對象完成鎖操作, 并且在完成
鎖操作前停止處理。當(dāng)鎖操作完成synchronized語句體得到執(zhí)行。當(dāng)語句體執(zhí)行
完畢(無論正常或異常),解鎖操作自動完成。作為面向?qū)ο蟮恼Z言,synchronized
經(jīng)常與方法連用。一種比較好的辦法是,如果某個變量由一個線程賦值并由別的線
程引用或賦值,那么所有對該變量的訪問都必須在某個synchromized語句或synch
ronized方法內(nèi)。
現(xiàn)在假設(shè)一種情況:線程1與線程2都要訪問某個數(shù)據(jù)區(qū),并且要求線程1的訪
問先于線程2, 則這時僅用synchronized是不能解決問題的。這在Unix或Windows
NT中可用Simaphore來實(shí)現(xiàn)。而Java并不提供。在Java中提供的是wait()和noti
fy()機(jī)制。使用如下:
synchronized method-1(…){ call by thread 1.
∥access data area;
available=true;
notify()
}
synchronized method-2(…){∥call by thread 2.
while(!available)
try{
wait();∥wait for notify().
}catch (Interrupted Exception e){
}
∥access data area
}
其中available是類成員變量,置初值為false。
如果在method-2中檢查available為假,則調(diào)用wait()。wait()的作用是使線
程2進(jìn)入非運(yùn)行態(tài),并且解鎖。在這種情況下,method-1可以被線程1調(diào)用。當(dāng)執(zhí)行
notify()后。線程2由非運(yùn)行態(tài)轉(zhuǎn)變?yōu)榭蛇\(yùn)行態(tài)。當(dāng)method-1調(diào)用返回后。線程2
可重新對該對象加鎖,加鎖成功后執(zhí)行wait()返回后的指令。這種機(jī)制也能適用于
其他更復(fù)雜的情況。
(2)死鎖
如果程序中有幾個競爭資源的并發(fā)線程,那么保證均衡是很重要的。系統(tǒng)均衡
是指每個線程在執(zhí)行過程中都能充分訪問有限的資源。系統(tǒng)中沒有餓死和死鎖的
線程。Java并不提供對死鎖的檢測機(jī)制。對大多數(shù)的Java程序員來說防止死鎖是
一種較好的選擇。最簡單的防止死鎖的方法是對競爭的資源引入序號,如果一個線
程需要幾個資源,那么它必須先得到小序號的資源,再申請大序號的資源。
4.小結(jié)
線程是Java中的重要內(nèi)容,多線程是Java的一個特點(diǎn)。雖然Java的同步互斥不
如某些系統(tǒng)那么豐富,但適當(dāng)?shù)厥褂盟鼈円材苁盏綕M意的效果。
re: 【Java面試題集錦系列一】 蘋果 2005-06-23 21:49
Java線程及同步(synchronized)樣例代碼
--------------------------------------------------------------------------------
Java線程及同步(synchronized)樣例代碼
import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;
public class TestThread extends Thread
{
private static Integer threadCounterLock; //用于同步,防止數(shù)據(jù)被寫亂
private static int threadCount; //本類的線程計數(shù)器
static
{
threadCount = 0;
threadCounterLock = new Integer(0);
}
public TestThread()
{
super();
}
public synchronized static void incThreadCount()
{
threadCount++;
System.out.println("thread count after enter: " + threadCount);
}
public synchronized static void decThreadCount()
{
threadCount--;
System.out.println("thread count after leave: " + threadCount);
}
public void run()
{
synchronized(threadCounterLock) //同步
{
threadCount++;
System.out.println("thread count after enter: " + threadCount);
}
//incThreadCount(); //和上面的語句塊是等價的
final long nSleepMilliSecs = 1000; //循環(huán)中的休眠時間
long nCurrentTime = System.currentTimeMillis();
long nEndTime = nCurrentTime + 30000; //運(yùn)行截止時間
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try
{
while (nCurrentTime < nEndTime)
{
nCurrentTime = System.currentTimeMillis();
System.out.println("Thread " + this.hashCode() + ", current time: " + simpleDateFormat.format(new Date(nCurrentTime)));
try
{
sleep(nSleepMilliSecs);
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
}
}
finally
{
synchronized(threadCounterLock) //同步
{
threadCount--;
System.out.println("thread count after leave: " + threadCount);
}
//decThreadCount(); //和上面的語句塊是等價的
}
}
public static void main(String[] args)
{
TestThread[] testThread = new TestThread[2];
for (int i=0; i {
testThread[i] = new TestThread();
testThread[i].start();
}
}
}
同步就是簡單的說我用的時候你不能用,大家用的要是一樣的就這樣!
比如說有只蘋果很好吃,我拉起來咬一口,放下,你再拉起咬一口,這就同步了,要是大家一起咬,呵呵,那就結(jié)婚吧,婚禮上常能看到這個,也不怕咬著嘴,嘻嘻嘻!
舉個例子,現(xiàn)在有個類,類中有一個私有成員一個蘋果,兩個方法一個看,一個吃。
現(xiàn)在不同步,我一“看”,哈哈一個蘋果,我“吃”四分之一了
你一“看”,哈哈一個蘋果,也“吃”四分之一了。
可能的情況就是都是看到一個蘋果但我的吃方法用在你的之前,所以可能你只能吃到3/4的1/4也就是3/16個而不是1/4個蘋果了。
現(xiàn)在加入同步鎖,我在吃的時候你看被鎖,等吃完了,你再看,啊3/4個蘋果,吃1/3好了了,就這樣!
re: 【Java面試題集錦系列一】 蘋果 2005-06-23 21:48
內(nèi)部類
內(nèi)部類的主要優(yōu)點(diǎn)之一是內(nèi)部類實(shí)例與外部類實(shí)例共享一種“特殊關(guān)系”。這種特殊關(guān)系為內(nèi)部類中的代碼提供對封裝(外部)類成員的訪問,就好象內(nèi)部類是外部類的一部分。不僅是“一部分”,而且是外部類一個羽翼豐滿、帶著卡片的成員。內(nèi)部類實(shí)例可以訪問外部類的所有成員,甚至哪些被標(biāo)識為private的成員。
Java群體每天都在擴(kuò)大,它既包括一些世界最大的ISV,也包括公司CIO、信息技術(shù)人員、系統(tǒng)分析人員、C/S開發(fā)人員、編程人員、多媒體設(shè)計者、市場行銷人員、教育工作者、經(jīng)理、影視生產(chǎn)者甚至業(yè)余愛好者等廣泛的用戶。從傳統(tǒng)上看,這樣一些人在一起有效地工作是不多見的。當(dāng)我們談到開放系統(tǒng)時,我們往往是就已發(fā)表的API及規(guī)格,或者源碼的可得性,或者硬件、聯(lián)網(wǎng)及操作系統(tǒng)而言的,沒有一個人是從人的開放意義上來談的。Java完成了開放系統(tǒng)的閉合鏈。它開發(fā)了人力資源,而反過來又開辟了共同工作的道路。
一談到Java,人們馬上會想起一種類似于C++的、適用于分布環(huán)境的面向?qū)ο缶幊陶Z言,想到這種語言的簡單、穩(wěn)定、安全、與體系結(jié)構(gòu)無關(guān)、可移植、可解釋、高性能、多線程和動態(tài)性等特征。這些都是Java作為一種程序設(shè)計語言的主要特征。
Java是由Sun公司的一個技術(shù)小組研制出來的。在實(shí)現(xiàn)Java語言的過程中,Sun小組的技術(shù)人員很快就意識到:C++無法成為一種完全面向?qū)ο蟮摹⒕W(wǎng)絡(luò)化的開發(fā)語言。C++是通過給原先的C語言增加面向?qū)ο蠊δ芏_發(fā)出來的,因此,它存在著先天不足。這主要體現(xiàn)在C++種類繁多,功能大量冗余,同時又沒有任何一種C++編譯器能夠支持它的全部功能。鑒于這種情況,Sun公司的技術(shù)人員決定不擴(kuò)充C++,而開發(fā)一種全新的計算機(jī)語言(Java的前身Oak)。但是,C++已經(jīng)成了大多數(shù)編程人員所熟練掌握的語言,Java的設(shè)計顯然不能無視這個現(xiàn)實(shí)。如果Java和C++之間的差別過大,那么程序員們在學(xué)會這種語言的過程中無疑要花費(fèi)大量的時間和精力。因此,Java保留了盡可能多的C++風(fēng)格。
Java自誕生起,為網(wǎng)絡(luò)用戶創(chuàng)造了無數(shù)客戶端的小應(yīng)用程序,由于這類應(yīng)用程序效果良好、數(shù)量巨大,以至于許多用戶想到Java編程語言時,會在腦海中出現(xiàn)一個不完全正確的印象-Java是用來編寫小的客戶端程序的。其實(shí),隨著技術(shù)的進(jìn)步,Java語言正在逐步改變自己執(zhí)行效率較低、無法擔(dān)任企業(yè)關(guān)鍵計算任務(wù)的形象,不斷向計算技術(shù)的核心地帶前進(jìn)。今天的Java技術(shù)正沿著網(wǎng)絡(luò)滲入各個應(yīng)用領(lǐng)域。
企業(yè)計算:企業(yè)計算是Java最重要的技術(shù)主題。Sun公司已經(jīng)公布了企業(yè)JavaBean(EJB,Enterprise JavaBean)的規(guī)格,隨后眾多公司開始開發(fā)企業(yè)應(yīng)用領(lǐng)域的Java技術(shù)。IBM公司也已經(jīng)為Windows NT開發(fā)了IBM HPCJ(High Performance Compiler for Java)12.0版,同時研制了IBM JDK(JavaDevelopment Kit)for Windows NT,Novell公司也在宣布了一個新的服務(wù)器端的企業(yè)Java平臺,而Sun公司也在積極地升級自己的JDK系統(tǒng),這個形勢表明,Java正在穩(wěn)步走向企業(yè)高端計算。對于Java來說,與其它編程語言爭奪企業(yè)計算主力編程工具的優(yōu)勢在于:其一,Java在進(jìn)行面向?qū)ο蟮木幊坦ぷ鲿r,比其它的編程語言如C++更加簡單,因此保證了編程的高效率,減少了編程投入;其二,Java虛擬機(jī)技術(shù)所提供的"一次編程,到處使用"的跨平臺能力非常適合網(wǎng)絡(luò)環(huán)境,這給Java在網(wǎng)絡(luò)服務(wù)器端的發(fā)展提供了便利條件;其三,Java擁有強(qiáng)大的提供商和支持者隊伍,該隊伍包括IBM、Oracle、Novell、Sybase和Netscape等公司。
提速運(yùn)行:許多企業(yè)的應(yīng)用開發(fā)人員非常喜愛Java的語言特性,但是在開發(fā)重要系統(tǒng)時,語言特性和執(zhí)行效率之間的抉擇往往令人傷透腦筋。在關(guān)鍵計算中,用戶可能并不在乎數(shù)據(jù)如何壓縮或者運(yùn)行的延遲關(guān)系如何設(shè)置,但是對程序的運(yùn)行速度卻非常重視,這使廠商將Java的編譯策略開發(fā)放在了首位。現(xiàn)在的Java語言,其執(zhí)行方式已經(jīng)不僅僅是解釋執(zhí)行方式了,即時編譯器(JITC、just-in-time compiler)技術(shù)和原型編譯技術(shù)已經(jīng)被許多廠家采用,包括Sun、IBM、Oracle以及Netscape等公司在內(nèi)的技術(shù)提供商正在利用這些技術(shù)逐步提高Java的執(zhí)行速度,其中IBM公司早已將Java虛擬機(jī)(JVM,JavaVirtual Machine)、操作系統(tǒng)和硬件的特性有機(jī)的結(jié)合在一起,非常有效地提高了Java的執(zhí)行效率。
嵌入計算:嵌入式Java是一個潛力巨大的應(yīng)用技術(shù),該技術(shù)充分發(fā)揮了Java小巧靈活的特點(diǎn)。以HP公司為例,該公司以自己的方式制造編譯工具和Java虛擬機(jī),其目的是將Java嵌入各種設(shè)備,如打印機(jī)、醫(yī)學(xué)監(jiān)視器和自動提款機(jī)等。嵌入設(shè)備依靠一個實(shí)時操作系統(tǒng)來處理某一個實(shí)時生效的事件,Java被嵌入這些設(shè)備后,通過實(shí)時擴(kuò)展(real-time extension)開始發(fā)揮作用,使設(shè)備具備了一定的智能性,增強(qiáng)了嵌入設(shè)備的可管理性和可用性,大大提高了設(shè)備的工作效率。各廠商對這一潛力巨大的市場都非常重視,目前該市場缺乏的是一個標(biāo)準(zhǔn),如果存在標(biāo)準(zhǔn)的話,相信很快就會有大量使用嵌入Java技術(shù)的設(shè)備上市。
微軟剛剛發(fā)行的Windows XP放棄了對Java的支持,但Java能夠獨(dú)立運(yùn)行于很多操作平臺上,其中也包括Linux,并且在某些特性上要比在Windows上發(fā)揮得更好,我們完全有理由拋棄Windows而選擇使用Linux來做Java開發(fā)。現(xiàn)在,你可以左手拿著Linux,右手拿著Java,然后對面帶微笑手里拿著Windows XP的Bill Gates說:"讓你的XP去見鬼吧!"
對于軟件開發(fā)者來講,任何一種編程語言都不可能是完美的。如果希望更好地理解Java語言,最好的方法是把這種語言與其同類型的語言相比較。既然Java類似于C++,把它同C++進(jìn)行一番比較也是順理成章的事情,哪一個好,哪一個不好,每個開發(fā)人員都有各自的看法。我個人認(rèn)為Java開發(fā)要比C++好一些。當(dāng)然每個人的看法和喜好是不同的。后面的文章將向大家介紹Java和C++的不同和對其的改進(jìn)。孰強(qiáng)孰弱,大家自然就會明白了。
我們知道,Java一開始采用C++的語法格式,基本上是為了讓程序設(shè)計者可以很快地熟悉 Java的語法格式,縮短學(xué)習(xí)Java的時間,畢竟C和C++仍舊是最多人會的一種程序語言。但是如果我們仔細(xì)檢查Java程序語言的許多細(xì)節(jié)設(shè)計,我們可以發(fā)現(xiàn)Java去掉了不少C++的特點(diǎn),并且加入一些新的特性。這些與C++的差異包括:
1.不再有#define、#include等預(yù)處理程序(Preprocessor)的功能
C++語言很重要的一個特點(diǎn)就是它的預(yù)處理程序。有些其他程序語言雖然也加入了#include的功能,但是還是欠缺處理宏(Macro)的能力。#define的功能在Java中我們可以用定義常數(shù)(constant)的方式來取代,而#include在Java中是不需要的,因?yàn)樵贘ava中程序在執(zhí)行時,會把類型數(shù)據(jù)記錄在對象實(shí)體之中,我們不需要靠一些標(biāo)頭文件(header file)來知道我們使用的對象或數(shù)值是屬于什么數(shù)據(jù)類型。
如果你使用C++語言時,只使用預(yù)處理程序的#include和#define功能的話,那么你大概不會覺得Java這樣的設(shè)計對你產(chǎn)生什么樣的困擾,但是如果你是使用C++語言預(yù)處理程序中宏功能的高手,你可能會覺得很不方便,進(jìn)而懷疑Java如此設(shè)計的意義何在。
使用預(yù)處理程序雖然可以很方便地達(dá)到許多功能,但是站在軟件工程的角度上看,對整個軟件的維護(hù)其實(shí)是很不利的。由于C++語言中預(yù)處理程序的功能太過強(qiáng)大,厲害的程序設(shè)計高手常會自行開發(fā)一套只有自己看的懂的宏語言,一旦整個軟件要交給其他人去維護(hù),后繼者很難在短時間內(nèi)了解前一個人所寫下的宏功能,增加軟件開發(fā)時團(tuán)隊工作及日后維護(hù)的困難度。
另外一點(diǎn)則是C++語言的編譯器所看到的程序代碼,其實(shí)和程序設(shè)計者看到的程序代碼是不同的。程序設(shè)計者看到的是尚未經(jīng)過預(yù)處理程序處理過的程序代碼,而編譯器看到的則是預(yù)處理程序處理過的程序代碼,一旦交給預(yù)處理程序處理的宏內(nèi)容有誤,編譯器產(chǎn)生的錯誤信息將不會是程序設(shè)計師所預(yù)料的。而這一點(diǎn)自然也增加了程序在排錯時的困難度。
預(yù)處理程序的存在也造成了閱讀程序的不便。如果你想使用別人已經(jīng)完成的C++語言程序,那么通常你不但要閱讀他所寫下的文件,還必須一并查閱上文件,才能了解其程序的全貌。如果換成是Java程序,只要查看java的程序文件就夠了。
2.不再有structure、union及typedef
事實(shí)上,早在C++中就可以去掉C語言中的structure和union等對復(fù)雜數(shù)據(jù)的自定結(jié)構(gòu)類型,因?yàn)轭?Class)的定義方式可以完全做到這項功能。而typedef也是不必要的,一切都用類就可以了。雖然C++這樣的設(shè)計是為了和C語言兼容,但是使用多余的語言特點(diǎn)不但不必要,而且容易造成對程序認(rèn)識的混淆。
3.不再有函數(shù)
在Java程序語言中,去掉了程序向?qū)дZ言中最重要的單元--函數(shù)(Function)。如果我們以對象向?qū)У挠^念來看待函數(shù),就可以了解函數(shù)在對象向?qū)У母拍钪校遣槐匾摹T趯ο笙驅(qū)У某绦蛴^念里,對象的數(shù)據(jù)才是真正的主體,而處理對象數(shù)據(jù)的方法則必須依附在對象內(nèi)才有意義。因此,去掉函數(shù)并不表示不再有子程序等模組化程 序的概念,相反地,是利用對象中的方法來取代函數(shù),再一次強(qiáng)化對向?qū)У陌l(fā)展策略。
4.不再有多重繼承(Multiplelnheritance)
在C++中,多重繼承是一項很強(qiáng)的功能,但也是一般人難以掌控的部分。去掉多重繼承雖然降低了Java語言的功能,但是也大幅簡化撰寫程序時的困難度。雖然移除了多重繼承的功能,但是Java提供了interface的方式,可以達(dá)到部分多重繼承的功用。所謂的interface基本上定義了一個類的對外溝通的方法原型,以及類內(nèi)部的常 數(shù),和多重繼承不同之處在于interface并不會定義類方法的內(nèi)容,以及類中的變量數(shù)據(jù)。
5.不再有Goto
在程序語言的發(fā)展史上,Goto一直是毀譽(yù)參半的一項功能。在很多時候使用Goto可以大幅減少不必要的程序代碼,但是也由于Goto可以很自由地改變程序的流程,如果冒然地使用,更可能造成程序結(jié)構(gòu)混亂的情況。一般來說,正確使用Goto的例子多出現(xiàn)在循環(huán)內(nèi)部,想要提早結(jié)束某一層循環(huán)。在C語言中,我們可以使用break 或contine來改變某一層循環(huán)的流程, 但如果想要改變兩層以上的環(huán)執(zhí)行流程,不是使用Goto就是以多余的布爾(boolean)變量,配合上一串if-then-else的判斷來達(dá)成。
Java一方面移除了Goto的功能, 而另一方面同時擴(kuò)大了break和continue的功能,可以允許多層循環(huán)的break或continue。如此一來不但避免了濫用Goto的可能性,同時也保存下Goto的好處。
6.不再有OperatorOverloading
在C++中,Operator Overloading同樣也是一項值得討論的設(shè)計。幾乎在所有C++的書中,都會引用一些例子,告訴你使用OperatorOverloading可以使你的程序看起來更為自然。如下面是一個程序設(shè)計師自定義的復(fù)數(shù)類:
//C++中自定義的復(fù)數(shù)類及0pemtor Overloading
class Complex{
public:
Complex(double real,double image){
Real_number=real;
Image_number=image;
}
Complex operator+(Complex&rhs){
Return Complex(rhs.real_number+real_number,
rhs.image_number+image_,nulnbef);
}
private:
doublereal_number //實(shí)部
doublejmage_nunmber; //虛部
}
在這里,如果你使用+來作為復(fù)數(shù)的加法符號,大家都不會有疑義,但是如果你使用的是*或》這樣的符號,那么別人看到你的程序之后,難保不會產(chǎn)生認(rèn)識上的錯誤。這也是Operator Overloading一大問題,當(dāng)大家都對運(yùn)算符賦予自己的定義后,整個程序的可讀性就會大受影響。Operator Overloading的存在并不是必要的,我們一樣可以定義類中的方法來達(dá)到同樣的目的,至于Java去掉這項功能的利弊,恐怕就要讀者自己去評斷了。
7.取消自動類型轉(zhuǎn)換
Java是一個嚴(yán)格進(jìn)行類型檢查的程序語言,對于下面這樣的程序,在C++的編譯器上編譯時最多只會出現(xiàn)警告的信息,但是在Java里則不予通過:
Int aInteger; Double aDouble=2.71828; AInteger = aDouble;
雖然這樣的轉(zhuǎn)型在C++里是合法的,但是也會造成數(shù)據(jù)精確度的損失。Java為了要確定寫程序的人充分地了解這點(diǎn),必須要程序設(shè)計強(qiáng)制轉(zhuǎn)型(type casting),Java的編譯器才會接受:
int aInteger;
doublea Double=2.71828;
aInteger=(int)aDouble;
8.不再有指針
取消指針(Pointer)這樣數(shù)據(jù)類型,可能會讓許多熟悉C++語言的程序設(shè)計師大吃一驚。在C++語言里,靈活地運(yùn)用指針是許多程序設(shè)計師的得意之作,但是占整個除錯時間最久的也是指針的問題。配合上C++對內(nèi)存管理的態(tài)度,程序設(shè)計師必須要自己去追蹤自己向系統(tǒng)要到的內(nèi)存,最后確實(shí)地交還給系統(tǒng),并且在使用指針時,要小心翼翼地注意不要跨過合法的記憶空間,造成Segmentation Fault或General Protection Fault之類的問題。
Java去掉了指針類型,并不表示程序設(shè)計師在開發(fā)高級數(shù)據(jù)結(jié)構(gòu),像堆棧(stack)、 隊列(queue)、二元樹(binarytree)時,都必須要像在傳統(tǒng)Basic上,利用大范圍的數(shù)組來自行模擬系統(tǒng)內(nèi)存,自行建構(gòu)類似指針的表示方式。
相反地,Java提供了和Lisp語言中相似的Reference類型,通過Reference去讀取配置到的內(nèi)存內(nèi)容,可以確保不會去讀取到不屬于自己的內(nèi)存空間,而另一方面,程序的執(zhí)行系統(tǒng)也可以動態(tài)地去做內(nèi)存垃圾回收的工作,將沒有被reference參考到的內(nèi)存空間回收給系統(tǒng)使用。
9.和C++連接
不管Java是多么強(qiáng)大,總是有人需要把它和C++連接起來。因?yàn)橹灰幸粋€新的程序語言或是軟件開發(fā)工具一出現(xiàn),大家就會問:"它是否具有和原有程序庫連接的能力呢?"也因?yàn)镃++語言在電腦界中占了很重要的地位。大家的問題其實(shí)就等于是直接問"它是否可以和C++連接?"。目前在Java中,的確提供了和C++語言連接的方法,它的做法基本上是先將C++語言所寫的程序建構(gòu)成動態(tài)鏈接函數(shù)庫(DynamicLinking Library,DLL),再由Java程序去調(diào)用DLL里的函數(shù)。
這種連接的方式,使得DLL中的函數(shù),從Java的眼光看就是一個"方法"。不過因?yàn)檫@種方法是直接由其他的程序語言所提供,而不是以Java語言所寫的,所以它被稱之為"原生方法"(NativeMethod)。
由于Java Applet一些安全上的限制,所以這種連接外部程序的方法只能用在Java Application內(nèi)。
小結(jié):
事實(shí)上,constant和typedef這兩條語句包含了#define語句的作用。現(xiàn)在,結(jié)構(gòu)和聯(lián)合已經(jīng)被Java的類所代替。刪除這些特性的原因是:由于其希望維持與C語言的向后兼容性,C ++的語言規(guī)范包含了大量冗余。比如,類實(shí)際上就已經(jīng)包括了結(jié)構(gòu)和聯(lián)合的作用,因此這兩種數(shù)據(jù)結(jié)構(gòu)完全可以取消。關(guān)于#define語句,Java語言規(guī)范的制訂者認(rèn)為:盡管該語句的出發(fā)點(diǎn)是為了增強(qiáng)程序的可讀性,但實(shí)際效果卻恰恰相反,它常常導(dǎo)致難讀的代碼,故應(yīng)該予以取消。Java不再支持獨(dú)立函數(shù),因此任何函數(shù)都必須封裝到某個類中。由于人們普遍認(rèn)為, C++所用的超類是非常不穩(wěn)定的,因此Java拋棄了C++中的多繼承并代之以接口。Java的接口指的是,在別的類看來一個類所能實(shí)現(xiàn)的方法。它所顯示的只是一個類的方法或常量和變量 ,而不是這個類的全部結(jié)構(gòu)。
最后,Java還取消了C++中的GOTO語句、操作符重載、自動類型轉(zhuǎn)換及指針數(shù)據(jù)類型。 GOTO語句引起的爭議已經(jīng)有很多年了,可一直陰魂不散,這跟某些程序員對該語句一直情有獨(dú)鐘有關(guān)。C++仍然支持?jǐn)?shù)據(jù)類型的自動轉(zhuǎn)換,但Java要求編程人員顯式實(shí)現(xiàn)數(shù)據(jù)類型之間的轉(zhuǎn)換。自動數(shù)據(jù)類型轉(zhuǎn)換使得兩個數(shù)據(jù)類型互不兼容的變量可以相互賦值,而不需要給出顯式說明。這有時會導(dǎo)致一些問題,其中最常見的是精確度損失。比方說,如果把一個帶符號的32位整數(shù)賦給一個無符號整數(shù),則所有的結(jié)果均為正數(shù)。Java的設(shè)計者們認(rèn)為這很容易引起程序錯誤,從而決定不支持這種轉(zhuǎn)換方式。
Java Q&A
Vector or ArrayList -- which is better?
Find out the difference between Vector and ArrayList
By Tony Sintes
Printer-friendly version | Mail this to a friend
Vector or ArrayList -- which is better and why?
Sometimes Vector is better; sometimes ArrayList is better; sometimes you don't want to use either. I hope you weren't looking for an easy answer because the answer depends upon what you are doing. There are four factors to consider:
API
Synchronization
Data growth
Usage patterns
Let's explore each in turn.
API
In The Java Programming Language (Addison-Wesley, June 2000) Ken Arnold, James Gosling, and David Holmes describe the Vector as an analog to the ArrayList. So, from an API perspective, the two classes are very similar. However, there are still some major differences between the two classes.
Synchronization
Vectors are synchronized. Any method that touches the Vector's contents is thread safe. ArrayList, on the other hand, is unsynchronized, making them, therefore, not thread safe. With that difference in mind, using synchronization will incur a performance hit. So if you don't need a thread-safe collection, use the ArrayList. Why pay the price of synchronization unnecessarily?
Data growth
Internally, both the ArrayList and Vector hold onto their contents using an Array. You need to keep this fact in mind while using either in your programs. When you insert an element into an ArrayList or a Vector, the object will need to expand its internal array if it runs out of room. A Vector defaults to doubling the size of its array, while the ArrayList increases its array size by 50 percent. Depending on how you use these classes, you could end up taking a large performance hit while adding new elements. It's always best to set the object's initial capacity to the largest capacity that your program will need. By carefully setting the capacity, you can avoid paying the penalty needed to resize the internal array later. If you don't know how much data you'll have, but you do know the rate at which it grows, Vector does possess a slight advantage since you can set the increment value.
Usage patterns
Both the ArrayList and Vector are good for retrieving elements from a specific position in the container or for adding and removing elements from the end of the container. All of these operations can be performed in constant time -- O(1). However, adding and removing elements from any other position proves more expensive -- linear to be exact: O(n-i), where n is the number of elements and i is the index of the element added or removed. These operations are more expensive because you have to shift all elements at index i and higher over by one element. So what does this all mean?
It means that if you want to index elements or add and remove elements at the end of the array, use either a Vector or an ArrayList. If you want to do anything else to the contents, go find yourself another container class. For example, the LinkedList can add or remove an element at any position in constant time -- O(1). However, indexing an element is a bit slower -- O(i) where i is the index of the element. Traversing an ArrayList is also easier since you can simply use an index instead of having to create an iterator. The LinkedList also creates an internal object for each element inserted. So you have to be aware of the extra garbage being created.
Finally, in "PRAXIS 41" from Practical Java (Addison-Wesley, Feb. 2000) Peter Haggar suggests that you use a plain old array in place of either Vector or ArrayList -- especially for performance-critical code. By using an array you can avoid synchronization, extra method calls, and suboptimal resizing. You just pay the cost of extra development time.
re: 【Java面試題集錦系列一】 蘋果 2005-06-23 20:52
2.HashMap和Hashtable基本相同,只是HashMap是非同步的,并且允許空值。
ArrayList和Vector的區(qū)別也是ArrayList是非同步的(unsyncronized).
Hashtable和HashMap的區(qū)別:
1.Hashtable是Dictionary的子類,HashMap是Map接口的一個實(shí)現(xiàn)類;
2.Hashtable中的方法是同步的,而HashMap中的方法在缺省情況下是非同步的。即是說,在多線程應(yīng)用程序中,不用專門的操作就安全地可以使用Hashtable了;而對于HashMap,則需要額外的同步機(jī)制。但HashMap的同步問題可通過Collections的一個靜態(tài)方法得到解決:
Map Collections.synchronizedMap(Map m)
這個方法返回一個同步的Map,這個Map封裝了底層的HashMap的所有方法,使得底層的HashMap即使是在多線程的環(huán)境中也是安全的。
3.在HashMap中,null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應(yīng)的值為null。當(dāng)get()方法返回null值時,即可以表示HashMap中沒有該鍵,也可以表示該鍵所對應(yīng)的值為null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵,而應(yīng)該用containsKey()方法來判斷。
Hashtable和HashMap采用的hash/rehash算法都大概一樣,所以性能不會有很大的差異。
re: 【Java面試題集錦系列一】 蘋果 2005-06-16 13:34
下面是我自己的一些注釋:
1.private 只有本類內(nèi)的方法才具有訪問權(quán)。
protected 只有本類內(nèi)的方法、子類以及同一包內(nèi)的其他類才具有訪問權(quán)。
public 公開訪問
final 一個常量或者一個不能被重載的類或方法
finally 一個try塊中總會被執(zhí)行的部分
re: Jena推理功能的展示 蘋果 2005-05-26 21:53
yujian:
我按你上面說的運(yùn)行了一遍,結(jié)果是
list properties of master:
hastuorof
沒有錯誤,你可以再運(yùn)行一遍試試,應(yīng)該不會有錯,如果還不行,我可以把程序發(fā)給你。
re: Jena推理功能的展示 蘋果 2005-05-20 20:26
這個推理程序我用的就是Jena doc中inference小節(jié)中的關(guān)于計算機(jī)的例子,你們沒有嗎?
我們小組的推理工作剛剛開始,所以自己的推理程序還沒有完成。你們有什么問題,我們可以一起探討一下。