• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Merlin

            Life was like a box of chocolates. You never know what you're gonna get.

               :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              34 隨筆 :: 0 文章 :: 40 評(píng)論 :: 0 Trackbacks

            2006年7月20日 #

            http://www.putclub.com/index.php
            posted @ 2006-07-20 22:06 Merlin 閱讀(259) | 評(píng)論 (0)編輯 收藏

            2006年7月19日 #

            有可能在閃躲炮彈和執(zhí)行精確攻擊的演練中學(xué)會(huì)繼承、多態(tài)性、事件處理以及內(nèi)部類這些內(nèi)容嗎?Robocode 這個(gè)游戲即將為全世界的 Java 開發(fā)者實(shí)現(xiàn)這個(gè)愿望,它把游戲風(fēng)潮變成了教學(xué)工具,人們對(duì)它的上癮程度令人吃驚。請(qǐng)跟隨 Sing Li 一起拆解 Robocode,同時(shí)著手建造屬于自己的、定制的、小而精悍的戰(zhàn)斗機(jī)器。

            Robocode 是一個(gè)很容易使用的機(jī)器人戰(zhàn)斗仿真器,可以在所有支持 Java 2 的平臺(tái)上運(yùn)行。您創(chuàng)建一個(gè)機(jī)器人,把它放到戰(zhàn)場(chǎng)上,然后讓它同其他開發(fā)者們創(chuàng)建的機(jī)器人對(duì)手拼死戰(zhàn)斗到底。Robocode 里有一些預(yù)先做好的機(jī)器人對(duì)手讓你入門,但一旦您不再需要它們,就可以把您自己創(chuàng)建的機(jī)器人加入到正在世界范圍內(nèi)形成的某個(gè)聯(lián)盟里去和世界最強(qiáng)手對(duì)陣。

            每個(gè) Robocode 參加者都要利用 Java 語(yǔ)言元素創(chuàng)建他或她的機(jī)器人,這樣就使從初學(xué)者到高級(jí)黑客的廣大開發(fā)者都可以參與這一娛樂活動(dòng)。初級(jí)的 Java 的開發(fā)者們可以學(xué)習(xí)一些基礎(chǔ)知識(shí):調(diào)用 API 代碼、閱讀 Javadoc、繼承、內(nèi)部類、事件處理等等。高級(jí)開發(fā)者們可以在構(gòu)建“最優(yōu)品種”的軟件機(jī)器人全球競(jìng)賽中提高他們的編程技巧。在本文中,我們將介紹 Robocode,并指導(dǎo)您從構(gòu)建您平生第一個(gè) Robocode 機(jī)器人開始征服世界。我們還將看一下迷人的“后臺(tái)”機(jī)制,正是它使得 Robocode 起作用。

            下載并安裝 Robocode

            Robocode 是 Mathew Nelson 的智慧之作,他是 IBM Internet 部門 Advanced Technology 的軟件工程師。請(qǐng)首先訪問(wèn) IBM alphaWorks Robocode 頁(yè)面。在這個(gè)頁(yè)面上,您可以找到 Robocode 系統(tǒng)最新的可執(zhí)行文件。這個(gè)分發(fā)包是一個(gè)自包含的安裝文件,在下載該分發(fā)包之后,您就可以使用下面的命令行在您的系統(tǒng)上安裝這個(gè)軟件包(當(dāng)然,我們假定您的機(jī)器上已經(jīng)預(yù)安裝了 Java VM(JDK 1.3.x)):

            java -jar robocode-setup.jar

            ?在安裝過(guò)程中,Robocode 將問(wèn)您是否要使用這個(gè)外部的 Java VM 來(lái)編譯機(jī)器人。您也可以選擇使用作為 Robocode 分發(fā)包一部分而提供的 Jikes 編譯器。

            安裝完成后,您可以通過(guò) shell 腳本(robocode.sh)、批處理文件(robocode.bat)或桌面上的圖標(biāo)來(lái)啟動(dòng) Robocode 系統(tǒng)。此時(shí),戰(zhàn)場(chǎng)將會(huì)出現(xiàn)。在此,您可以通過(guò)菜單調(diào)用 Robot Editor 和 compiler。





            回頁(yè)首


            Robocode 系統(tǒng)組件

            當(dāng)您激活 Robocode 時(shí),將看到兩個(gè)相關(guān)的 GUI 窗口,這兩個(gè)窗口構(gòu)成了 Robocode 的 IDE:

            • 戰(zhàn)場(chǎng)
            • Robot Editor

            圖 1 展示了處于工作狀態(tài)的戰(zhàn)場(chǎng)和 Robot Editor。


            圖 1. Robocode IDE
            Robocode IDE

            戰(zhàn)場(chǎng)是機(jī)器人之間進(jìn)行戰(zhàn)斗直至分出勝負(fù)的場(chǎng)地。主要的仿真引擎被置于其中,并且允許您在這里創(chuàng)建戰(zhàn)斗、保存戰(zhàn)斗以及打開新建的或現(xiàn)有的戰(zhàn)斗。通過(guò)界面區(qū)域內(nèi)的控件,您可以暫停或繼續(xù)戰(zhàn)斗、終止戰(zhàn)斗、消滅任何機(jī)器人個(gè)體或獲取任何機(jī)器人的統(tǒng)計(jì)數(shù)據(jù)。此外,您可以在此屏幕上激活 Robot Editor。

            Robot Editor 是一個(gè)定制的文本編輯器,它可以用于編輯生成機(jī)器人的 Java 源文件。在它的菜單里集成了 Java 編譯器(用于編譯機(jī)器人代碼)以及定制的 Robot 打包器。由 Robot Editor 創(chuàng)建并成功編譯的所有機(jī)器人都會(huì)處于戰(zhàn)場(chǎng)上一個(gè)部署就緒的位置。

            Robocode 里的每個(gè)機(jī)器人都由一個(gè)或多個(gè) Java 類構(gòu)成。這些類可以被壓縮成一個(gè) JAR 包。為此,Robocode 的最新版本提供了一個(gè)可以在戰(zhàn)場(chǎng) GUI 窗口中激活的“Robot Packager”。





            回頁(yè)首


            對(duì) Robocode 機(jī)器人的詳細(xì)分析

            在寫這篇文章時(shí),Robocode 機(jī)器人是一個(gè)圖形化的坦克。圖 2 是一個(gè)典型的 Robocode 機(jī)器人的圖解。


            圖 2. 對(duì) Robocode 機(jī)器人的詳細(xì)分析
            Robocode 機(jī)器人

            請(qǐng)注意,機(jī)器人有一門可以旋轉(zhuǎn)的炮,炮上面的雷達(dá)也是可以旋轉(zhuǎn)的。機(jī)器人坦克車(Vehicle)、炮(Gun)以及雷達(dá)(Radar)都可以單獨(dú)旋轉(zhuǎn),也就是說(shuō),在任何時(shí)刻,機(jī)器人坦克車、炮以及雷達(dá)都可以轉(zhuǎn)向不同的方向。缺省情況下,這些方向是一致的,都指向坦克車運(yùn)動(dòng)的方向。





            回頁(yè)首


            Robot 命令

            Robocode 機(jī)器人的命令集都收錄在 Robocode API Javadoc 中。您將會(huì)發(fā)現(xiàn)這些命令都是 robocode.Robot 類的公共方法。在這一部分,我們將分類討論每個(gè)可用的命令。

            移動(dòng)機(jī)器人、炮和雷達(dá)

            讓我們從移動(dòng)機(jī)器人及其裝備的基本命令開始:

            • turnRight(double degree)turnLeft(double degree) 使機(jī)器人轉(zhuǎn)過(guò)一個(gè)指定的角度。
            • ahead(double distance)back(double distance) 使機(jī)器人移動(dòng)指定的像素點(diǎn)距離;這兩個(gè)方法在機(jī)器人碰到墻或另外一個(gè)機(jī)器人時(shí)即告完成。
            • turnGunRight(double degree)turnGunLeft(double degree) 使炮可以獨(dú)立于坦克車的方向轉(zhuǎn)動(dòng)。
            • turnRadarRight(double degree)turnRadarLeft(double degree) 使炮上面的雷達(dá)轉(zhuǎn)動(dòng),轉(zhuǎn)動(dòng)的方向也獨(dú)立于炮的方向(以及坦克車的方向)。

            這些命令都是在執(zhí)行完畢后才把控制權(quán)交還給程序。此外,轉(zhuǎn)動(dòng)坦克車的時(shí)候,除非通過(guò)調(diào)用下列方法分別指明炮(和雷達(dá))的方向,否則炮(和雷達(dá))的指向也將移動(dòng)。

            • setAdjustGunForRobotTurn(boolean flag) :如果 flag 被設(shè)置成 true,那么坦克車轉(zhuǎn)動(dòng)時(shí),炮保持原來(lái)的方向。
            • setAdjustRadarForRobotTurn(boolean flag) :如果 flag 被設(shè)置成 true,那么坦克車(和炮)轉(zhuǎn)動(dòng)時(shí),雷達(dá)會(huì)保持原來(lái)的方向。
            • setAdjustRadarForGunTurn(boolean flag) :如果 flag 被設(shè)置成 true,那么炮轉(zhuǎn)動(dòng)時(shí),雷達(dá)會(huì)保持原來(lái)的方向。而且,它執(zhí)行的動(dòng)作如同調(diào)用了 setAdjustRadarForRobotTurn(true)

            獲取關(guān)于機(jī)器人的信息

            有許多方法可以得到關(guān)于機(jī)器人的信息。下面簡(jiǎn)單列舉了常用的方法調(diào)用:

            • getX()getY() 可以捕捉到機(jī)器人當(dāng)前的坐標(biāo)。
            • getHeading()getGunHeading()getRadarHeading() 可以得出坦克車、炮或雷達(dá)當(dāng)前的方向,該方向是以角度表示的。
            • getBattleFieldWidth()getBattleFieldHeight() 可以得到當(dāng)前這一回合的戰(zhàn)場(chǎng)尺寸。

            射擊命令

            一旦您掌握了移動(dòng)機(jī)器人以及相關(guān)的武器裝備的方法,您就該考慮射擊和控制損害的任務(wù)了。每個(gè)機(jī)器人在開始時(shí)都有一個(gè)缺省的“能量級(jí)別”,當(dāng)它的能量級(jí)別減小到零的時(shí)候,我們就認(rèn)為這個(gè)機(jī)器人已經(jīng)被消滅了。射擊的時(shí)候,機(jī)器人最多可以用掉三個(gè)能量單位。提供給炮彈的能量越多,對(duì)目標(biāo)機(jī)器人所造成的損害也就越大。 fire(double power)fireBullet(double power) 用來(lái)發(fā)射指定能量(火力)的炮彈。調(diào)用的 fireBullet() 版本返回 robocode.Bullet 對(duì)象的一個(gè)引用,該引用可以用于高級(jí)機(jī)器人。

            事件

            每當(dāng)機(jī)器人在移動(dòng)或轉(zhuǎn)動(dòng)時(shí),雷達(dá)一直處于激活狀態(tài),如果雷達(dá)檢測(cè)到有機(jī)器人在它的范圍內(nèi),就會(huì)觸發(fā)一個(gè)事件。作為機(jī)器人創(chuàng)建者,您有權(quán)選擇處理可能在戰(zhàn)斗中發(fā)生的各類事件。基本的 Robot 類中包括了所有這些事件的缺省處理程序。但是,您可以覆蓋其中任何一個(gè)“什么也不做的”缺省處理程序,然后實(shí)現(xiàn)您自己的定制行為。下面是一些較為常用的事件:

            • ScannedRobotEvent 。通過(guò)覆蓋 onScannedRobot() 方法來(lái)處理 ScannedRobotEvent ;當(dāng)雷達(dá)檢測(cè)到機(jī)器人時(shí),就調(diào)用該方法。
            • HitByBulletEvent 。通過(guò)覆蓋 onHitByBullet() 方法來(lái)處理 HitByBulletEvent ;當(dāng)機(jī)器人被炮彈擊中時(shí),就調(diào)用該方法。
            • HitRobotEvent 。通過(guò)覆蓋 onHitRobot() 方法來(lái)處理 HitRobotEvent ;當(dāng)您的機(jī)器人擊中另外一個(gè)機(jī)器人時(shí),就調(diào)用該方法。
            • HitWallEvent 。通過(guò)覆蓋 onHitWall() 方法來(lái)處理 HitWallEvent ;當(dāng)您的機(jī)器人撞到墻時(shí),就調(diào)用該方法。

            我們只需要知道這些就可以創(chuàng)建一些相當(dāng)復(fù)雜的機(jī)器人了。您可以通過(guò)戰(zhàn)場(chǎng)的幫助菜單或 Robot Editor 的幫助菜單訪問(wèn) Javadoc 中其余的 Robocode API。

            現(xiàn)在,我們?cè)摪褜W(xué)到的知識(shí)付諸實(shí)踐了。





            回頁(yè)首


            創(chuàng)建機(jī)器人

            要?jiǎng)?chuàng)建一個(gè)新的機(jī)器人,請(qǐng)啟動(dòng) Robot Editor 并選擇 File-> New-> Robot。系統(tǒng)將會(huì)提示您輸入機(jī)器人的名稱,這個(gè)名稱將成為 Java 類名。請(qǐng)您在提示符處輸入 DWStraight。接下來(lái),系統(tǒng)還會(huì)提示您輸入一個(gè)獨(dú)一無(wú)二的包前綴,它將用作存放機(jī)器人(還可能有相關(guān)的 Java 文件)的包的名稱。請(qǐng)?jiān)谠撎崾痉庉斎?dw

            Robot Editor 就會(huì)顯示您要控制這個(gè)機(jī)器人需要編寫的 Java 代碼。清單 1 是您將會(huì)看到的代碼的一個(gè)示例:


            清單 1. Robocode 生成的 Robot 代碼
            												
            														package dw;
            import robocode.*;
            
            /**
             * DWStraight - a robot by (developerWorks)
             */
            public class DWStraight extends Robot
            {
                ...  // <<Area 1>>
                /**
                 * run: DWStraight's default behavior
                 */
                public void run() {
                    ... // <<Area 2>>
                    while(true) {
                    ... // <<Area 3>>
                    }
                }
                  ... // <<Area 4>>
                public void onScannedRobot(ScannedRobotEvent e) {
                    fire(1);
                }
            }
            
            												
            										

            突出顯示的區(qū)域就是我們添加控制機(jī)器人的代碼的地方:

            Area 1
            我們可以在這片空白里聲明類作用域變量并設(shè)置這些變量的值。這些變量可以在機(jī)器人的 run() 方法內(nèi)以及其他一些您可能創(chuàng)建的助手方法內(nèi)使用。

            Area 2
            戰(zhàn)斗管理器調(diào)用 run() 方法激活機(jī)器人。典型情況下,run() 方法包括兩個(gè)區(qū)域(即在清單 1 中指出的 Area 2 和 Area 3),您可以在這兩塊空白里添加代碼。您在 Area 2 中加入的代碼每個(gè)機(jī)器人實(shí)例只運(yùn)行一次。這部分代碼通常用于使機(jī)器人先處于一種預(yù)設(shè)狀態(tài)后再開始執(zhí)行重復(fù)行為。

            Area 3
            這是典型的 run() 方法實(shí)現(xiàn)的第二部分。在此,我們將在無(wú)限 while 循環(huán)內(nèi)對(duì)機(jī)器人可能執(zhí)行的重復(fù)行為進(jìn)行編程。

            Area 4
            您可以在這一區(qū)域內(nèi)添加機(jī)器人在 run() 邏輯內(nèi)使用的助手方法。您也可以在此添加您想要覆蓋的任何事件處理程序。例如,清單 1 里的代碼處理 ScannedRobot 事件,每當(dāng)雷達(dá)檢測(cè)到機(jī)器人的時(shí)候,只是直接向其發(fā)射炮彈。

            我們對(duì)第一個(gè)機(jī)器人(DWStraight)的代碼的更新如清單 2 中紅色標(biāo)記所示。


            清單 2. DWStraight 機(jī)器人代碼的增加部分
            												
            														package dw;
            import robocode.*;
            
            public class DWStraight extends Robot
            {
                public void run() {
                    turnLeft(getHeading());
                    while(true) {
                        ahead(1000);
                        turnRight(90);
            
                    }
                }
                     public void onScannedRobot(ScannedRobotEvent e) {
                    fire(1);
                }
                public void onHitByBullet(HitByBulletEvent e) {
                    turnLeft(180);
                }
                  
            }
            
            												
            										

            下面我們逐區(qū)地描述這個(gè)第一個(gè)機(jī)器人將做些什么:

            Area 1我們沒有在這個(gè)機(jī)器人的程序中指定任何類作用域變量。

            Area 2
            為了使機(jī)器人處于已知的狀態(tài),我們通過(guò) turnLeft(getHeading()) 使它轉(zhuǎn)到 0 度的方向。

            Area 3
            在這個(gè)重復(fù)性的部分,我們使用語(yǔ)句 ahead(1000) 讓機(jī)器人盡其所能向前移動(dòng)到最遠(yuǎn)的地方。當(dāng)機(jī)器人撞到墻或其他機(jī)器人時(shí),就會(huì)停下來(lái)。接著,我們通過(guò) turnRight(90) 使它向右轉(zhuǎn)。在重復(fù)執(zhí)行這一行為時(shí),機(jī)器人基本上是在沿著墻按順時(shí)針方向移動(dòng)。

            Area 4
            在此,除處理自動(dòng)生成的 ScannedRobot 事件并向被發(fā)現(xiàn)的機(jī)器人直接射擊之外,我們還會(huì)檢測(cè) HitByBullet 事件,并且讓機(jī)器人在被擊中的時(shí)候轉(zhuǎn)過(guò) 180 度(沿順時(shí)針方向或逆時(shí)針方向)。





            回頁(yè)首


            編譯以及測(cè)試機(jī)器人

            在 Robot Editor 菜單上選擇 Compiler-> Compile編譯您的機(jī)器人代碼。現(xiàn)在我們可以嘗試第一回合的戰(zhàn)斗了。切換回戰(zhàn)場(chǎng)并選擇菜單上的 Battle-> New,將會(huì)出現(xiàn)一個(gè)類似于圖 3 中所示的對(duì)話框。


            圖 3. New Battle 對(duì)話框
            New Battle 對(duì)話框

            請(qǐng)先將我們的機(jī)器人 dw.DWStraight 添加到戰(zhàn)斗中,然后再添加一個(gè)對(duì)手機(jī)器人,比如 sample.SittingDuck。單擊 Finish,戰(zhàn)斗就開始了。不可否認(rèn),同 SittingDuck 戰(zhàn)斗并不怎么有趣,但是您可以目睹這個(gè)叫做 DWStraight 的機(jī)器人在缺省情況下的行為。試試 sample 文件夾里的其他機(jī)器人,看看 DWStraight 同這些機(jī)器人的戰(zhàn)斗情況如何。

            當(dāng)您準(zhǔn)備開始研究另外一個(gè)機(jī)器人的代碼時(shí),請(qǐng)先看看隨 參考資料 中的代碼分發(fā)包一起提供的 dw.DWRotater 這個(gè)機(jī)器人的代碼。在缺省情況下,這個(gè)機(jī)器人將會(huì):

            • 移動(dòng)到戰(zhàn)場(chǎng)中心
            • 一直轉(zhuǎn)動(dòng)它的炮,直到檢測(cè)到機(jī)器人
            • 每次嘗試以不同的角度在離被檢測(cè)到的機(jī)器人前方不遠(yuǎn)的地方射擊
            • 每當(dāng)它被另外一個(gè)機(jī)器人擊中時(shí),它都會(huì)迅速的來(lái)回移動(dòng)

            這段代碼簡(jiǎn)單易懂,所以我們?cè)谶@里就不做分析了,但是我鼓勵(lì)您試驗(yàn)一下。Robocode 中的 sample 包還提供了許多其他機(jī)器人的代碼。

            附加的機(jī)器人支持類

            隨著您設(shè)計(jì)機(jī)器人的水平的提高,機(jī)器人的代碼主體將充分增長(zhǎng)。對(duì)這些代碼的一種模塊化處理方法是把代碼分解成獨(dú)立的 Java 類,然后通過(guò)打包器把這些 Java 類打包成一個(gè)單獨(dú)的包(JAR 文件),并將它包括在您的機(jī)器人分發(fā)包內(nèi)。Robocode 將自動(dòng)在它的 robots 目錄下的包里找到 robot 類。

            其他 Robot 子類

            任何人都可以創(chuàng)建 Robot 子類并添加用于構(gòu)建機(jī)器人的新功能。Robocode 提供了一個(gè)叫做 AdvancedRobotRobot 子類,它允許異步 API 調(diào)用。雖然對(duì) AdvancedRobot 類的描述超出了本文的范圍,但我鼓勵(lì)您在掌握了基本的 Robot 類的操作后,試驗(yàn)一下這個(gè)高級(jí)類。

            設(shè)計(jì) Robocode 的目的

            我碰見了 Robocode 的創(chuàng)建者 Mathew Nelson,向他請(qǐng)教創(chuàng)建 Robocode 最初的設(shè)計(jì)目的。Mat 所說(shuō)的是:“編寫 Robocode 的一部分目的是為了向世界證明:象‘Java 比較慢’以及‘Java 不可以用來(lái)寫游戲’之類的論斷不再正確。我認(rèn)為我證明了這一點(diǎn)。”





            回頁(yè)首


            戰(zhàn)斗仿真器的體系結(jié)構(gòu)

            通過(guò)“在后臺(tái)”對(duì) Robocode 進(jìn)行分析,我們發(fā)現(xiàn)復(fù)雜的仿真引擎既具高性能(為了以現(xiàn)實(shí)的速度生成戰(zhàn)斗)又具靈活性(使創(chuàng)建復(fù)雜的機(jī)器人邏輯不存在障礙)。特別感謝 Robocode 的創(chuàng)建者 Mathew Nelson 無(wú)私的提供了仿真引擎體系結(jié)構(gòu)的內(nèi)部信息。

            利用 Java 平臺(tái)進(jìn)行設(shè)計(jì)

            圖 4 中所示的仿真引擎利用的是大多數(shù)現(xiàn)代的 Java VM 都提供的非搶占式線程技術(shù),并結(jié)合使用了 JDK GUI 和 2D 圖形庫(kù)提供的生成功能。


            圖 4. Robocode 仿真引擎體系結(jié)構(gòu)
            仿真引擎

            請(qǐng)注意,所仿真的每個(gè)機(jī)器人都在它自己的 Java 線程上,它可以在任何可適用的地方利用 VM 本地線程映射機(jī)制。戰(zhàn)斗管理器線程是系統(tǒng)的控制器:它安排仿真并驅(qū)動(dòng)圖形化的生成子系統(tǒng)。圖形化的生成子系統(tǒng)本身是基于 Java 2D 和 AWT 的。

            松散的線程耦合

            為了減少共享資源可能帶來(lái)的問(wèn)題(以及有可能隨之出現(xiàn)的死鎖或阻塞仿真引擎),戰(zhàn)斗管理器線程和機(jī)器人線程之間的耦合應(yīng)當(dāng)非常松散。為了實(shí)現(xiàn)這種松散耦合,每個(gè)機(jī)器人線程都將有屬于自己的事件隊(duì)列。獲取及處理這些事件都是在每個(gè)機(jī)器人自己的線程內(nèi)進(jìn)行。這種基于線程的隊(duì)列有效地消除了戰(zhàn)斗管理器線程和機(jī)器人線程之間(或機(jī)器人線程本身之間)可能存在的任何爭(zhēng)用。

            Robocode 內(nèi)部結(jié)構(gòu)

            您可以把 Robocode 仿真器引擎看作是一個(gè)仿真器程序,該程序在運(yùn)行時(shí)會(huì)使用一些插件(定制機(jī)器人);這些插件可以利用已有的 API( robocode.Robot 類的方法)。實(shí)際上,每個(gè)機(jī)器人都是一個(gè)獨(dú)立的 Java 線程,同時(shí) run() 方法內(nèi)包含了每個(gè)線程上將要執(zhí)行的邏輯。

            在任何時(shí)候,機(jī)器人線程都可以調(diào)用由它的父類 robocoode.Robot 類所提供的 API。典型情況下,這將通過(guò)調(diào)用 Object.wait() 阻塞機(jī)器人線程。

            戰(zhàn)斗管理器線程

            戰(zhàn)斗管理器線程管理機(jī)器人、炮彈及它們?cè)趹?zhàn)場(chǎng)上的生成。仿真“時(shí)鐘”是根據(jù)戰(zhàn)場(chǎng)上生成的幀的數(shù)目來(lái)標(biāo)記的。用戶可以調(diào)整真實(shí)的幀的速度。

            在一個(gè)典型的回合中,戰(zhàn)斗管理器線程喚醒每個(gè)機(jī)器人線程,然后等待機(jī)器人完成它的一輪戰(zhàn)斗(即,再次調(diào)用一個(gè)阻塞 API)。等待的間隔時(shí)間通常是幾十毫秒,即使是最復(fù)雜的機(jī)器人,使用現(xiàn)今典型的系統(tǒng)速度進(jìn)行策略安排和計(jì)算,也只要 1 到 2 毫秒的時(shí)間。

            以下是戰(zhàn)斗管理器線程執(zhí)行的邏輯的偽代碼:


            清單 3. 戰(zhàn)斗管理器的邏輯的偽代碼
            												
            														while (round is not over) do
               call the rendering subsystem to draw robots, bullets, explosions
               for  each robot do
                   wake up the robot
                   wait for it to make a blocking call, up to a max time interval
               end for
               clear all robot event queue
               move bullets, and generate event into robots' event queue if applicable
               move robots, and generate event into robots' event queue if applicable
               do battle housekeeping and generate event into robots' event queue
                     if applicable
               delay for frame rate if necessary
            end do
            
            												
            										

            請(qǐng)注意,在 for 循環(huán)內(nèi)部,戰(zhàn)斗管理器線程的等待時(shí)間不會(huì)超過(guò)最大的時(shí)間間隔。如果機(jī)器人線程沒有及時(shí)調(diào)用阻塞 API(典型情況下是由于一些應(yīng)用程序邏輯錯(cuò)誤或無(wú)限循環(huán)),那么,它將繼續(xù)進(jìn)行戰(zhàn)斗。生成一個(gè) SkippedTurnEvent 并將其加入機(jī)器人事件隊(duì)列中,用來(lái)通知高級(jí)機(jī)器人。

            可替換的生成子系統(tǒng)

            AWT 和 Java 2D 線程就是當(dāng)前實(shí)現(xiàn)中的生成子系統(tǒng),它從戰(zhàn)斗管理器中獲取命令并生成戰(zhàn)場(chǎng)。它同系統(tǒng)的其余部分是完全分離的。我們可以預(yù)見到,在這個(gè)生成子系統(tǒng)將來(lái)的修訂版中,它可以被替換掉(比如,用 3-D 生成器)。在當(dāng)前的實(shí)現(xiàn)中,只要 Robocode 應(yīng)用程序被最小化,生成就禁用了,這可以以更快的速度進(jìn)行仿真。





            回頁(yè)首


            Robocode 的未來(lái)

            通過(guò) alphaWorks Robocode 站點(diǎn)上的一個(gè)討論組(請(qǐng)參閱 參考資料 ),Mathew Nelson 可以同 Robocode 用戶社區(qū)保持緊密的反饋聯(lián)系。許多反饋都并入了真實(shí)的代碼中。Mathew 已計(jì)劃即將要進(jìn)行的一些改進(jìn)有:

            • 通過(guò)不同的物體和障礙來(lái)定制戰(zhàn)場(chǎng)地圖
            • 基于團(tuán)隊(duì)的戰(zhàn)斗
            • 對(duì)聯(lián)賽或聯(lián)盟的集成支持
            • 用戶可選擇坦克車體/炮/雷達(dá)/武器的樣式




            回頁(yè)首


            擋不住的 Robocode 風(fēng)潮

            對(duì)于一個(gè)從 2001 年 7 月 12 日出現(xiàn)在公眾面前的項(xiàng)目,Robocode 的出名簡(jiǎn)直讓人吃驚。盡管最新的可用版本還不到 1.0(在寫這篇文章時(shí)是版本 0.98.2),但它已經(jīng)是全世界的大學(xué)校園以及公司的 PC 機(jī)上頗受歡迎的娛樂活動(dòng)了。Robocode 聯(lián)盟(或 roboleagues)正如雨后春筍般出現(xiàn),在這些聯(lián)盟里,人們通過(guò)因特網(wǎng)讓自己定制的作品相互較量。大學(xué)教授們一直在挖掘 Robocode 的教育特性,并且已經(jīng)把它納入了大學(xué)里的計(jì)算機(jī)科學(xué)課程。在因特網(wǎng)上,Robocode 用戶組、討論列表、FAQ、教程和 Webring 隨處可見。

            顯然,Robocode 已經(jīng)填補(bǔ)了大眾化的寓教于樂領(lǐng)域的空白 ― 它為學(xué)生們和熬夜的工程師們提供簡(jiǎn)便、有趣、非脅迫卻富競(jìng)爭(zhēng)力的方式,釋放他們的創(chuàng)造力,而且有可能實(shí)現(xiàn)他們征服世界的夢(mèng)想。

            posted @ 2006-07-19 20:55 Merlin 閱讀(421) | 評(píng)論 (0)編輯 收藏

            華裔美國(guó)科學(xué)家、前微軟中國(guó)研究院院長(zhǎng)(呵呵,應(yīng)該是前了吧!)李開復(fù)是一位在語(yǔ)音識(shí)別、人工智能、三維圖形和國(guó)際互聯(lián)網(wǎng)多媒體等領(lǐng)域享有很高聲譽(yù)的年輕人。他的成功經(jīng)驗(yàn)和治學(xué)精神引起了我國(guó)許多青年尤其是大學(xué)生的廣泛關(guān)注。在與我國(guó)年輕人的交往過(guò)程中,李開復(fù)歸納出了一些大家共同關(guān)心的問(wèn)題,并結(jié)合自己的學(xué)習(xí)和工作經(jīng)歷,坦誠(chéng)相見,直抒胸臆,寫成了一封給我國(guó)學(xué)生的長(zhǎng)信.相信對(duì)大學(xué)生和青年朋友在如何對(duì)待機(jī)遇、如何對(duì)待學(xué)業(yè)、如何對(duì)待工作、如何對(duì)待他人 、如何對(duì)待自己等諸多方面會(huì)有一些有益的啟示。

            ????我在中國(guó)的這兩年來(lái),工作中最大的享受是到國(guó)內(nèi)各高校與學(xué)生們進(jìn)行交流。這些訪問(wèn)和交流使得我有機(jī)會(huì)與成千上萬(wàn)的青年學(xué)生就他們所關(guān)心的事業(yè)、前途等問(wèn)題進(jìn)行面對(duì)面的溝通。中國(guó)學(xué)生的聰明、好學(xué)和上進(jìn)給我留下了非常深刻的印象。   

              在與這些青年學(xué)生的交流過(guò)程中,我發(fā)現(xiàn)有一些問(wèn)題是大家都十分關(guān)心的。那些已經(jīng)獲得國(guó)外大學(xué)獎(jiǎng)學(xué)金的學(xué)生,大都希望我談一談應(yīng)該如何度過(guò)自己在美國(guó)的學(xué)習(xí)生涯;那些決定留在國(guó)內(nèi)發(fā)展的學(xué)生,非常關(guān)心如何確定一個(gè)正確的方向,并以最快的速度在科研和學(xué)業(yè)方面取得成功;還有那些剛剛踏進(jìn)大學(xué)校門的學(xué)生,則希望我能講給他們一些學(xué)習(xí)、做人的經(jīng)驗(yàn)之談。最近,更有一些學(xué)生關(guān)心網(wǎng)絡(luò)信息產(chǎn)業(yè)的發(fā)展,希望了解美國(guó)的大學(xué)生是如何創(chuàng)業(yè)和致富的。看到這么多雙渴求知識(shí)、充滿希望的眼睛,我突然產(chǎn)生了一種沖動(dòng),那就是給中國(guó)的學(xué)生們寫一封信,將我與同學(xué)們?cè)诮涣鬟^(guò)程中產(chǎn)生的一些想法以及我要對(duì)中國(guó)學(xué)生的一些忠告寫出來(lái),幫助他們?cè)谖磥?lái)的留學(xué)、工作或者創(chuàng)業(yè)的過(guò)程中能夠人格更完美,生活更順利,事業(yè)更成功。   

            堅(jiān)守誠(chéng)信、正直的原則
              我在蘋果公司工作時(shí),曾有一位剛被我提拔的經(jīng)理,由于受到下屬的批評(píng),非常沮喪地要我再找一個(gè)人來(lái)接替他。我問(wèn)他:“你認(rèn)為你的長(zhǎng)處是什么?”他說(shuō):“我自信自己是一個(gè)非常正直的人。”我告訴他:“當(dāng)初我提拔你做經(jīng)理,就是因?yàn)槟闶且粋€(gè)公正無(wú)私的人。管理經(jīng)驗(yàn)和溝通能力是可以在日后工作中學(xué)習(xí)的,但一顆正直的心是無(wú)價(jià)的。”我支持他繼續(xù)干下去,并在管理和溝通技巧方面給予他很多指點(diǎn)和幫助。最終, 他不負(fù)眾望,成為一個(gè)出色的管理人才。   

              與之相反,我曾面試過(guò)一位求職者。他在技術(shù)、管理方面都相當(dāng)出色。但是,在談話之余,他表示,如果我錄取他,他可以把在原來(lái)公司工作時(shí)的一項(xiàng)發(fā)明帶過(guò)來(lái)。隨后他似乎覺察到這樣說(shuō)有些不妥,特做聲明:那些工作是他在下班之后做的,他的老板并不知道。這一番談話之后 ,對(duì)于我而言,不論他的能力和工作水平怎樣,我都肯定不會(huì)錄用他。原因是他缺乏最基本的處世準(zhǔn)則和最起碼的職業(yè)道德:“誠(chéng)實(shí)”和“講信用”。如果雇用這樣的人,誰(shuí)能保證他不會(huì)在這里工作一段時(shí)間后,把在這里的成果也當(dāng)作所謂“業(yè)余之作”而變成向其他公司討好的“貢品”呢?這說(shuō)明,一個(gè)人品不完善的人是不可能成為一個(gè)真正有所作為的人的。
              在美國(guó),中國(guó)學(xué)生的勤奮和優(yōu)秀是出了名的。曾經(jīng)一度是美國(guó)各名校最歡迎的留學(xué)生群體,而最近,卻有一些變化。原因很簡(jiǎn)單,某些中國(guó)學(xué)生拿著讀博士的獎(jiǎng)學(xué)金到了美國(guó),可一旦找到工作機(jī)會(huì),他們就會(huì)馬上申請(qǐng)離開學(xué)校,將自己曾經(jīng)承諾要完成的學(xué)位和研究拋在一邊。這種言行不一的做法已經(jīng)使得美國(guó)一部分教授對(duì)中國(guó)學(xué)生的誠(chéng)信產(chǎn)生了懷疑。應(yīng)該指出,有這種行為的中國(guó)學(xué)生是少數(shù),然而就是這樣的“少數(shù)”,已經(jīng)讓中國(guó)學(xué)生的名譽(yù)受到了極大的損害。另外,目前美國(guó)有些教授不愿理會(huì)部分中國(guó)學(xué)生的推薦信,因?yàn)樗麄冎肋@些推薦信根本就出自學(xué)生自己之手,已無(wú)參考性可言。這也是誠(chéng)信受到損害以后的必然結(jié)果。   

              我在微軟研究院也曾碰到過(guò)類似的問(wèn)題。一位來(lái)這里實(shí)習(xí)的學(xué)生,有一次出乎意料地報(bào)告了一個(gè)非常好的研究結(jié)果。但是,他做的研究結(jié)果別人卻無(wú)法重復(fù)。后來(lái),他的老板發(fā)現(xiàn),這個(gè)學(xué)生對(duì)實(shí)驗(yàn)數(shù)據(jù)進(jìn)行了挑選,只留下了那些合乎最佳結(jié)果的數(shù)據(jù),而舍棄了那些“不太好”的數(shù)據(jù)。我認(rèn)為,這個(gè)學(xué)生永遠(yuǎn)不可能實(shí)現(xiàn)真正意義的學(xué)術(shù)突破,也不可能成為一名真正合格的研究人員。   

              最后想提的是一些喜歡貪小便宜的人。他們用學(xué)校或公司的電話打私人長(zhǎng)途、多報(bào)銷出租車票。也許有人認(rèn)為,學(xué)生以成績(jī)、事業(yè)為重,其他細(xì)節(jié)只是一些小事,隨心所欲地做了,也沒什么大不了的。然而,就是那些身邊的所謂“小事”,往往成為一個(gè)人塑造人格和積累誠(chéng)信的關(guān)鍵。一些貪小便宜、耍小聰明的行為只會(huì)把自己定性為一個(gè)貪圖小利、沒有出息的人的形象,最終因小失大。中國(guó)有“勿以惡小而為之”的古訓(xùn),很值得記取。   

            生活在群體之中
            與大多數(shù)美國(guó)學(xué)生比較而言,中國(guó)學(xué)生的表達(dá)能力、溝通能力和團(tuán)隊(duì)精神要相對(duì)欠缺一些。這也許是由于文化背景和教育體制的不同而造成的。今天,當(dāng)我們面對(duì)一個(gè)正在走向高度全球化的社會(huì)時(shí),生活在群體之中,做出更好的表現(xiàn),得到更多的收獲,是尤為重要的。   

              表達(dá)和溝通的能力是非常重要的。不論你做出了怎樣優(yōu)秀的工作,不會(huì)表達(dá),無(wú)法讓更多的人去理解和分享,那就幾乎等于白做。所以,在學(xué)習(xí)階段,你不可以只生活在一個(gè)人的世界中,而應(yīng)當(dāng)盡量學(xué)會(huì)與各類人交往和溝通,主動(dòng)表達(dá)自己對(duì)各種事物的看法和意見,甚至在公眾集會(huì)時(shí)發(fā)表演講,鍛煉自己的表達(dá)能力。   

              表達(dá)能力絕不只是你的“口才”。哈佛大學(xué)的Ambady教授最近做過(guò)一個(gè)非常有趣的實(shí)驗(yàn),他讓兩組學(xué)生分別評(píng)估幾位教授的授課質(zhì)量。他把這幾位教授的講課錄像帶先無(wú)聲地放兩秒鐘給一組學(xué)生看,得出一套評(píng)估結(jié)果。然后與那些已經(jīng)聽過(guò)這幾位教授幾個(gè)月講課的學(xué)生的結(jié)果進(jìn)行對(duì)比,兩個(gè)小組的結(jié)論竟然驚人的相似。這表明,在表達(dá)自己思想的過(guò)程中,非語(yǔ)言表達(dá)方式和語(yǔ)言同樣重要,有時(shí)作用甚至更加明顯。這里所講的非語(yǔ)言表達(dá)方式是指人的儀表、舉止、語(yǔ)氣、聲調(diào)和表情等。因?yàn)閺倪@些方面,人們可以更直觀、更形象地判斷你為人、做事的能力,看出你的自信和熱情,從而獲得十分重要的“第一印象”。   

              對(duì)于一個(gè)集體、一個(gè)公司,甚至是一個(gè)國(guó)家,團(tuán)隊(duì)精神都是非常關(guān)鍵性的。微軟公司在美國(guó)以特殊的團(tuán)隊(duì)精神著稱。像Windows2000這樣的產(chǎn)品的研發(fā),有超過(guò)3000名開發(fā)工程師和測(cè)試人員參與,寫出了5000萬(wàn)行代碼。沒有高度統(tǒng)一的團(tuán)隊(duì)精神,沒有全部參與者的默契與分工合作,這項(xiàng)工程是根本不可能完成的。   

              以前我在別的公司時(shí)卻也曾見到過(guò)相反的現(xiàn)象。一項(xiàng)工程布置下來(lái),大家明明知道無(wú)法完成,但都心照不宣,不告訴老板。因?yàn)榉凑沧霾煌辏蠹宜餍砸膊慌θプ鍪拢瑓s花更多的時(shí)間去算計(jì)怎么把這項(xiàng)工程的失敗怪罪到別人身上去。就是這些人和這樣的工作作風(fēng),幾乎把這家公司拖垮。   

              為了培養(yǎng)團(tuán)隊(duì)精神,我建議同學(xué)們?cè)谧x書之余積極參加各種社會(huì)團(tuán)體的工作。在與他人分工合作、分享成果、互助互惠的過(guò)程中,你們可以體會(huì)團(tuán)隊(duì)精神的重要性。
              在學(xué)習(xí)過(guò)程中,你千萬(wàn)不要不愿意把好的思路、想法和結(jié)果與別人分享,擔(dān)心別人走到你前面的想法是不健康的,也無(wú)助于你的成功。有一句諺語(yǔ)說(shuō),“你付出的越多,你得到的越多”。試想,如果你的行為讓人覺得“你的是我的,我的還是我的”,當(dāng)你需要幫忙時(shí),你認(rèn)為別人會(huì)來(lái)幫助你嗎?反之,如果你時(shí)常慷慨地幫助別人,那你是不是會(huì)得到更多人的回報(bào)呢?   

            在團(tuán)隊(duì)之中,要勇于承認(rèn)他人的貢獻(xiàn)。如果借助了別人的智慧和成果,就應(yīng)該聲明。如果得到了他人的幫助,就應(yīng)該表示感謝。這也是團(tuán)隊(duì)精神的基本體現(xiàn)。
            做一個(gè)主動(dòng)的人   

              三十年前,一個(gè)工程師夢(mèng)寐以求的目標(biāo)就是進(jìn)入科技最領(lǐng)先的IBM。那時(shí)IBM對(duì)人才的定義是一個(gè)有專業(yè)知識(shí)的、埋頭苦干的人。斗轉(zhuǎn)星移,事物發(fā)展到今天,人們對(duì)人才的看法已逐步發(fā)生了變化。現(xiàn)在,很多公司所渴求的人才是積極主動(dòng)、充滿熱情、靈活自信的人。   

              作為當(dāng)代中國(guó)的大學(xué)生,你應(yīng)該不再只是被動(dòng)地等待別人告訴你應(yīng)該做什么,而是應(yīng)該主動(dòng)去了解自己要做什么,并且規(guī)劃它們,然后全力以赴地去完成。想想今天世界上最成功的那些人,有幾個(gè)是唯唯諾諾、等人吩咐的人?對(duì)待自己的學(xué)業(yè)和研究項(xiàng)目,你需要以一個(gè)母親對(duì)孩子那樣的責(zé)任心和愛心,全力投入,不斷努力。果真如此,便沒有什么目標(biāo)是不能達(dá)到的。   

              一個(gè)積極主動(dòng)的人還應(yīng)該虛心聽取他人的批評(píng)和意見。其實(shí),這也是一種進(jìn)取心的體現(xiàn)。不能虛心接受別人的批評(píng),并從中汲取教訓(xùn),就不可能有更大的進(jìn)步。比爾蓋茨曾經(jīng)對(duì)公司所有員工說(shuō)過(guò):“客戶的批評(píng)比賺錢更重要。從客戶的批評(píng)中,我們可以更好地汲取失敗的教訓(xùn),將它轉(zhuǎn)為成功的動(dòng)力。”   

              除了虛心接受別人的批評(píng),你還應(yīng)該努力尋找一位你特別尊敬的良師。這位良師應(yīng)該是直接教導(dǎo)你的老師以外的人,這樣的人更能客觀地給你一些忠告。這位良師除了可以在學(xué)識(shí)上教導(dǎo)你之外,還可以在其他一些方面對(duì)你有所指點(diǎn),包括為人處世,看問(wèn)題的眼光,應(yīng)對(duì)突發(fā)事件的技能等等。
              我以前在蘋果公司負(fù)責(zé)一個(gè)研究部門時(shí),就曾有幸找到這樣一位良師。當(dāng)時(shí),他是負(fù)責(zé)蘋果公司全球運(yùn)作和生產(chǎn)業(yè)務(wù)的高級(jí)副總裁,他在事業(yè)發(fā)展方面給我的許多教誨令我終身受益。如果有這樣的人給你幫助 ,那你成長(zhǎng)的速度一定會(huì)比別人更快一些。   

              中國(guó)學(xué)生大多比較含蓄、害羞,不太習(xí)慣做自我推銷。但是,要想把握住轉(zhuǎn)瞬即逝的機(jī)會(huì),就必須學(xué)會(huì)說(shuō)服他人,向別人推銷自己或自己的觀點(diǎn)。在說(shuō)服他人之前,要先說(shuō)服自己。你的激情加上才智往往折射出你的潛力,一個(gè)好的自我推銷策略可以令事情的發(fā)展錦上添花。

              例如,有一次我收到了一份很特殊的求職申請(qǐng)書。不同于已往大多數(shù)求職者,這位申請(qǐng)人的求職資料中包括了他的自我介紹、他對(duì)微軟研究院的向往、以及他為什么認(rèn)為自己是合適的人選,此外還有他已經(jīng)發(fā)表的論文、老師的推薦信和他希望來(lái)微軟作的課題等。盡管他畢業(yè)的學(xué)校不是中國(guó)最有名的學(xué)校,但他的自我推銷奏效了。我從這些文件中看到了他的熱情和認(rèn)真。在我面試他時(shí),他又遞交了一份更充分的個(gè)人資料。最后,當(dāng)我問(wèn)他有沒有問(wèn)題要問(wèn)我時(shí),他反問(wèn)我,:“你對(duì)我還有沒有任何的保留?”當(dāng)時(shí),我的確對(duì)他能否進(jìn)入新的研究領(lǐng)域有疑慮,于是就進(jìn)一步問(wèn)了他一些這方面的問(wèn)題。他舉出了兩個(gè)很有說(shuō)服力的例子。最后,我們雇用了這名應(yīng)聘者。他現(xiàn)在做得非常出色。   

            挑戰(zhàn)自我、開發(fā)自身潛力   
              我在蘋果公司工作的時(shí)候,有一天,老板突然問(wèn)我什么時(shí)候可以接替他的工作?我非常吃驚,表示自己缺乏像他那樣的管理經(jīng)驗(yàn)和能力。但是他卻說(shuō),這些經(jīng)驗(yàn)是可以培養(yǎng)和積累的,而且他希望我在兩年之后就可以做到。有了這樣的提示和鼓勵(lì),我開始有意識(shí)地加強(qiáng)自己在這方面的學(xué)習(xí)和實(shí)踐。果然,我真的在兩年之后接替了他的工作。我個(gè)人認(rèn)為,一個(gè)人的領(lǐng)導(dǎo)素質(zhì)對(duì)于他將來(lái)的治學(xué)、經(jīng)商或從政都是十分重要的。在任何時(shí)候、任何環(huán)境里,我們都應(yīng)該有意識(shí)地培養(yǎng)自己的領(lǐng)導(dǎo)才能。同時(shí),我建議你給自己一些機(jī)會(huì)展示這方面的能力,或許像我一樣,你會(huì)驚訝自己在這一方面的潛力遠(yuǎn)遠(yuǎn)超過(guò)了自己的想象。   
              給自己設(shè)定目標(biāo)是一件十分重要的事情。目標(biāo)設(shè)定過(guò)高固然不切實(shí)際,但是目標(biāo)千萬(wàn)不可定得太低。在二十一世紀(jì),競(jìng)爭(zhēng)已經(jīng)沒有疆界,你應(yīng)該放開思維,站在一個(gè)更高的起點(diǎn),給自己設(shè)定一個(gè)更具挑戰(zhàn)性的標(biāo)準(zhǔn),才會(huì)有準(zhǔn)確的努力方向和廣闊的前景,切不可做“井底之蛙”。另外,只在一所學(xué)校取得好成績(jī)、好名次就認(rèn)為自己已經(jīng)功成名就是可笑的,要知道,山外有山,人上有人,而且,不同地方的衡量標(biāo)準(zhǔn)又不一 樣。所以,在訂立目標(biāo)方面,千萬(wàn)不要有“寧為雞首,不為牛后”的思想。   

              一個(gè)一流的人與一個(gè)一般的人在一般問(wèn)題上的表現(xiàn)可能一樣,但是在一流問(wèn)題上的表現(xiàn)則會(huì)有天壤之別。美國(guó)著名作家威廉&#8226;福克納說(shuō)過(guò):“不要竭盡全力去和你的同僚競(jìng)爭(zhēng)。你更應(yīng)該在乎的是:你要比現(xiàn)在的你更強(qiáng)。”你應(yīng)該永遠(yuǎn)給自己設(shè)立一些很具挑戰(zhàn)性、但并非不可及的目標(biāo)。

            在確立將來(lái)事業(yè)的目標(biāo)時(shí),不要忘了捫心自問(wèn):“這是不是我最熱愛的專業(yè)?我是否愿意全力投入?”我希望你們能夠?qū)ψ约哼x擇所從事的工作充滿激情和想象力,對(duì)前進(jìn)途中可能出現(xiàn)的各種艱難險(xiǎn)阻無(wú)所畏懼。談到對(duì)工作的熱愛,我認(rèn)識(shí)的一位微軟的研究員曾經(jīng)讓我深有感觸。他經(jīng)常周末開車出門,說(shuō)去見“女朋友”,后來(lái),一次偶然機(jī)會(huì)我在辦公室里看見他,問(wèn)他:“女朋友在哪里?”他笑著指著電腦說(shuō):“就是她呀。 ”

              對(duì)于工作的熱愛,比爾&#8226;蓋茨也曾有過(guò)非常精彩的闡述,他說(shuō):“每天早晨醒來(lái),一想到所從事的工作和所開發(fā)的技術(shù)將會(huì)給人類生活帶來(lái)的巨大影響和變化,我就會(huì)無(wú)比興奮和激動(dòng)。”   

              幾個(gè)月前,《北京青年報(bào)》上曾有一場(chǎng)探討比爾&#8226;蓋茨和保爾&#8226;柯察金誰(shuí)更偉大的討論。由于從小在美國(guó)長(zhǎng)大,我并不知道保爾和他的事跡。但是,我非常贊同保爾的這段名言:“人最寶貴的東西是生命,生命屬于我們只有一次。人的一生應(yīng)當(dāng)這樣度過(guò),當(dāng)他回首往事的時(shí)候,不因虛度年華而悔恨,也不因碌碌無(wú)為而羞愧……”所以,你應(yīng)當(dāng)選擇一個(gè)你真心熱愛的事業(yè),不斷地挑戰(zhàn)自我、完善自我,讓自己的一生過(guò)得精彩和充實(shí)。
              
            客觀、直截了當(dāng)?shù)臏贤?/b>
              有一次,一位中國(guó)的大學(xué)教授找到我,希望我?guī)退乙晃粐?guó)外的專家在他組織的會(huì)議上去做主題演講,末了還特意加了一句,最好是一個(gè)洋人。我很不以為然地對(duì)他說(shuō):“這個(gè)領(lǐng)域最具權(quán)威的人士就是在北京的一個(gè)中國(guó)人,為什么你一定要找一位洋人呢?”他表面上同意我的說(shuō)法,但是他仍然請(qǐng)了一個(gè)美國(guó)人來(lái)做這個(gè)演講,結(jié)果效果很差。所以,我們不應(yīng)該陷入盲目的崇洋情結(jié)。我們應(yīng)該用客觀的眼光來(lái)判斷事物,而不是以他的膚色或他的居住地來(lái)決定。   

            有一句話說(shuō),“真理往往掌握在少數(shù)人手中”。這句話的意思是,我們看問(wèn)題應(yīng)該有自己的眼光,有獨(dú)立思考的能力,不一定大多數(shù)人認(rèn)可的,或某個(gè)權(quán)威說(shuō)的,就是對(duì)的。不論是做學(xué)問(wèn)、搞研究還是經(jīng)商,我們都不能盲從,要多想幾個(gè)為什么。有了客觀的意見,你就應(yīng)該直截了當(dāng)?shù)乇磉_(dá)。如果做任何事情都像“打太極拳”,會(huì)讓人不知所云,也會(huì)造成很多誤會(huì)。有一次,在微軟研究院工作的一位研究人員就自己所選擇的研究方向來(lái)征求我的意見,我作了一番分析,認(rèn)為這個(gè)方向有不少問(wèn)題,但如果他堅(jiān)持,我愿意支持他試著去做。結(jié)果他認(rèn)為我這句話的意思實(shí)際上就是不允許他去做,所以他就選擇了其他的方向。后來(lái)他要出差時(shí),負(fù)責(zé)行政事務(wù)的人告訴他,你可以選擇坐火車或者坐飛機(jī)。他認(rèn)為行政人員實(shí)際上是在暗示他坐火車,因?yàn)樽w機(jī)太貴。其實(shí),他的猜測(cè)都是錯(cuò)誤的。因?yàn)槲覀兊臏贤ǚ绞绞侵苯亓水?dāng),而他卻在“打太極拳”。這之后,我們通過(guò)一系列的公司文化講座,讓員工們了解到,心里想什么就講什么,不要把簡(jiǎn)單的問(wèn)題復(fù)雜化。現(xiàn)在,研究院里這類的誤會(huì)少了很多。  

              拐彎抹角,言不由衷,結(jié)果浪費(fèi)了大家的寶貴時(shí)間。瞻前顧后,生怕說(shuō)錯(cuò)話,結(jié)果是變成謹(jǐn)小慎微的懦夫。更糟糕的是還有些人,當(dāng)面不說(shuō),背后亂講,這樣對(duì)他人和自己都毫無(wú)益處,最后只能是破壞了集體的團(tuán)結(jié)。這樣的人和作風(fēng)既不能面對(duì)社會(huì),也不可能在科學(xué)研究中走出新路,更不可能在激烈的商戰(zhàn)中脫穎而出。   

              希望同學(xué)們能夠做到開誠(chéng)布公,敢于說(shuō)“不”,這才是尊重自己思想意愿的表現(xiàn)。當(dāng)然,在表達(dá)你的意見時(shí),無(wú)論反對(duì)和批評(píng)都應(yīng)是建設(shè)性的,有高度誠(chéng)意的,而不是為批評(píng)而批評(píng),為辯論而批評(píng)。我贊成的方式是提供建設(shè)性的正面的意見。在開始討論問(wèn)題時(shí),任何人先不要拒人千里之外,大家把想法都擺在桌面上,充分體現(xiàn)個(gè)人的觀點(diǎn),這樣才會(huì)有一個(gè)容納大部分人意見的結(jié)論。當(dāng)然,你也要學(xué)習(xí)用適當(dāng)?shù)姆椒ê涂跉獗磉_(dá)你的意見,比如說(shuō)不要在很多人面前讓別人難堪。這樣,你的批評(píng)才會(huì)奏效。   


            珍惜校園學(xué)習(xí)生活   
              幾天前,報(bào)紙上登出一條消息,說(shuō)有中學(xué)生輟學(xué)去開網(wǎng)絡(luò)公司。我認(rèn)為這并不值得提倡。對(duì)絕大多數(shù)學(xué)生來(lái)講,在校生活是系統(tǒng)地學(xué)習(xí)基礎(chǔ)理論知識(shí),學(xué)習(xí)思考和解決問(wèn)題方式的好機(jī)會(huì)。這些知識(shí)將成為你未來(lái)發(fā)展過(guò)程中所需要的最基本的知識(shí)和技能。就像建一棟高樓,如果不打好基礎(chǔ),是經(jīng)不起風(fēng)吹雨打的。   

              在全球范圍內(nèi),美國(guó)的研究水平無(wú)疑是世界一流的。而除了美國(guó)之外,你會(huì)發(fā)現(xiàn)英國(guó)的研究水平也是相當(dāng)突出的。究其原因,其實(shí)就是語(yǔ)言問(wèn)題。英國(guó)人可以毫無(wú)阻礙地閱讀美國(guó)乃至全球各種最新的英文研究報(bào)告和資料。這對(duì)于他們把握研究方向,跟蹤最新進(jìn)展,發(fā)表研究成果都有很大的幫助。因此,英語(yǔ)學(xué)習(xí)對(duì)于我們作研究的人來(lái)說(shuō),是相當(dāng)重要的。只有加強(qiáng)這方面素質(zhì)的培養(yǎng),才能適應(yīng)將來(lái)的發(fā)展。我建議,學(xué)英語(yǔ)先聽說(shuō),再學(xué)讀寫,而且務(wù)必在大學(xué)階段完全解決英語(yǔ)學(xué)習(xí)的問(wèn)題。等到年齡大了,要付出的代價(jià)相比就會(huì)大得多。   

              除了英語(yǔ)之外,數(shù)學(xué)、統(tǒng)計(jì)學(xué)對(duì)理工科學(xué)生也是很重要的基礎(chǔ)課程,是不可忽視的。數(shù)學(xué)是人類幾千年的智慧結(jié)晶,你們一定要用心把它學(xué)好,不能敷衍了事。我今天就很后悔自己當(dāng)初沒有花更多功夫把數(shù)學(xué) 學(xué)得 更好些。另外,計(jì)算機(jī)應(yīng)用、算法和編程也都是每一個(gè)工科學(xué)生應(yīng)該 熟悉 和掌握的,它們是將來(lái)人人必須會(huì)用的工具。   

              科技的發(fā)展可謂日新月異。在校學(xué)習(xí)的目的,其實(shí)就是掌握最基本的學(xué)習(xí)工具和方法。將來(lái)利用這些工具和方法,再去學(xué)習(xí)新的東西。比如:上課學(xué)會(huì)了C++,能否自己學(xué)會(huì)Java?上課學(xué)會(huì)了HTML,能否自己學(xué)會(huì) XML?與其說(shuō)上大學(xué)是為了學(xué)一門專業(yè),不如說(shuō)是為了學(xué)會(huì)如何學(xué)習(xí) ,讓自己能夠“無(wú)師自通”。   

              大學(xué)畢業(yè)后的前兩年,同學(xué)們聚到一起,發(fā)現(xiàn)變化都還不算大。五年后再聚到一起,變化就大多了。一些人落伍了,因?yàn)樗麄儾辉賹W(xué)習(xí),不再能夠掌握新的東西,自然而然地落在了社會(huì)發(fā)展的后面。如果我們要在這個(gè)競(jìng)爭(zhēng)激烈的社會(huì)中永不落伍,那就得永遠(yuǎn)學(xué)習(xí)。   
              我的老板RickRashid博士是目前微軟公司主管研究的高級(jí)副總裁,他已經(jīng)功成名就,卻始終保持著一顆學(xué)習(xí)和進(jìn)取的心。現(xiàn)在,他每年仍然編寫大約50,000行程序。他認(rèn)為:用最新的技術(shù)編程可以使他保持對(duì)計(jì)算機(jī)最前沿技術(shù)的敏感,使自己能夠不斷進(jìn)步。今天,有些博士生帶著低年級(jí)的本科生和碩士生做項(xiàng)目,就自滿地認(rèn)為自己已經(jīng)沒有必要再編程了。其實(shí),這樣的做法是很不明智的。   

              每次到清華和其他學(xué)校訪問(wèn),被問(wèn)到最多的就是學(xué)生打工的問(wèn)題。我認(rèn)為,打工從總體來(lái)說(shuō)對(duì)學(xué)生是一件好事,是拓寬視野的一種方式。例如,在研究機(jī)構(gòu)打工,可以學(xué)到最新的科技;在產(chǎn)品部門打工,可以學(xué)到開發(fā)的技術(shù)和技能;在市場(chǎng)部門打工,可以理解商業(yè)的運(yùn)作。我認(rèn)為每一個(gè)學(xué)生都應(yīng)該有打工的經(jīng)驗(yàn),但不要打一些“沒用的工”。首先要明白打工只是學(xué)生生活中的一種補(bǔ)充,學(xué)習(xí)才是最重要的。打工的目的是開闊眼界,不是提前上班。如果你把翻譯書本、錄入數(shù)據(jù)庫(kù)所花的時(shí)間投入學(xué)習(xí),將來(lái)可以賺更多的錢。那些錢將遠(yuǎn)遠(yuǎn)超出目前打工的收入。   ??

              此外,還有一些學(xué)生受到目前退學(xué)創(chuàng)業(yè)風(fēng)潮的鼓勵(lì),為成為中國(guó)的比爾&#8226;蓋茨和邁克爾&#8226;戴爾而中途輟學(xué)。以我的觀點(diǎn),除了十分特殊的情況外,我不建議在校學(xué)生退學(xué)創(chuàng)業(yè)。你所看到的那些退學(xué)創(chuàng)業(yè)的成功者實(shí)際上少之又少。目前,大部分學(xué)生雖有創(chuàng)業(yè)的想法,但缺少創(chuàng)業(yè)的經(jīng)驗(yàn),所以失敗的可能性非常大。如果要成功,我建議你們先把書讀好。如果是要學(xué)習(xí)創(chuàng)業(yè)的經(jīng)驗(yàn),你完全可以利用假期的時(shí)間先去一家公司邊打工邊學(xué)。

              比爾&#8226;蓋茨也曾說(shuō)過(guò):“如果你正在考慮自己成立一家新公司,你應(yīng)該首先明確地知道:創(chuàng)辦公司需要巨大的精力投入,要冒巨大的風(fēng)險(xiǎn)。我覺得你們不必像我,一開始就創(chuàng)辦一家公司。你應(yīng)該考慮加盟其他公司并在這家公司中學(xué)習(xí)他們的工作、創(chuàng)業(yè)方法。”   


            你想戴一頂什么樣的博士帽   
              在我進(jìn)入卡內(nèi)基梅隆大學(xué)攻讀計(jì)算機(jī)博士學(xué)位時(shí),系主任曾對(duì)我講,當(dāng)你拿到你的博士學(xué)位時(shí),你應(yīng)該成為你所從事的研究領(lǐng)域里世界第一的專家。這句話對(duì)于初出茅廬的我來(lái)說(shuō)簡(jiǎn)直高不可攀,但也讓我躊躇滿志、躍躍欲試。就這樣,在經(jīng)過(guò)五年寒窗、夜以繼日的努力工作后,他所期待的結(jié)果就那么自然而然地出現(xiàn)了。

              一個(gè)打算攻讀博士學(xué)位的人,就應(yīng)該給自己樹立一個(gè)很高的目標(biāo)。如果沒有雄心壯志,就千萬(wàn)不要自欺欺人,也許經(jīng)商或從事其它工作,會(huì)有更大的成績(jī)。在目標(biāo)確立之后,我建議你為自己設(shè)計(jì)一個(gè)三年的學(xué)習(xí)和科研計(jì)劃。首先,你需要徹底地了解在相關(guān)領(lǐng)域他人已有的工作和成績(jī)。然后再提出自己的想法和見解,做腳踏實(shí)地的工作。另外,還要不斷跟蹤這個(gè)領(lǐng)域的最新研究進(jìn)展。只有這樣,才可以把握好方向,避免重復(fù)性工作,把精力集中在最有價(jià)值的研究方向上 。   

              在學(xué)術(shù)界,人們普遍認(rèn)為“名師出高徒”。可見導(dǎo)師在你的成長(zhǎng)道路中作用是多么大。所以,你應(yīng)該主動(dòng)去尋找自己所研究的領(lǐng)域里最好的老師。除了你的老師之外,你還應(yīng)該去求教于周圍所有的專家。更不要忘了常去求教“最博學(xué)的老師”Internet!現(xiàn)在,幾乎所有的論文、研究結(jié)果、先進(jìn)想法都可以在網(wǎng)上找到。我還鼓勵(lì)你直接發(fā)電子郵件去咨詢一些世界公認(rèn)的專家和教授。以我的經(jīng)驗(yàn),對(duì)于這樣的郵件,他們中的大部分都會(huì)很快給你回復(fù)。   

              我在攻讀博士學(xué)位時(shí),每周工作七天,每天工作16個(gè)小時(shí),大量的統(tǒng)計(jì)結(jié)果和分析報(bào)告幾乎讓我崩潰。那時(shí),同領(lǐng)域其他研究人員采用的是與我不同的傳統(tǒng)方法。我的老師雖然支持我,但并不認(rèn)可我的研究方向 。我也曾不止一次地懷疑自己的所作所為是否真的能夠成功。但終于有一 天, 在半夜三點(diǎn)時(shí)做出的一個(gè)結(jié)果讓我感受到了成功的滋味。后來(lái),研究有了突飛猛進(jìn)的進(jìn)展,導(dǎo)師也開始采用我的研究方法。我的博士論文使我的研究成為自然語(yǔ)言研究方面當(dāng)時(shí)最有影響力的工作之一。

              讀博士不是一件輕松的事,切忌浮躁的情緒,而要一步一個(gè)腳印,扎扎實(shí)實(shí)地工作。也不可 受一些稍縱即逝的名利的誘惑,而要200%的投入。也許你會(huì)疲勞,會(huì)懊悔,會(huì)迷失方向,但是要記住,你所期待的成功和突破也正孕育其中。那種一切都很順利,誰(shuí)都可以得到的工作和結(jié)果,我相信研究?jī)r(jià)值一定不高。從一定意義上講,一個(gè)人如果打算一輩子從事研究工作,那么從他在讀博士學(xué)位期間所形成的做事習(xí)慣、研究方法和思維方式基本上就可以判斷出他未來(lái)工作的輪廓。所以,你一定要做一個(gè)“有心人”,充分利 用在 校的時(shí)間,為自己的將來(lái)打好基礎(chǔ)。   

              上述一些觀點(diǎn),是我在與同學(xué)們交往過(guò)程中的一些感受。我希望這些建議和想法能對(duì)正在未來(lái)之路上跋涉的你們有所啟發(fā),能對(duì)你們目前的學(xué)習(xí)有所幫助。或許因?yàn)橛^點(diǎn)不同、人各有志,或許因?yàn)橹已阅娑@封信可能無(wú)法為每一位同學(xué)所接受。但是只要一百位閱讀這封信的同學(xué)中有一位從中受益,這封信就已經(jīng)比我所作的任何研究都更有價(jià)值。我真誠(chéng)地希望,在新的世紀(jì),中國(guó)學(xué)生無(wú)論是在國(guó)內(nèi),還是國(guó)外;無(wú)論是做研究,還是經(jīng)商,都顯得更成熟一些,成功的機(jī)率更大一些。
            posted @ 2006-07-19 17:02 Merlin 閱讀(300) | 評(píng)論 (0)編輯 收藏

            作為程序員,應(yīng)該是最為辛苦的一件事情,通宵達(dá)旦的熬夜,把自己的血汗無(wú)償?shù)木璜I(xiàn)給了Boss ,同時(shí)還得小心自己落伍,明天要學(xué)習(xí),再學(xué)習(xí),因?yàn)榧夹g(shù)更新實(shí)在是太快,JDK1.4還沒有搞定, JDK5.0已經(jīng)開始普及了,等俺們開始用上了5.0,6.0已經(jīng)開始發(fā)布測(cè)試版了,7.0也在磨刀霍霍之中,危機(jī)感始終是籠罩在自己頭上,怎么辦? 難道我們程序員就是這樣的生活?

            ????真想好好的休息一下,放松自己的神經(jīng)! 但是不能!怎么辦? 工作兩年了,真的是感覺到了這種辛苦。那怎么才能夠改變這種現(xiàn)象呢?方法,改變我們學(xué)習(xí)的方法,這是我最近一直在思考的事情。新技術(shù)曾出不窮,我們不可能永遠(yuǎn)跟得上腳步,所以我們要掌握自己的主動(dòng)權(quán)。

            ?? 第一,要有好的心態(tài),我們選擇了這一行,沒有什么可以抱怨的。

            ?? 第二,經(jīng)常反省自己,看能不能變得更好。 每天都會(huì)有收獲,所以呢,每天都可以發(fā)現(xiàn)自己的不足。Matrin Folwer說(shuō),如果,兩年后,你還是認(rèn)為兩年前的自己已經(jīng)很優(yōu)秀的話,那說(shuō)明你沒有進(jìn)步。

            ?? 第三,要總結(jié),把自己明天的心得都記下來(lái),記錄自己的腳步。

            ?? 第四,要鉆研,要做就把它做好。碰到困難更是要迎難而上,這時(shí)候才是學(xué)習(xí)的最好機(jī)會(huì)。

            ?? 第五,不要有畏懼心理,不要怕做不好。相信自己。

            ?? 第六,要學(xué)會(huì)使用文檔,俺的頭這一點(diǎn)最讓人佩服,不會(huì)的問(wèn)題,看文檔,很快就可以搞定,當(dāng)然,前提是他英語(yǔ)實(shí)在是高。沒有語(yǔ)言障礙。

            ????第七,就是上面說(shuō)的,作為程序員,要學(xué)好英語(yǔ)。這是很重要。

            ????還有就是,程序員每天該做的事,好東西。


            寫的真的很好,不過(guò)我發(fā)現(xiàn)人堅(jiān)持干一件事情真的很難。
            posted @ 2006-07-19 16:32 Merlin 閱讀(332) | 評(píng)論 (0)編輯 收藏

            2006年7月13日 #

            除非你像我一樣學(xué)程序語(yǔ)言只是為了到處獻(xiàn)寶,否則你在學(xué)一套程序語(yǔ)言前,應(yīng)該先仔細(xì)評(píng)估到底要學(xué)哪一套。每個(gè)程序語(yǔ)言的用途都有很大的差異,走了冤枉路可能會(huì)耽誤到計(jì)畫實(shí)作的進(jìn)程。
            我大致上把程序語(yǔ)言分成五類,分述如下:

            Web Page Script Languages
            用來(lái)做網(wǎng)頁(yè)的語(yǔ)言,可以對(duì)網(wǎng)頁(yè)做控制。如果你希望設(shè)計(jì)出很炫的網(wǎng)頁(yè),光靠 HTML 是不夠的,你還得學(xué)一套 Web Page Script Language,比方說(shuō) javascript(ECMAScript)和微軟的 JScript。不過(guò)兩者都是系出同門,所以差不多。WML Script(WAP 手機(jī)的 script)也是襲自
            javascript。
            許多人知道我不會(huì) javascript 之后,都會(huì)大吃一驚地反問(wèn):「可是你不是會(huì) Java,怎么不順便學(xué) javascript,兩個(gè)語(yǔ)言不是差不多」。如果依照此推理,我看我差不多每個(gè)語(yǔ)言都要學(xué)了,因?yàn)槌?REBOL 和匯編語(yǔ)言比較特殊之外,我覺得其它語(yǔ)言的語(yǔ)法都差不多(但用途差很多)。
            不過(guò)我最近的確是有打算開始學(xué) javascript,因?yàn)槲野l(fā)現(xiàn)用到它的機(jī)會(huì)還不少。除了網(wǎng)頁(yè)會(huì)用到之外,我最近所接觸的 SVG(Scalable Vector Graphics)就使用 javascript 來(lái)達(dá)到動(dòng)畫效果。

            Interpreted Languages(直譯式語(yǔ)言)
            這類直譯式的語(yǔ)言包括了 Perl、Python、REBOL、Ruby... 等,也常被稱為 script 語(yǔ)言,通常是用來(lái)取代批次檔和 shell script 以便和底下的操作系統(tǒng)溝通。基本上,每個(gè)人至少都應(yīng)該要會(huì)一套這類的語(yǔ)言,當(dāng)你需要做某件簡(jiǎn)單的工作,你可以透過(guò)直譯式的語(yǔ)言來(lái)輕易地辦到,這么一來(lái),你就可以不必大張旗鼓地使用 Java 和 C++ 等工具了。
            直譯式的語(yǔ)言通常比較高階,程序比較好寫,往往簡(jiǎn)短地幾行程序就抵得過(guò) Java 或 C++ 的一堆程序代碼。因?yàn)椴挥镁幾g而且高階,所以這類語(yǔ)言的程序效率通常很差,又因?yàn)樵汲绦虼a暴露在外,所以拿它來(lái)寫寫工具程序自己用可以,但是拿來(lái)開發(fā)軟件產(chǎn)品比較不恰當(dāng)(除非你不在乎原始碼外流)。目前這類語(yǔ)言最常被用來(lái)開發(fā)網(wǎng)頁(yè)服務(wù)器端的程序,或者是設(shè)計(jì)軟件的 prototype。
            Python 有一些不錯(cuò)的語(yǔ)言特性,目前在國(guó)外算是滿熱門的;Ruby 是日本一位教授設(shè)計(jì)的,但是這語(yǔ)言太新了,目前好象只有 Addison Wesley 的一本英文書和 O'Reilly 的一本日文書可供參考;REBOL 則是我近期最喜歡的程序語(yǔ)言,非常特別,REBOL 語(yǔ)言的思維和別的語(yǔ)言差異非常大,許多時(shí)候很接近英文句子。至于 Perl,我就沒有研究了,臺(tái)灣歐萊禮公司已經(jīng)有 Perl 的專家了,如果我現(xiàn)在去學(xué) Perl 的話,短期內(nèi)是不可能超越他的,所以我看算了 :(

            Hybrid Languages(混合式語(yǔ)言)
            Java,C# 都是混合式語(yǔ)言,介于直譯式語(yǔ)言和編譯式語(yǔ)言之間(不管是在執(zhí)行效能上或程序簡(jiǎn)單性上)。
            C# 的語(yǔ)言有許多奇怪的特色,但也有一些不錯(cuò)的特色。C# 的學(xué)習(xí)使用上的難度介于 Java 和 C/C++ 之間。C# 是 Microsoft .NET 平臺(tái)上最重要的語(yǔ)言,值得我們持續(xù)觀察其后續(xù)發(fā)展。至于 Java 我就不用多說(shuō)了,相信 Sleepless in Java 的讀者們應(yīng)該都知道 Java 是怎么一回事。
            至于 Visual Basic,在 .NET 平臺(tái)主推 C# 語(yǔ)言,而 VisualBasic .NET 的語(yǔ)言又比以前復(fù)雜許多的情況下, Visual Basic 的前途似乎很不看好。

            Compiling Languages(編譯式語(yǔ)言)
            C/C++,Delphi(Object Pascal)都是編譯式語(yǔ)言。這幾年來(lái),C++ 已經(jīng)變得越來(lái)越龐大了,大多數(shù)的 C++ 程序員只用到(也只懂)C++ 功能的一小部份。想成為 C++ 語(yǔ)言真正的高手,沒有耗上三五年是不可能的。雖然 C++ 很復(fù)雜,但是真正想成為程序高手的人應(yīng)該都要懂 C/C++,重要的 API 都會(huì)有 C/C++ 的版本,由此可見 C/C++ 的重要性。至于 Delphi,在 Microsoft .NET 推出之后會(huì)對(duì) Delphi 造成一些打擊(Microsoft .NET 的語(yǔ)言名單中連 Scheme、Eiffel 和 Mercury 這種少用的語(yǔ)言都出現(xiàn)了,獨(dú)缺 Delphi),但是 Delphi 能透過(guò) Kylix 來(lái)跨越 Windows 和 Linux,又是一個(gè)很大的吸引力,如果你想要跨 Linux 和 Windows 平臺(tái)的 RAD 工具(語(yǔ)言),目前 Delphi 似乎是最好的選擇。

            Assembly Languages(匯編語(yǔ)言)
            使用匯編語(yǔ)言,你將嘗試到一磚一瓦堆砌出程序的樂趣(或痛苦)。匯編語(yǔ)言可以說(shuō)是最接近硬件的語(yǔ)言,學(xué)會(huì)匯編語(yǔ)言,就可以對(duì)計(jì)算機(jī)的運(yùn)作有相當(dāng)程度的了解。不過(guò),目前連開發(fā)驅(qū)動(dòng)程序都不太需要用到匯編語(yǔ)言了。恐怕只有做 DSP 和 OS 等極少部份的人需要用到匯編語(yǔ)言。我也好久沒寫匯編程序了,以前 DOS 時(shí)代,我還用匯編語(yǔ)言寫過(guò)一個(gè) PE 2。

            程序語(yǔ)言學(xué)習(xí)順序的建議
            通常 Web Script 最簡(jiǎn)單,直譯式語(yǔ)言其次,接著是混合式語(yǔ)言,和編譯式語(yǔ)言,最麻煩的是匯編語(yǔ)言。如果你完全沒有程序經(jīng)驗(yàn),想開始學(xué)程序設(shè)計(jì)的話,你可以從 javascript 著手,等到程序基礎(chǔ)觀念建立得差不多了,再往下學(xué)習(xí)直譯式語(yǔ)言,然后再學(xué)習(xí)混合式語(yǔ)言 ...,以此類推。
            希望這篇文章能解決讀者們選擇程序語(yǔ)言的困擾

            看完這篇文章,我覺得自己的學(xué)習(xí)經(jīng)歷真的很搞笑,上大學(xué)最先學(xué)的是C++,接著學(xué)了一年的C#,后來(lái)接觸了Javascript,現(xiàn)在又在學(xué)Java。弄了半天我是越學(xué)越簡(jiǎn)單了,哈哈~~~~~~~
            posted @ 2006-07-13 21:50 Merlin 閱讀(526) | 評(píng)論 (1)編輯 收藏

            2006年7月12日 #

            在論壇上面常常看到初學(xué)者對(duì)線程的無(wú)可奈何,所以總結(jié)出了下面一篇文章,希望對(duì)一些正在學(xué)習(xí)使用java線程的初學(xué)者有所幫助。

            首先要理解線程首先需要了解一些基本的東西,我們現(xiàn)在所使用的大多數(shù)操作系統(tǒng)都屬于多任務(wù),分時(shí)操作系統(tǒng)。正是由于這種操作系統(tǒng)的出現(xiàn)才有了多線程這個(gè)概念。我們使用的windows,linux就屬于此列。什么是分時(shí)操作系統(tǒng)呢,通俗一點(diǎn)與就是可以同一時(shí)間執(zhí)行多個(gè)程序的操作系統(tǒng),在自己的電腦上面,你是不是一邊聽歌,一邊聊天還一邊看網(wǎng)頁(yè)呢?但實(shí)際上,并不上cpu在同時(shí)執(zhí)行這些程序,cpu只是將時(shí)間切割為時(shí)間片,然后將時(shí)間片分配給這些程序,獲得時(shí)間片的程序開始執(zhí)行,不等執(zhí)行完畢,下個(gè)程序又獲得時(shí)間片開始執(zhí)行,這樣多個(gè)程序輪流執(zhí)行一段時(shí)間,由于現(xiàn)在cpu的高速計(jì)算能力,給人的感覺就像是多個(gè)程序在同時(shí)執(zhí)行一樣。
            一般可以在同一時(shí)間內(nèi)執(zhí)行多個(gè)程序的操作系統(tǒng)都有進(jìn)程的概念.一個(gè)進(jìn)程就是一個(gè)執(zhí)行中的程序,而每一個(gè)進(jìn)程都有自己獨(dú)立的一塊內(nèi)存空間,一組系統(tǒng)資源.在進(jìn)程概念中,每一個(gè)進(jìn)程的內(nèi)部數(shù)據(jù)和狀態(tài)都是完全獨(dú)立的.因此可以想像創(chuàng)建并執(zhí)行一個(gè)進(jìn)程的系統(tǒng)開像是比較大的,所以線程出現(xiàn)了。在java中,程序通過(guò)流控制來(lái)執(zhí)行程序流,程序中單個(gè)順序的流控制稱為線程,多線程則指的是在單個(gè)程序中可以同時(shí)運(yùn)行多個(gè)不同的線程,執(zhí)行不同的任務(wù).多線程意味著一個(gè)程序的多行語(yǔ)句可以看上去幾乎在同一時(shí)間內(nèi)同時(shí)運(yùn)行.(你可以將前面一句話的程序換成進(jìn)程,進(jìn)程是程序的一次執(zhí)行過(guò)程,是系統(tǒng)運(yùn)行程序的基本單位)

            線程與進(jìn)程相似,是一段完成某個(gè)特定功能的代碼,是程序中單個(gè)順序的流控制;但與進(jìn)程不同的是,同類的多個(gè)線程是共享一塊內(nèi)存空間和一組系統(tǒng)資源,而線程本身的數(shù)據(jù)通常只有微處理器的寄存器數(shù)據(jù),以及一個(gè)供程序執(zhí)行時(shí)使用的堆棧.所以系統(tǒng)在產(chǎn)生一個(gè)線程,或者在各個(gè)線程之間切換時(shí),負(fù)擔(dān)要比進(jìn)程小的多,正因如此,線程也被稱為輕負(fù)荷進(jìn)程(light-weight process).一個(gè)進(jìn)程中可以包含多個(gè)線程.

            多任務(wù)是指在一個(gè)系統(tǒng)中可以同時(shí)運(yùn)行多個(gè)程序,即有多個(gè)獨(dú)立運(yùn)行的任務(wù),每個(gè)任務(wù)對(duì)應(yīng)一個(gè)進(jìn)程,同進(jìn)程一樣,一個(gè)線程也有從創(chuàng)建,運(yùn)行到消亡的過(guò)程,稱為線程的生命周期.用線程的狀態(tài)(state)表明線程處在生命周期的哪個(gè)階段.線程有創(chuàng)建,可運(yùn)行,運(yùn)行中,阻塞,死亡五中狀態(tài).通過(guò)線程的控制與調(diào)度可使線程在這幾種狀態(tài)間轉(zhuǎn)化每個(gè)程序至少自動(dòng)擁有一個(gè)線程,稱為主線程.當(dāng)程序加載到內(nèi)存時(shí),啟動(dòng)主線程.

            [線程的運(yùn)行機(jī)制以及調(diào)度模型]
            java中多線程就是一個(gè)類或一個(gè)程序執(zhí)行或管理多個(gè)線程執(zhí)行任務(wù)的能力,每個(gè)線程可以獨(dú)立于其他線程而獨(dú)立運(yùn)行,當(dāng)然也可以和其他線程協(xié)同運(yùn)行,一個(gè)類控制著它的所有線程,可以決定哪個(gè)線程得到優(yōu)先級(jí),哪個(gè)線程可以訪問(wèn)其他類的資源,哪個(gè)線程開始執(zhí)行,哪個(gè)保持休眠狀態(tài)。
            下面是線程的機(jī)制圖:
            image

            線程的狀態(tài)表示線程正在進(jìn)行的活動(dòng)以及在此時(shí)間段內(nèi)所能完成的任務(wù).線程有創(chuàng)建,可運(yùn)行,運(yùn)行中,阻塞,死亡五中狀態(tài).一個(gè)具有生命的線程,總是處于這五種狀態(tài)之一:
            1.創(chuàng)建狀態(tài)
            使用new運(yùn)算符創(chuàng)建一個(gè)線程后,該線程僅僅是一個(gè)空對(duì)象,系統(tǒng)沒有分配資源,稱該線程處于創(chuàng)建狀態(tài)(new thread)
            2.可運(yùn)行狀態(tài)
            使用start()方法啟動(dòng)一個(gè)線程后,系統(tǒng)為該線程分配了除CPU外的所需資源,使該線程處于可運(yùn)行狀態(tài)(Runnable)
            3.運(yùn)行中狀態(tài)
            Java運(yùn)行系統(tǒng)通過(guò)調(diào)度選中一個(gè)Runnable的線程,使其占有CPU并轉(zhuǎn)為運(yùn)行中狀態(tài)(Running).此時(shí),系統(tǒng)真正執(zhí)行線程的run()方法.
            4.阻塞狀態(tài)
            一個(gè)正在運(yùn)行的線程因某種原因不能繼續(xù)運(yùn)行時(shí),進(jìn)入阻塞狀態(tài)(Blocked)
            5.死亡狀態(tài)
            線程結(jié)束后是死亡狀態(tài)(Dead)

            同一時(shí)刻如果有多個(gè)線程處于可運(yùn)行狀態(tài),則他們需要排隊(duì)等待CPU資源.此時(shí)每個(gè)線程自動(dòng)獲得一個(gè)線程的優(yōu)先級(jí)(priority),優(yōu)先級(jí)的高低反映線程的重要或緊急程度.可運(yùn)行狀態(tài)的線程按優(yōu)先級(jí)排隊(duì),線程調(diào)度依據(jù)優(yōu)先級(jí)基礎(chǔ)上的"先到先服務(wù)"原則.
            線程調(diào)度管理器負(fù)責(zé)線程排隊(duì)和CPU在線程間的分配,并由線程調(diào)度算法進(jìn)行調(diào)度.當(dāng)線程調(diào)度管理器選種某個(gè)線程時(shí),該線程獲得CPU資源而進(jìn)入運(yùn)行狀態(tài).

            線程調(diào)度是先占式調(diào)度,即如果在當(dāng)前線程執(zhí)行過(guò)程中一個(gè)更高優(yōu)先級(jí)的線程進(jìn)入可運(yùn)行狀態(tài),則這個(gè)線程立即被調(diào)度執(zhí)行.先占式調(diào)度分為:獨(dú)占式和分時(shí)方式.
            獨(dú)占方式下,當(dāng)前執(zhí)行線程將一直執(zhí)行下去,直 到執(zhí)行完畢或由于某種原因主動(dòng)放棄CPU,或CPU被一個(gè)更高優(yōu)先級(jí)的線程搶占
            分時(shí)方式下,當(dāng)前運(yùn)行線程獲得一個(gè)時(shí)間片,時(shí)間到時(shí),即使沒有執(zhí)行完也要讓出CPU,進(jìn)入可運(yùn)行狀態(tài),等待下一個(gè)時(shí)間片的調(diào)度.系統(tǒng)選中其他可運(yùn)行狀態(tài)的線程執(zhí)行
            分時(shí)方式的系統(tǒng)使每個(gè)線程工作若干步,實(shí)現(xiàn)多線程同時(shí)運(yùn)行

            另外請(qǐng)注意下面的線程調(diào)度規(guī)則(如果有不理解,不急,往下看):
            ①如果兩個(gè)或是兩個(gè)以上的線程都修改一個(gè)對(duì)象,那么把執(zhí)行修改的方法定義為被同步的(Synchronized),如果對(duì)象更新影響到只讀方法,那么只度方法也應(yīng)該定義為同步的
            ②如果一個(gè)線程必須等待一個(gè)對(duì)象狀態(tài)發(fā)生變化,那么它應(yīng)該在對(duì)象內(nèi)部等待,而不是在外部等待,它可以調(diào)用一個(gè)被同步的方法,并讓這個(gè)方法調(diào)用wait()
            ③每當(dāng)一個(gè)方法改變某個(gè)對(duì)象的狀態(tài)的時(shí)候,它應(yīng)該調(diào)用notifyAll()方法,這給等待隊(duì)列的線程提供機(jī)會(huì)來(lái)看一看執(zhí)行環(huán)境是否已發(fā)生改變
            ④記住wait(),notify(),notifyAll()方法屬于Object類,而不是Thread類,仔細(xì)檢查看是否每次執(zhí)行wait()方法都有相應(yīng)的notify()或notifyAll()方法,且它們作用與相同的對(duì)象 在java中每個(gè)類都有一個(gè)主線程,要執(zhí)行一個(gè)程序,那么這個(gè)類當(dāng)中一定要有main方法,這個(gè)man方法也就是java class中的主線程。你可以自己創(chuàng)建線程,有兩種方法,一是繼承Thread類,或是實(shí)現(xiàn)Runnable接口。一般情況下,最好避免繼承,因?yàn)閖ava中是單根繼承,如果你選用繼承,那么你的類就失去了彈性,當(dāng)然也不能全然否定繼承Thread,該方法編寫簡(jiǎn)單,可以直接操作線程,適用于單重繼承情況。至于選用那一種,具體情況具體分析。


            eg.繼承Thread
            				public class MyThread_1 extends Thread
            {
            public void run()
            {
            //some code
            }
            }


            eg.實(shí)現(xiàn)Runnable接口
            				public class MyThread_2 implements Runnable
            {
            public void run()
            {
            //some code
            }
            }



            當(dāng)使用繼承創(chuàng)建線程,這樣啟動(dòng)線程:
            				new MyThread_1().start()
            		


            當(dāng)使用實(shí)現(xiàn)接口創(chuàng)建線程,這樣啟動(dòng)線程:
            				new Thread(new MyThread_2()).start()
            		


            注意,其實(shí)是創(chuàng)建一個(gè)線程實(shí)例,并以實(shí)現(xiàn)了Runnable接口的類為參數(shù)傳入這個(gè)實(shí)例,當(dāng)執(zhí)行這個(gè)線程的時(shí)候,MyThread_2中run里面的代碼將被執(zhí)行。
            下面是完成的例子:

            				public class MyThread implements Runnable
            {

            public void run()
            {
            System.out.println("My Name is "+Thread.currentThread().getName());
            }
            public static void main(String[] args)
            {
            new Thread(new MyThread()).start();
            }
            }



            執(zhí)行后將打印出:
            My Name is Thread-0

            你也可以創(chuàng)建多個(gè)線程,像下面這樣
            				new Thread(new MyThread()).start();
            new Thread(new MyThread()).start();
            new Thread(new MyThread()).start();



            那么會(huì)打印出:
            My Name is Thread-0
            My Name is Thread-1
            My Name is Thread-2


            看了上面的結(jié)果,你可能會(huì)認(rèn)為線程的執(zhí)行順序是依次執(zhí)行的,但是那只是一般情況,千萬(wàn)不要用以為是線程的執(zhí)行機(jī)制;影響線程執(zhí)行順序的因素有幾點(diǎn):首先看看前面提到的優(yōu)先級(jí)別


            				public class MyThread implements Runnable
            {

            public void run()
            {
            System.out.println("My Name is "+Thread.currentThread().getName());
            }
            public static void main(String[] args)
            {
            Thread t1=new Thread(new MyThread());
            Thread t2=new Thread(new MyThread());
            Thread t3=new Thread(new MyThread());
            t2.setPriority(Thread.MAX_PRIORITY);//賦予最高優(yōu)先級(jí)
            t1.start();
            t2.start();
            t3.start();
            }
            }


            再看看結(jié)果:
            My Name is Thread-1
            My Name is Thread-0
            My Name is Thread-2



            線程的優(yōu)先級(jí)分為10級(jí),分別用1到10的整數(shù)代表,默認(rèn)情況是5。上面的t2.setPriority(Thread.MAX_PRIORITY)等價(jià)與t2.setPriority(10)
            然后是線程程序本身的設(shè)計(jì),比如使用sleep,yield,join,wait等方法(詳情請(qǐng)看JDKDocument)

            				public class MyThread implements Runnable
            {
            public void run()
            {
            try
            {
            int sleepTime=(int)(Math.random()*100);//產(chǎn)生隨機(jī)數(shù)字,
            Thread.currentThread().sleep(sleepTime);//讓其休眠一定時(shí)間,時(shí)間又上面sleepTime決定
            //public static void sleep(long millis)throw InterruptedException (API)
            System.out.println(Thread.currentThread().getName()+" 睡了 "+sleepTime);
            }catch(InterruptedException ie)//由于線程在休眠可能被中斷,所以調(diào)用sleep方法的時(shí)候需要捕捉異常
            {
            ie.printStackTrace();
            }
            }
            public static void main(String[] args)
            {
            Thread t1=new Thread(new MyThread());
            Thread t2=new Thread(new MyThread());
            Thread t3=new Thread(new MyThread());
            t1.start();
            t2.start();
            t3.start();
            }
            }


            執(zhí)行后觀察其輸出:

            Thread-0 睡了 11
            Thread-2 睡了 48
            Thread-1 睡了 69




            上面的執(zhí)行結(jié)果是隨機(jī)的,再執(zhí)行很可能出現(xiàn)不同的結(jié)果。由于上面我在run中添加了休眠語(yǔ)句,當(dāng)線程休眠的時(shí)候就會(huì)讓出cpu,cpu將會(huì)選擇執(zhí)行處于runnable狀態(tài)中的其他線程,當(dāng)然也可能出現(xiàn)這種情況,休眠的Thread立即進(jìn)入了runnable狀態(tài),cpu再次執(zhí)行它。
            [線程組概念]
            線程是可以被組織的,java中存在線程組的概念,每個(gè)線程都是一個(gè)線程組的成員,線程組把多個(gè)線程集成為一個(gè)對(duì)象,通過(guò)線程組可以同時(shí)對(duì)其中的多個(gè)線程進(jìn)行操作,如啟動(dòng)一個(gè)線程組的所有線程等.Java的線程組由java.lang包中的Thread——Group類實(shí)現(xiàn).
            ThreadGroup類用來(lái)管理一組線程,包括:線程的數(shù)目,線程間的關(guān)系,線程正在執(zhí)行的操作,以及線程將要啟動(dòng)或終止時(shí)間等.線程組還可以包含線程組.在Java的應(yīng)用程序中,最高層的線程組是名位main的線程組,在main中還可以加入線程或線程組,在mian的子線程組中也可以加入線程和線程組,形成線程組和線程之間的樹狀繼承關(guān)系。像上面創(chuàng)建的線程都是屬于main這個(gè)線程組的。
            借用上面的例子,main里面可以這樣寫:

            				public static void main(String[] args)
            {
            /***************************************
            ThreadGroup(String name)
            ThreadGroup(ThreadGroup parent, String name)
            ***********************************/
            ThreadGroup group1=new ThreadGroup("group1");
            ThreadGroup group2=new ThreadGroup(group1,"group2");
            Thread t1=new Thread(group2,new MyThread());
            Thread t2=new Thread(group2,new MyThread());
            Thread t3=new Thread(group2,new MyThread());
            t1.start();
            t2.start();
            t3.start();
            }



            線程組的嵌套,t1,t2,t3被加入group2,group2加入group1。
            另外一個(gè)比較多就是關(guān)于線程同步方面的,試想這樣一種情況,你有一筆存款在銀行,你在一家銀行為你的賬戶存款,而你的妻子在另一家銀行從這個(gè)賬戶提款,現(xiàn)在你有1000塊在你的賬戶里面。你存入了1000,但是由于另一方也在對(duì)這筆存款進(jìn)行操作,人家開始執(zhí)行的時(shí)候只看到賬戶里面原來(lái)的1000元,當(dāng)你的妻子提款1000元后,你妻子所在的銀行就認(rèn)為你的賬戶里面沒有錢了,而你所在的銀行卻認(rèn)為你還有2000元。
            看看下面的例子:

            				class BlankSaving //儲(chǔ)蓄賬戶
            {
            private static int money=10000;
            public void add(int i)
            {
            money=money+i;
            System.out.println("Husband 向銀行存入了 [¥"+i+"]");
            }
            public void get(int i)
            {
            money=money-i;
            System.out.println("Wife 向銀行取走了 [¥"+i+"]");
            if(money<0)
            System.out.println("余額不足!");
            }
            public int showMoney()
            {
            return money;
            }
            }


            class Operater implements Runnable
            {
            String name;
            BlankSaving bs;
            public Operater(BlankSaving b,String s)
            {
            name=s;
            bs=b;



            }
            public static void oper(String name,BlankSaving bs)
            {



            if(name.equals("husband"))
            {
            try
            {
            for(int i=0;i<10;i++)
            {
            Thread.currentThread().sleep((int)(Math.random()*300));
            bs.add(1000);
            }
            }catch(InterruptedException e){}
            }else
            {
            try
            {



            for(int i=0;i<10;i++)
            {
            Thread.currentThread().sleep((int)(Math.random()*300));
            bs.get(1000);
            }
            }catch(InterruptedException e){}
            }
            }
            public void run()
            {
            oper(name,bs);
            }
            }
            public class BankTest
            {
            public static void main(String[] args)throws InterruptedException
            {
            BlankSaving bs=new BlankSaving();
            Operater o1=new Operater(bs,"husband");
            Operater o2=new Operater(bs,"wife");
            Thread t1=new Thread(o1);
            Thread t2=new Thread(o2);
            t1.start();
            t2.start();
            Thread.currentThread().sleep(500);
            }



            }



            下面是其中一次的執(zhí)行結(jié)果:



            ---------first--------------
            Husband 向銀行存入了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Husband 向銀行存入了 [¥1000]


            看到了嗎,這可不是正確的需求,在husband還沒有結(jié)束操作的時(shí)候,wife就插了進(jìn)來(lái),這樣很可能導(dǎo)致意外的結(jié)果。解決辦法很簡(jiǎn)單,就是將對(duì)數(shù)據(jù)進(jìn)行操作方法聲明為synchronized,當(dāng)方法被該關(guān)鍵字聲明后,也就意味著,如果這個(gè)數(shù)據(jù)被加鎖,只有一個(gè)對(duì)象得到這個(gè)數(shù)據(jù)的鎖的時(shí)候該對(duì)象才能對(duì)這個(gè)數(shù)據(jù)進(jìn)行操作。也就是當(dāng)你存款的時(shí)候,這筆賬戶在其他地方是不能進(jìn)行操作的,只有你存款完畢,銀行管理人員將賬戶解鎖,其他人才能對(duì)這個(gè)賬戶進(jìn)行操作。
            修改public static void oper(String name,BlankSaving bs)為public static void oper(String name,BlankSaving bs),再看看結(jié)果:

            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Husband 向銀行存入了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]
            Wife 向銀行取走了 [¥1000]




            當(dāng)丈夫完成操作后,妻子才開始執(zhí)行操作,這樣的話,對(duì)共享對(duì)象的操作就不會(huì)有問(wèn)題了。
            [wait and notify]
            你可以利用這兩個(gè)方法很好的控制線程的執(zhí)行流程,當(dāng)線程調(diào)用wait方法后,線程將被掛起,直到被另一線程喚醒(notify)或則是如果wait方法指定有時(shí)間得話,在沒有被喚醒的情況下,指定時(shí)間時(shí)間過(guò)后也將自動(dòng)被喚醒。但是要注意一定,被喚醒并不是指馬上執(zhí)行,而是從組塞狀態(tài)變?yōu)榭蛇\(yùn)行狀態(tài),其是否運(yùn)行還要看cpu的調(diào)度。
            事例代碼:

            				class MyThread_1 extends Thread
            {
            Object lock;
            public MyThread_1(Object o)
            {
            lock=o;
            }
            public void run()
            {
            try
            {
            synchronized(lock)
            {
            System.out.println("Enter Thread_1 and wait");
            lock.wait();
            System.out.println("be notified");
            }
            }catch(InterruptedException e){}
            }
            }
            class MyThread_2 extends Thread
            {
            Object lock;
            public MyThread_2(Object o)
            {
            lock=o;
            }
            public void run()
            {
            synchronized(lock)
            {
            System.out.println("Enter Thread_2 and notify");
            lock.notify();
            }
            }
            }
            public class MyThread
            {
            public static void main(String[] args)
            {
            int[] in=new int[0];//notice
            MyThread_1 t1=new MyThread_1(in);
            MyThread_2 t2=new MyThread_2(in);
            t1.start();
            t2.start();
            }
            }




            執(zhí)行結(jié)果如下:
            Enter Thread_1 and wait
            Enter Thread_2 and notify
            Thread_1 be notified


            可能你注意到了在使用wait and notify方法得時(shí)候我使用了synchronized塊來(lái)包裝這兩個(gè)方法,這是由于調(diào)用這兩個(gè)方法的時(shí)候線程必須獲得鎖,也就是上面代碼中的lock[],如果你不用synchronized包裝這兩個(gè)方法的得話,又或則鎖不一是同一把,比如在MyThread_2中synchronized(lock)改為synchronized(this),那么執(zhí)行這個(gè)程序的時(shí)候?qū)?huì)拋出java.lang.IllegalMonitorStateException執(zhí)行期異常。另外wait and notify方法是Object中的,并不在Thread這個(gè)類中。最后你可能注意到了這點(diǎn):int[] in=new int[0];為什么不是創(chuàng)建new Object而是一個(gè)0長(zhǎng)度的數(shù)組,那是因?yàn)樵趈ava中創(chuàng)建一個(gè)0長(zhǎng)度的數(shù)組來(lái)充當(dāng)鎖更加高效。

            Thread作為java中一重要組成部分,當(dāng)然還有很多地方需要更深刻的認(rèn)識(shí),上面只是對(duì)Thread的一些常識(shí)和易錯(cuò)問(wèn)題做了一個(gè)簡(jiǎn)要的總結(jié),若要真正的掌握java的線程,還需要自己多做總結(jié)
            posted @ 2006-07-12 16:38 Merlin 閱讀(388) | 評(píng)論 (0)編輯 收藏

            第一,談?wù)刦inal, finally, finalize的區(qū)別。

              
            final—修飾符(關(guān)鍵字)如果一個(gè)類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個(gè)類不能既被聲明為 abstract的,又被聲明為final的。將變量或方法聲明為final,可以保證它們?cè)谑褂弥胁槐桓淖儭1宦暶鳛閒inal的變量必須在聲明時(shí)給定初值,而在以后的引用中只能讀取,不可修改。被聲明為final的方法也同樣只能使用,不能重載。

              
            finally—再異常處理時(shí)提供 finally 塊來(lái)執(zhí)行任何清除操作。如果拋出一個(gè)異常,那么相匹配的 catch 子句就會(huì)執(zhí)行,然后控制就會(huì)進(jìn)入 finally 塊(如果有的話)。

              
            finalize—方法名。Java 技術(shù)允許使用 finalize() 方法在垃圾收集器將對(duì)象從內(nèi)存中清除出去之前做必要的清理工作。這個(gè)方法是由垃圾收集器在確定這個(gè)對(duì)象沒有被引用時(shí)對(duì)這個(gè)對(duì)象調(diào)用的。它是在 Object 類中定義的,因此所有的類都繼承了它。子類覆蓋 finalize() 方法以整理系統(tǒng)資源或者執(zhí)行其他清理工作。finalize() 方法是在垃圾收集器刪除對(duì)象之前對(duì)這個(gè)對(duì)象調(diào)用的。


              
            第二,Anonymous Inner Class (匿名內(nèi)部類) 是否可以extends(繼承)其它類,是否可以implements(實(shí)現(xiàn))interface(接口)?

              
            匿名的內(nèi)部類是沒有名字的內(nèi)部類。不能extends(繼承) 其它類,但一個(gè)內(nèi)部類可以作為一個(gè)接口,由另一個(gè)內(nèi)部類實(shí)現(xiàn)。


              
            第三,Static Nested Class 和 Inner Class的不同,說(shuō)得越多越好(面試題有的很籠統(tǒng))。

              
            Nested Class (一般是C++的說(shuō)法),Inner Class (一般是JAVA的說(shuō)法)。Java內(nèi)部類與C++嵌套類最大的不同就在于是否有指向外部的引用上。具體可見http: //www.frontfree.net/articles/services/view.asp?id=704&page=1

              
            注: 靜態(tài)內(nèi)部類(Inner Class)意味著1創(chuàng)建一個(gè)static內(nèi)部類的對(duì)象,不需要一個(gè)外部類對(duì)象,2不能從一個(gè)static內(nèi)部類的一個(gè)對(duì)象訪問(wèn)一個(gè)外部類對(duì)象


              
            第四,&和&&的區(qū)別。

              
            &是位運(yùn)算符。&&是布爾邏輯運(yùn)算符。


              
            第五,HashMap和Hashtable的區(qū)別。

              
            都屬于Map接口的類,實(shí)現(xiàn)了將惟一鍵映射到特定的值上。

              
            HashMap 類沒有分類或者排序。它允許一個(gè) null 鍵和多個(gè) null 值。

              
            Hashtable 類似于 HashMap,但是不允許 null 鍵和 null 值。它也比 HashMap 慢,因?yàn)樗峭降摹?br />

              
            第六,Collection 和 Collections的區(qū)別。

              
            Collections是個(gè)java.util下的類,它包含有各種有關(guān)集合操作的靜態(tài)方法。

              
            Collection是個(gè)java.util下的接口,它是各種集合結(jié)構(gòu)的父接口。



              
            第七,什么時(shí)候用assert。

              
            斷言是一個(gè)包含布爾表達(dá)式的語(yǔ)句,在執(zhí)行這個(gè)語(yǔ)句時(shí)假定該表達(dá)式為 true。如果表達(dá)式計(jì)算為 false,那么系統(tǒng)會(huì)報(bào)告一個(gè) Assertionerror。它用于調(diào)試目的:

              
            assert(a > 0); // throws an Assertionerror if a <= 0

              

            斷言可以有兩種形式:

              
            assert Expression1 ;

             
            assert Expression1 : Expression2 ;

              
            Expression1 應(yīng)該總是產(chǎn)生一個(gè)布爾值。

              
            Expression2 可以是得出一個(gè)值的任意表達(dá)式。這個(gè)值用于生成顯示更多調(diào)試信息的 String 消息。

              
            斷言在默認(rèn)情況下是禁用的。要在編譯時(shí)啟用斷言,需要使用 source 1.4 標(biāo)記:

              
            javac -source 1.4 Test.java

              
            要在運(yùn)行時(shí)啟用斷言,可使用 -enableassertions 或者 -ea 標(biāo)記。

              
            要在運(yùn)行時(shí)選擇禁用斷言,可使用 -da 或者 -disableassertions 標(biāo)記。

              
            要系統(tǒng)類中啟用斷言,可使用 -esa 或者 -dsa 標(biāo)記。還可以在包的基礎(chǔ)上啟用或者禁用斷言。

              
            可以在預(yù)計(jì)正常情況下不會(huì)到達(dá)的任何位置上放置斷言。斷言可以用于驗(yàn)證傳遞給私有方法的參數(shù)。不過(guò),斷言不應(yīng)該用于驗(yàn)證傳遞給公有方法的參數(shù),因?yàn)椴还苁欠駟⒂昧藬嘌裕蟹椒ǘ急仨殭z查其參數(shù)。不過(guò),既可以在公有方法中,也可以在非公有方法中利用斷言測(cè)試后置條件。另外,斷言不應(yīng)該以任何方式改變程序的狀態(tài)。


              
            第八,GC是什么? 為什么要有GC? (基礎(chǔ))。

              
            GC是垃圾收集器。Java 程序員不用擔(dān)心內(nèi)存管理,因?yàn)槔占鲿?huì)自動(dòng)進(jìn)行管理。要請(qǐng)求垃圾收集,可以調(diào)用下面的方法之一:

              
            System.gc()

              
            Runtime.getRuntime().gc()


              
            第九,String s = new String("xyz");創(chuàng)建了幾個(gè)String Object?

              
            兩個(gè)對(duì)象,一個(gè)是"xyx",一個(gè)是指向"xyx"的引用對(duì)象s。


              
            第十,Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

                
            Math.round(11.5)返回(long)12,Math.round(-11.5)返回(long)-11;


              
            第十一,short s1 = 1; s1 = s1 + 1;有什么錯(cuò)? short s1 = 1; s1 += 1;有什么錯(cuò)?

              
            short s1 = 1; s1 = s1 + 1;有錯(cuò),s1是short型,s1+1是int型,不能顯式轉(zhuǎn)化為short型。可修改為s1 =(short)(s1 + 1) 。short s1 = 1; s1 += 1正確。


              
            第十二,sleep() 和 wait() 有什么區(qū)別? 搞線程的最愛

              
            sleep()方法是使線程停止一段時(shí)間的方法。在sleep 時(shí)間間隔期滿后,線程不一定立即恢復(fù)執(zhí)行。這是因?yàn)樵谀莻€(gè)時(shí)刻,其它線程可能正在運(yùn)行而且沒有被調(diào)度為放棄執(zhí)行,除非

            (a)"醒來(lái)"的線程具有更高的優(yōu)先級(jí)。

              
            (b)正在運(yùn)行的線程因?yàn)槠渌蚨枞?br />
              
            wait()是線程交互時(shí),如果線程對(duì)一個(gè)同步對(duì)象x 發(fā)出一個(gè)wait()調(diào)用,該線程會(huì)暫停執(zhí)行,被調(diào)對(duì)象進(jìn)入等待狀態(tài),直到被喚醒或等待時(shí)間到。


              
            第十三,Java有沒有g(shù)oto?

              
            Goto—java中的保留字,現(xiàn)在沒有在java中使用。


              
            第十四,數(shù)組有沒有l(wèi)ength()這個(gè)方法? String有沒有l(wèi)ength()這個(gè)方法?

              
            數(shù)組沒有l(wèi)ength()這個(gè)方法,有l(wèi)ength的屬性。

              
            String有有l(wèi)ength()這個(gè)方法。


              
            第十五,Overload和Override的區(qū)別。Overloaded的方法是否可以改變返回值的類型?

              
            方法的重寫Overriding和重載Overloading是Java多態(tài)性的不同表現(xiàn)。重寫Overriding是父類與子類之間多態(tài)性的一種表現(xiàn),重載Overloading是一個(gè)類中多態(tài)性的一種表現(xiàn)。如果在子類中定義某方法與其父類有相同的名稱和參數(shù),我們說(shuō)該方法被重寫 (Overriding)。子類的對(duì)象使用這個(gè)方法時(shí),將調(diào)用子類中的定義,對(duì)它而言,父類中的定義如同被"屏蔽"了。如果在一個(gè)類中定義了多個(gè)同名的方法,它們或有不同的參數(shù)個(gè)數(shù)或有不同的參數(shù)類型,則稱為方法的重載(Overloading)。Overloaded的方法是可以改變返回值的類型。


              
            第十六,Set里的元素是不能重復(fù)的,那么用什么方法來(lái)區(qū)分重復(fù)與否呢? 是用==還是equals()? 它們有何區(qū)別?

              
            Set里的元素是不能重復(fù)的,那么用iterator()方法來(lái)區(qū)分重復(fù)與否。equals()是判讀兩個(gè)Set是否相等。

              
            equals()和==方法決定引用值是否指向同一對(duì)象equals()在類中被覆蓋,為的是當(dāng)兩個(gè)分離的對(duì)象的內(nèi)容和類型相配的話,返回真值。


              
            第十七,給我一個(gè)你最常見到的runtime exception。

              
            ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException, EmptyStackException, IllegalArgumentException, IllegalMonitorStateException, IllegalPathStateException, IllegalStateException,   ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NullPointerException, ProfileDataException, ProviderException, RasterFORMatException, SecurityException, SystemException, UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException


              
            第十八,error和exception有什么區(qū)別?

              
            error 表示恢復(fù)不是不可能但很困難的情況下的一種嚴(yán)重問(wèn)題。比如說(shuō)內(nèi)存溢出。不可能指望程序能處理這樣的情況。

              
            exception 表示一種設(shè)計(jì)或?qū)崿F(xiàn)問(wèn)題。也就是說(shuō),它表示如果程序運(yùn)行正常,從不會(huì)發(fā)生的情況。


              
            第十九,List, Set, Map是否繼承自Collection接口?

              
            List,Set是

              
            Map不是


              
            第二十,abstract class和interface有什么區(qū)別?

              
            聲明方法的存在而不去實(shí)現(xiàn)它的類被叫做抽象類(abstract class),它用于要?jiǎng)?chuàng)建一個(gè)體現(xiàn)某些基本行為的類,并為該類聲明方法,但不能在該類中實(shí)現(xiàn)該類的情況。不能創(chuàng)建abstract 類的實(shí)例。然而可以創(chuàng)建一個(gè)變量,其類型是一個(gè)抽象類,并讓它指向具體子類的一個(gè)實(shí)例。不能有抽象構(gòu)造函數(shù)或抽象靜態(tài)方法。Abstract 類的子類為它們父類中的所有抽象方法提供實(shí)現(xiàn),否則它們也是抽象類為。取而代之,在子類中實(shí)現(xiàn)該方法。知道其行為的其它類可以在類中實(shí)現(xiàn)這些方法。

              
            接口(interface)是抽象類的變體。在接口中,所有方法都是抽象的。多繼承性可通過(guò)實(shí)現(xiàn)這樣的接口而獲得。接口中的所有方法都是抽象的,沒有一個(gè)有程序體。接口只可以定義static final成員變量。接口的實(shí)現(xiàn)與子類相似,除了該實(shí)現(xiàn)類不能從接口定義中繼承行為。當(dāng)類實(shí)現(xiàn)特殊接口時(shí),它定義(即將程序體給予)所有這種接口的方法。然后,它可以在實(shí)現(xiàn)了該接口的類的任何對(duì)象上調(diào)用接口的方法。由于有抽象類,它允許使用接口名作為引用變量的類型。通常的動(dòng)態(tài)聯(lián)編將生效。引用可以轉(zhuǎn)換到接口類型或從接口類型轉(zhuǎn)換,instanceof 運(yùn)算符可以用來(lái)決定某對(duì)象的類是否實(shí)現(xiàn)了接口。


              
            第二十一,abstract的method是否可同時(shí)是static,是否可同時(shí)是native,是否可同時(shí)是synchronized?

              
            都不能


              
            第二十二,接口是否可繼承接口? 抽象類是否可實(shí)現(xiàn)(implements)接口? 抽象類是否可繼承實(shí)體類(concrete class)?

              
            接口可以繼承接口。抽象類可以實(shí)現(xiàn)(implements)接口,抽象類是否可繼承實(shí)體類,但前提是實(shí)體類必須有明確的構(gòu)造函數(shù)。


             
            第二十三,啟動(dòng)一個(gè)線程是用run()還是start()?

              
            啟動(dòng)一個(gè)線程是調(diào)用start()方法,使線程所代表的虛擬處理機(jī)處于可運(yùn)行狀態(tài),這意味著它可以由JVM調(diào)度并執(zhí)行。這并不意味著線程就會(huì)立即運(yùn)行。run()方法可以產(chǎn)生必須退出的標(biāo)志來(lái)停止一個(gè)線程。


              
            第二十四,構(gòu)造器Constructor是否可被override?

              
            構(gòu)造器Constructor不能被繼承,因此不能重寫Overriding,但可以被重載Overloading。


              
            第二十五,是否可以繼承String類?

              
            String類是final類故不可以繼承。


              
            第二十六,當(dāng)一個(gè)線程進(jìn)入一個(gè)對(duì)象的一個(gè)synchronized方法后,其它線程是否可進(jìn)入此對(duì)象的其它方法?

              
            不能,一個(gè)對(duì)象的一個(gè)synchronized方法只能由一個(gè)線程訪問(wèn)。


              
            第二十七,try {}里有一個(gè)return語(yǔ)句,那么緊跟在這個(gè)try后的finally {}里的code會(huì)不會(huì)被執(zhí)行,什么時(shí)候被執(zhí)行,在return前還是后?

              
            會(huì)執(zhí)行,在return前執(zhí)行。


              
            二十八,編程題: 用最有效率的方法算出2乘以8等於幾?

              
            有C背景的程序員特別喜歡問(wèn)這種問(wèn)題。


              
            第二十九,兩個(gè)對(duì)象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對(duì)不對(duì)?

             
            不對(duì),有相同的hash code。


              
            第三十,當(dāng)一個(gè)對(duì)象被當(dāng)作參數(shù)傳遞到一個(gè)方法后,此方法可改變這個(gè)對(duì)象的屬性,并可返回變化后的結(jié)果,那么這里到底是值傳遞還是引用傳遞?

              
            是值傳遞。Java 編程語(yǔ)言只由值傳遞參數(shù)。當(dāng)一個(gè)對(duì)象實(shí)例作為一個(gè)參數(shù)被傳遞到方法中時(shí),參數(shù)的值就是對(duì)該對(duì)象的引用。對(duì)象的內(nèi)容可以在被調(diào)用的方法中改變,但對(duì)象的引用是永遠(yuǎn)不會(huì)改變的。


              
            第三十一,swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?

              
            switch(expr1)中,expr1是一個(gè)整數(shù)表達(dá)式。因此傳遞給 switch 和 case 語(yǔ)句的參數(shù)應(yīng)該是 int、 short、 char 或者 byte。long,string 都不能作用于swtich。


              
            第三十二,編程題: 寫一個(gè)Singleton出來(lái)。

              
            Singleton模式主要作用是保證在Java應(yīng)用程序中,一個(gè)類Class只有一個(gè)實(shí)例存在。

             
            一般Singleton模式通常有幾種種形式:

              
            第一種形式: 定義一個(gè)類,它的構(gòu)造函數(shù)為private的,它有一個(gè)static的private的該類變量,在類初始化時(shí)實(shí)例話,通過(guò)一個(gè)public的getInstance方法獲取對(duì)它的引用,繼而調(diào)用其中的方法。

              
            public class Singleton {

              
            private Singleton(){}

              
            //在自己內(nèi)部定義自己一個(gè)實(shí)例,是不是很奇怪?

              
            //注意這是private 只供內(nèi)部調(diào)用

              
            private static Singleton instance = new Singleton();

              
            //這里提供了一個(gè)供外部訪問(wèn)本class的靜態(tài)方法,可以直接訪問(wèn)  

              
            public static Singleton getInstance() {

              
            return instance;   

              
            }

              
            }


              
            第二種形式:

              
            public class Singleton {

              
            private static Singleton instance = null;

              
            public static synchronized Singleton getInstance() {

              
            //這個(gè)方法比上面有所改進(jìn),不用每次都進(jìn)行生成對(duì)象,只是第一次 

                  
             //使用時(shí)生成實(shí)例,提高了效率!

              
            if (instance==null)

              
            instance=new Singleton();

              
            return instance;   }

              
            }

              
            其他形式:

              
            定義一個(gè)類,它的構(gòu)造函數(shù)為private的,所有方法為static的。

              
            一般認(rèn)為第一種形式要更加安全些

              
            Hashtable和HashMap

              
            Hashtable繼承自Dictionary類,而HashMap是Java1.2引進(jìn)的Map interface的一個(gè)實(shí)現(xiàn)

              
            HashMap允許將null作為一個(gè)entry的key或者value,而Hashtable不允許

              
            還有就是,HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因?yàn)閏ontains方法容易讓人引起誤解。

              
            最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在

              
            多個(gè)線程訪問(wèn)Hashtable時(shí),不需要自己為它的方法實(shí)現(xiàn)同步,而HashMap

              
            就必須為之提供外同步。

              
            Hashtable和HashMap采用的hash/rehash算法都大概一樣,所以性能不會(huì)有很大的差異。
            posted @ 2006-07-12 16:02 Merlin 閱讀(343) | 評(píng)論 (1)編輯 收藏

            2006年7月11日 #

            《Thinking in Java》
            《J2EE技術(shù)實(shí)踐》
            《JAVA高效編程指南》

            《Sleepless in Java》 下載地址: http://www.shnenglu.com/Files/yunduan5158/SleeplessInJava.rar ?
            ?
            posted @ 2006-07-11 22:34 Merlin 閱讀(230) | 評(píng)論 (0)編輯 收藏

            近期到CSDN論壇看看一些網(wǎng)友貼的面試題,其中關(guān)于String的問(wèn)題常常被提及。我一直以為自己很清楚這個(gè)東西了,其實(shí)深究起來(lái),發(fā)現(xiàn)自己并不那么清楚,會(huì)犯一些錯(cuò)誤;同時(shí)也產(chǎn)生了一些聯(lián)想。小結(jié)一下。

            1、"abc"與new String("abc");
            ????經(jīng)常會(huì)問(wèn)到的面試題:String s = new String("abc");創(chuàng)建了幾個(gè)String Object?【如這里創(chuàng)建了多少對(duì)象? 和一道小小的面試題 】

            ????這個(gè)問(wèn)題比較簡(jiǎn)單,涉及的知識(shí)點(diǎn)包括:

            引用變量與對(duì)象的區(qū)別;
            字符串文字"abc"是一個(gè)String對(duì)象;
            文字池[pool of literal strings]和堆[heap]中的字符串對(duì)象。
            ????一、引用變量與對(duì)象:除了一些早期的Java書籍和現(xiàn)在的垃圾書籍,人們都可以從中比較清楚地學(xué)習(xí)到兩者的區(qū)別。A aa;語(yǔ)句聲明一個(gè)類A的引用變量aa[我常常稱之為句柄],而對(duì)象一般通過(guò)new創(chuàng)建。所以題目中s僅僅是一個(gè)引用變量,它不是對(duì)象。[ref 句柄、引用與對(duì)象]

            ????二、Java中所有的字符串文字[字符串常量]都是一個(gè)String的對(duì)象。有人[特別是C程序員]在一些場(chǎng)合喜歡把字符串"當(dāng)作/看成"字符數(shù)組,這也沒有辦法,因?yàn)樽址c字符數(shù)組存在一些內(nèi)在的聯(lián)系。事實(shí)上,它與字符數(shù)組是兩種完全不同的對(duì)象。

            ????????System.out.println("Hello".length());
            ????????char[] cc={'H','i'};
            ????????System.out.println(cc.length);

            ????三、字符串對(duì)象的創(chuàng)建:由于字符串對(duì)象的大量使用[它是一個(gè)對(duì)象,一般而言對(duì)象總是在heap分配內(nèi)存],Java中為了節(jié)省內(nèi)存空間和運(yùn)行時(shí)間[如比較字符串時(shí),==比equals()快],在編譯階段就把所有的字符串文字放到一個(gè)文字池[pool of literal strings]中,而運(yùn)行時(shí)文字池成為常量池的一部分。文字池的好處,就是該池中所有相同的字符串常量被合并,只占用一個(gè)空間。我們知道,對(duì)兩個(gè)引用變量,使用==判斷它們的值[引用]是否相等,即指向同一個(gè)對(duì)象:

            				String s1 = "abc" ;
            String s2 = "abc" ;
            if( s1 == s2 )
            ????System.out.println("s1,s2 refer to the same object");
            else???? System.out.println("trouble");


            ????這里的輸出顯示,兩個(gè)字符串文字保存為一個(gè)對(duì)象。就是說(shuō),上面的代碼只在pool中創(chuàng)建了一個(gè)String對(duì)象。

            ????現(xiàn)在看String s = new String("abc");語(yǔ)句,這里"abc"本身就是pool中的一個(gè)對(duì)象,而在運(yùn)行時(shí)執(zhí)行new String()時(shí),將pool中的對(duì)象復(fù)制一份放到heap中,并且把heap中的這個(gè)對(duì)象的引用交給s持有。ok,這條語(yǔ)句就創(chuàng)建了2個(gè)String對(duì)象。

            				String s1 = new String("abc") ;
            String s2 = new String("abc") ;
            if( s1 == s2 ){ //不會(huì)執(zhí)行的語(yǔ)句}


            ????這時(shí)用==判斷就可知,雖然兩個(gè)對(duì)象的"內(nèi)容"相同[equals()判斷],但兩個(gè)引用變量所持有的引用不同,

            ????BTW:上面的代碼創(chuàng)建了幾個(gè)String Object? [三個(gè),pool中一個(gè),heap中2個(gè)。]
            ????[Java2 認(rèn)證考試學(xué)習(xí)指南 (第4版)( 英文版)p197-199有圖解。]


            2、字符串的+運(yùn)算和字符串轉(zhuǎn)換
            ????字符串轉(zhuǎn)換和串接是很基礎(chǔ)的內(nèi)容,因此我以為這個(gè)問(wèn)題簡(jiǎn)直就是送分題。事實(shí)上,我自己就答錯(cuò)了。

            String str = new String("jf"); // jf是接分
            str = 1+2+str+3+4;
            一共創(chuàng)建了多少String的對(duì)象?[我開始的答案:5個(gè)。jf、new、3jf、3jf3、3jf34]

            ????首先看JLS的有關(guān)論述:

            ????一、字符串轉(zhuǎn)換的環(huán)境[JLS 5.4 String Conversion]

            ????字符串轉(zhuǎn)換環(huán)境僅僅指使用雙元的+運(yùn)算符的情況,其中一個(gè)操作數(shù)是一個(gè)String對(duì)象。在這一特定情形下,另一操作數(shù)轉(zhuǎn)換成String,表達(dá)式的結(jié)果是這兩個(gè)String的串接。

            ????二、串接運(yùn)算符[JLS 15.18.1 String Concatenation Operator + ]

            ????如果一個(gè)操作數(shù)/表達(dá)式是String類型,則另一個(gè)操作數(shù)在運(yùn)行時(shí)轉(zhuǎn)換成一個(gè)String對(duì)象,并兩者串接。此時(shí),任何類型都可以轉(zhuǎn)換成String。[這里,我漏掉了"3"和"4"]

            如果是基本數(shù)據(jù)類型,則如同首先轉(zhuǎn)換成其包裝類對(duì)象,如int x視為轉(zhuǎn)換成Integer(x)。
            現(xiàn)在就全部統(tǒng)一到引用類型向String的轉(zhuǎn)換了。這種轉(zhuǎn)換如同[as if]調(diào)用該對(duì)象的無(wú)參數(shù)toString方法。[如果是null則轉(zhuǎn)換成"null"]。因?yàn)閠oString方法在Object中定義,故所有的類都有該方法,而且Boolean, Character, Integer, Long, Float, Double, and String改寫了該方法。
            關(guān)于+是串接還是加法,由操作數(shù)決定。1+2+str+3+4 就很容易知道是"3jf34"。[BTW :在JLS的15.18.1.3中舉的一個(gè)jocular little example,真的很無(wú)趣。]
            ????下面的例子測(cè)試了改寫toString方法的情況.。

            				class A{
            ????int i = 10;
            ????public static void main(String []args){
            ????????String str = new String("jf");
            ????????str += new A();
            ????????System.out.print(str);
            ????}

            ????public String toString(){
            ????????return " a.i ="+i+"\n";
            ????}
            }


            三、字符串轉(zhuǎn)換的優(yōu)化

            按照上述說(shuō)法,str = 1+2+str+3+4;語(yǔ)句似乎應(yīng)該就應(yīng)該生成5個(gè)String對(duì)象:

            1+2 =3,then 3→Integer(3)→"3" in pool? [假設(shè)如此]
            "3"+str(in heap) = "3jf"???? (in heap)
            "3jf" +3 ,first 3→Integer(3)→"3" in pool? [則不創(chuàng)建] then "3jf3"
            "3jf3"+4 create "4"??in pool
            then "3jf34"

            ????這里我并不清楚3、4轉(zhuǎn)換成字符串后是否在池中,所以上述結(jié)果仍然是猜測(cè)。

            ????為了減少創(chuàng)建中間過(guò)渡性的字符串對(duì)象,提高反復(fù)進(jìn)行串接運(yùn)算時(shí)的性能,a Java compiler可以使用StringBuffer或者類似的技術(shù),或者把轉(zhuǎn)換與串接合并成一步。例如:對(duì)于 a + b + c ,Java編譯器就可以將它視為[as if]

            ????new StringBuffer().append(a).append(b).append(c).toString();

            ????注意,對(duì)于基本類型和引用類型,在append(a)過(guò)程中仍然要先將參數(shù)轉(zhuǎn)換,從這個(gè)觀點(diǎn)看,str = 1+2+str+3+4;創(chuàng)建的字符串可能是"3"、"4"和"3jf34"[以及一個(gè)StringBuffer對(duì)象]。

            ????現(xiàn)在我仍然不知道怎么回答str = 1+2+str+3+4;創(chuàng)建了多少String的對(duì)象,。或許,這個(gè)問(wèn)題不需要過(guò)于研究,至少SCJP不會(huì)考它。

            3、這又不同:str = "3"+"jf"+"3"+"4";
            ????如果是一個(gè)完全由字符串文字組成的表達(dá)式,則在編譯時(shí),已經(jīng)被優(yōu)化而不會(huì)在運(yùn)行時(shí)創(chuàng)建中間字符串。測(cè)試代碼如下:

            				String str1 ="3jf34";
            ????????String str2 ="3"+"jf"+"3"+"4";
            ????????if(str1 == str2) {
            ????????????System.out.println("str1 == str2");
            ????????}else {
            ????????????System.out.println("think again");
            ????????}
            ????????if(str2.equals(str1))
            ????????????System.out.println("yet str2.equals(str1)");


            ????可見,str1與str2指向同一個(gè)對(duì)象,這個(gè)對(duì)象在pool中。所有遵循Java Language Spec的編譯器都必須在編譯時(shí)對(duì)constant expressions 進(jìn)行簡(jiǎn)化。JLS規(guī)定:Strings computed by constant expressions (&yacute;15.28) are computed at compile time and then treated as if they were literals.

            ????對(duì)于String str2 ="3"+"jf"+"3"+"4";我們說(shuō)僅僅創(chuàng)建一個(gè)對(duì)象。注意,“創(chuàng)建多少對(duì)象”的討論是說(shuō)運(yùn)行時(shí)創(chuàng)建多少對(duì)象。

            ????BTW:編譯時(shí)優(yōu)化

            				????String x = "aaa " + "bbb ";
            ????if (false) {
            ????????x = x + "ccc ";
            ????}
            ????x +=??"ddd ";

            ????等價(jià)于:

            ????String x = "aaa bbb ";
            ????x = x + "ddd ";
            //這個(gè)地方我自己進(jìn)行了編譯,不過(guò)和他的結(jié)論不一樣,好像當(dāng)用x+="ddd"的時(shí)候和直接的x="aaa"+"bbb"+"ddd" 不同,但是具體為什么我也不清楚,正在研究中。。。

            4、不變類
            ????String對(duì)象是不可改變的(immutable)。有人對(duì)str = 1+2+str+3+4;語(yǔ)句提出疑問(wèn),怎么str的內(nèi)容可以改變?其實(shí)仍然是因?yàn)椴磺宄阂米兞颗c對(duì)象的區(qū)別。str僅僅是引用變量,它的值——它持有的引用可以改變。你不停地創(chuàng)建新對(duì)象,我就不斷地改變指向。[參考TIJ的Read-only classes。]

            ????不變類的關(guān)鍵是,對(duì)于對(duì)象的所有操作都不可能改變?cè)瓉?lái)的對(duì)象[只要需要,就返回一個(gè)改變了的新對(duì)象]。這就保證了對(duì)象不可改變。為什么要將一個(gè)類設(shè)計(jì)成不變類?有一個(gè)OOD設(shè)計(jì)的原則:Law of Demeter。其廣義解讀是:

            ????使用不變類。只要有可能,類應(yīng)當(dāng)設(shè)計(jì)為不變類。
            posted @ 2006-07-11 22:29 Merlin 閱讀(386) | 評(píng)論 (0)編輯 收藏

            abstract class和interface在Java語(yǔ)言中都是用來(lái)進(jìn)行抽象類定義的

            Interface ,給外界的接口,按照規(guī)定辦事;
            Abstract??,內(nèi)部繼承關(guān)系;

            interface 就是一組操作的集合,它定義了一個(gè)行為集但不作任何具體的實(shí)現(xiàn),這樣的話,具體的操作 都可以放在實(shí)現(xiàn)類中去,
            ??????????體現(xiàn)設(shè)計(jì)與實(shí)現(xiàn)分離的設(shè)計(jì)思想。

            在面向?qū)ο蟮母拍钪校械膶?duì)象都是通過(guò)類來(lái)描繪,如果一個(gè)類中沒有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象,這樣的類就是抽象類
            抽象概念在問(wèn)題領(lǐng)域沒有對(duì)應(yīng)的具體概念,所以用以表征抽象概念的抽象類是不能夠?qū)嵗摹?br />
            =====================================================================================================================
            使用abstract class的方式定義Demo抽象類的方式如下:

            				abstract class Demo {
            abstract void method1();
            abstract void method2();

            }



            使用interface的方式定義Demo抽象類的方式如下:

            				interface Demo {
            void method1();
            void method2();

            }



            ====================================================================================================================
            從編程層面看abstract class和interface

            abstract class在Java語(yǔ)言中表示的是一種繼承關(guān)系,一個(gè)類只能使用一次繼承關(guān)系
            一個(gè)類卻可以實(shí)現(xiàn)多個(gè)interface

            在abstract class的定義中,我們可以賦予方法的默認(rèn)行為
            在interface的定義中,方法卻不能擁有默認(rèn)行為

            ======================================================================================================================
            例如要設(shè)計(jì)一個(gè)形狀類MShape,從此類可以派生 方形、圓形、三角形等子類。我們就可以將MShape這個(gè)父類設(shè)計(jì)為abstract類。

            比如,子類都有 color 屬性,因此可以把 color 這個(gè)數(shù)據(jù)成員,以及給 color 賦值的method均設(shè)計(jì)在父類中,
            這樣就不用在每個(gè)子類中設(shè)計(jì)相同的代碼來(lái)處理 color 這個(gè)屬性。
            而如果想計(jì)算幾何形狀的面積,由于各個(gè)幾何形狀的面積計(jì)算方式都不相同,所以把計(jì)算面積的method的處理放在父類中就不合適,
            但由于每個(gè)幾何形狀都需要用到這個(gè)method,因此可以在父類中只聲明計(jì)算面積的method "area()",而把具體的處理放在子類中定義。
            即把a(bǔ)rea()設(shè)計(jì)為抽象類。

            以下是程序代碼:
            //abstract類 MShape??????

            				abstract class MShape
            {
            ????????protected String color;?? //數(shù)據(jù)成員
            ????????public void setColor(String mcolor)?? //一般方法,定義了具體的處理
            ????????{
            ?????????? color=mcolor;
            ????????}
            ????????abstract void area();?? //抽象方法,沒有定義具體的處理
            }



            //方形類

            				class RectShape extends MShape
            {??????
            ????????int width,height,rectarea;????
            ????????public RectShape(int w,int h)
            ????????{??
            ???????????????? width=w;
            ???????????????? height=h;????????
            ????????}
            ????????public void area()??//計(jì)算面積
            ????????{??????????
            ??????????rectarea=width*height;
            ????????}
            }



            //使用

            				public class myapp
            {
            ????????public static void main(String args[])
            ????????{
            ??????????RectShape rect=new RectShape(3,6);
            ??????????rect.setColor("Red");
            ??????????rect.area();
            ??????????System.out.print("color="+rect.color+", area="+rect.rectarea);
            ????????}
            }



            由此可見,在abstract中不僅可以定義一般的方法(即可以進(jìn)行具體處理的方法),還可以象interface一樣定義抽象方法。
            而在interface中只能定義抽象方法。

            posted @ 2006-07-11 19:53 Merlin 閱讀(421) | 評(píng)論 (0)編輯 收藏

            僅列出標(biāo)題  下一頁(yè)
            久久伊人中文无码| 久久免费小视频| 久久婷婷五月综合色99啪ak| 久久99精品久久久久久动态图| 欧美精品九九99久久在观看| 日日狠狠久久偷偷色综合免费| 狠狠久久综合伊人不卡| 久久国产成人精品麻豆| 久久99精品久久久久久| 久久免费视频观看| 婷婷综合久久狠狠色99h| 狠狠色丁香婷婷综合久久来| 国产亚洲欧美成人久久片| 国产亚洲欧美精品久久久| 久久狠狠高潮亚洲精品| 精品精品国产自在久久高清 | 日本欧美国产精品第一页久久| 国产伊人久久| 色综合合久久天天给综看| 亚洲欧美日韩久久精品| 久久久久高潮综合影院| 亚洲成色www久久网站夜月| 久久久久久亚洲Av无码精品专口| 久久久久亚洲精品无码蜜桃| 精品久久久久久久无码| 亚洲成人精品久久| 久久久WWW成人免费毛片| 伊人伊成久久人综合网777| 午夜天堂av天堂久久久| 久久国产精品无码HDAV| 99久久精品免费观看国产| 久久精品国产亚洲Aⅴ香蕉| 久久笫一福利免费导航| 日本人妻丰满熟妇久久久久久| 国产三级久久久精品麻豆三级| 亚洲天堂久久精品| 色婷婷综合久久久久中文字幕| 欧洲人妻丰满av无码久久不卡| 久久综合丝袜日本网| 欧美一区二区久久精品| 97精品国产91久久久久久|