• <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.

               :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
              34 隨筆 :: 0 文章 :: 40 評論 :: 0 Trackbacks

            2006年7月20日 #

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

            2006年7月19日 #

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

            Robocode 是一個很容易使用的機器人戰斗仿真器,可以在所有支持 Java 2 的平臺上運行。您創建一個機器人,把它放到戰場上,然后讓它同其他開發者們創建的機器人對手拼死戰斗到底。Robocode 里有一些預先做好的機器人對手讓你入門,但一旦您不再需要它們,就可以把您自己創建的機器人加入到正在世界范圍內形成的某個聯盟里去和世界最強手對陣。

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

            下載并安裝 Robocode

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

            java -jar robocode-setup.jar

            ?在安裝過程中,Robocode 將問您是否要使用這個外部的 Java VM 來編譯機器人。您也可以選擇使用作為 Robocode 分發包一部分而提供的 Jikes 編譯器。

            安裝完成后,您可以通過 shell 腳本(robocode.sh)、批處理文件(robocode.bat)或桌面上的圖標來啟動 Robocode 系統。此時,戰場將會出現。在此,您可以通過菜單調用 Robot Editor 和 compiler。





            回頁首


            Robocode 系統組件

            當您激活 Robocode 時,將看到兩個相關的 GUI 窗口,這兩個窗口構成了 Robocode 的 IDE:

            • 戰場
            • Robot Editor

            圖 1 展示了處于工作狀態的戰場和 Robot Editor。


            圖 1. Robocode IDE
            Robocode IDE

            戰場是機器人之間進行戰斗直至分出勝負的場地。主要的仿真引擎被置于其中,并且允許您在這里創建戰斗、保存戰斗以及打開新建的或現有的戰斗。通過界面區域內的控件,您可以暫停或繼續戰斗、終止戰斗、消滅任何機器人個體或獲取任何機器人的統計數據。此外,您可以在此屏幕上激活 Robot Editor。

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

            Robocode 里的每個機器人都由一個或多個 Java 類構成。這些類可以被壓縮成一個 JAR 包。為此,Robocode 的最新版本提供了一個可以在戰場 GUI 窗口中激活的“Robot Packager”。





            回頁首


            對 Robocode 機器人的詳細分析

            在寫這篇文章時,Robocode 機器人是一個圖形化的坦克。圖 2 是一個典型的 Robocode 機器人的圖解。


            圖 2. 對 Robocode 機器人的詳細分析
            Robocode 機器人

            請注意,機器人有一門可以旋轉的炮,炮上面的雷達也是可以旋轉的。機器人坦克車(Vehicle)、炮(Gun)以及雷達(Radar)都可以單獨旋轉,也就是說,在任何時刻,機器人坦克車、炮以及雷達都可以轉向不同的方向。缺省情況下,這些方向是一致的,都指向坦克車運動的方向。





            回頁首


            Robot 命令

            Robocode 機器人的命令集都收錄在 Robocode API Javadoc 中。您將會發現這些命令都是 robocode.Robot 類的公共方法。在這一部分,我們將分類討論每個可用的命令。

            移動機器人、炮和雷達

            讓我們從移動機器人及其裝備的基本命令開始:

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

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

            • setAdjustGunForRobotTurn(boolean flag) :如果 flag 被設置成 true,那么坦克車轉動時,炮保持原來的方向。
            • setAdjustRadarForRobotTurn(boolean flag) :如果 flag 被設置成 true,那么坦克車(和炮)轉動時,雷達會保持原來的方向。
            • setAdjustRadarForGunTurn(boolean flag) :如果 flag 被設置成 true,那么炮轉動時,雷達會保持原來的方向。而且,它執行的動作如同調用了 setAdjustRadarForRobotTurn(true)

            獲取關于機器人的信息

            有許多方法可以得到關于機器人的信息。下面簡單列舉了常用的方法調用:

            • getX()getY() 可以捕捉到機器人當前的坐標。
            • getHeading()getGunHeading()getRadarHeading() 可以得出坦克車、炮或雷達當前的方向,該方向是以角度表示的。
            • getBattleFieldWidth()getBattleFieldHeight() 可以得到當前這一回合的戰場尺寸。

            射擊命令

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

            事件

            每當機器人在移動或轉動時,雷達一直處于激活狀態,如果雷達檢測到有機器人在它的范圍內,就會觸發一個事件。作為機器人創建者,您有權選擇處理可能在戰斗中發生的各類事件。基本的 Robot 類中包括了所有這些事件的缺省處理程序。但是,您可以覆蓋其中任何一個“什么也不做的”缺省處理程序,然后實現您自己的定制行為。下面是一些較為常用的事件:

            • ScannedRobotEvent 。通過覆蓋 onScannedRobot() 方法來處理 ScannedRobotEvent ;當雷達檢測到機器人時,就調用該方法。
            • HitByBulletEvent 。通過覆蓋 onHitByBullet() 方法來處理 HitByBulletEvent ;當機器人被炮彈擊中時,就調用該方法。
            • HitRobotEvent 。通過覆蓋 onHitRobot() 方法來處理 HitRobotEvent ;當您的機器人擊中另外一個機器人時,就調用該方法。
            • HitWallEvent 。通過覆蓋 onHitWall() 方法來處理 HitWallEvent ;當您的機器人撞到墻時,就調用該方法。

            我們只需要知道這些就可以創建一些相當復雜的機器人了。您可以通過戰場的幫助菜單或 Robot Editor 的幫助菜單訪問 Javadoc 中其余的 Robocode API。

            現在,我們該把學到的知識付諸實踐了。





            回頁首


            創建機器人

            要創建一個新的機器人,請啟動 Robot Editor 并選擇 File-> New-> Robot。系統將會提示您輸入機器人的名稱,這個名稱將成為 Java 類名。請您在提示符處輸入 DWStraight。接下來,系統還會提示您輸入一個獨一無二的包前綴,它將用作存放機器人(還可能有相關的 Java 文件)的包的名稱。請在該提示符處輸入 dw

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


            清單 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);
                }
            }
            
            												
            										

            突出顯示的區域就是我們添加控制機器人的代碼的地方:

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

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

            Area 3
            這是典型的 run() 方法實現的第二部分。在此,我們將在無限 while 循環內對機器人可能執行的重復行為進行編程。

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

            我們對第一個機器人(DWStraight)的代碼的更新如清單 2 中紅色標記所示。


            清單 2. DWStraight 機器人代碼的增加部分
            												
            														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);
                }
                  
            }
            
            												
            										

            下面我們逐區地描述這個第一個機器人將做些什么:

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

            Area 2
            為了使機器人處于已知的狀態,我們通過 turnLeft(getHeading()) 使它轉到 0 度的方向。

            Area 3
            在這個重復性的部分,我們使用語句 ahead(1000) 讓機器人盡其所能向前移動到最遠的地方。當機器人撞到墻或其他機器人時,就會停下來。接著,我們通過 turnRight(90) 使它向右轉。在重復執行這一行為時,機器人基本上是在沿著墻按順時針方向移動。

            Area 4
            在此,除處理自動生成的 ScannedRobot 事件并向被發現的機器人直接射擊之外,我們還會檢測 HitByBullet 事件,并且讓機器人在被擊中的時候轉過 180 度(沿順時針方向或逆時針方向)。





            回頁首


            編譯以及測試機器人

            在 Robot Editor 菜單上選擇 Compiler-> Compile編譯您的機器人代碼。現在我們可以嘗試第一回合的戰斗了。切換回戰場并選擇菜單上的 Battle-> New,將會出現一個類似于圖 3 中所示的對話框。


            圖 3. New Battle 對話框
            New Battle 對話框

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

            當您準備開始研究另外一個機器人的代碼時,請先看看隨 參考資料 中的代碼分發包一起提供的 dw.DWRotater 這個機器人的代碼。在缺省情況下,這個機器人將會:

            • 移動到戰場中心
            • 一直轉動它的炮,直到檢測到機器人
            • 每次嘗試以不同的角度在離被檢測到的機器人前方不遠的地方射擊
            • 每當它被另外一個機器人擊中時,它都會迅速的來回移動

            這段代碼簡單易懂,所以我們在這里就不做分析了,但是我鼓勵您試驗一下。Robocode 中的 sample 包還提供了許多其他機器人的代碼。

            附加的機器人支持類

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

            其他 Robot 子類

            任何人都可以創建 Robot 子類并添加用于構建機器人的新功能。Robocode 提供了一個叫做 AdvancedRobotRobot 子類,它允許異步 API 調用。雖然對 AdvancedRobot 類的描述超出了本文的范圍,但我鼓勵您在掌握了基本的 Robot 類的操作后,試驗一下這個高級類。

            設計 Robocode 的目的

            我碰見了 Robocode 的創建者 Mathew Nelson,向他請教創建 Robocode 最初的設計目的。Mat 所說的是:“編寫 Robocode 的一部分目的是為了向世界證明:象‘Java 比較慢’以及‘Java 不可以用來寫游戲’之類的論斷不再正確。我認為我證明了這一點。”





            回頁首


            戰斗仿真器的體系結構

            通過“在后臺”對 Robocode 進行分析,我們發現復雜的仿真引擎既具高性能(為了以現實的速度生成戰斗)又具靈活性(使創建復雜的機器人邏輯不存在障礙)。特別感謝 Robocode 的創建者 Mathew Nelson 無私的提供了仿真引擎體系結構的內部信息。

            利用 Java 平臺進行設計

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


            圖 4. Robocode 仿真引擎體系結構
            仿真引擎

            請注意,所仿真的每個機器人都在它自己的 Java 線程上,它可以在任何可適用的地方利用 VM 本地線程映射機制。戰斗管理器線程是系統的控制器:它安排仿真并驅動圖形化的生成子系統。圖形化的生成子系統本身是基于 Java 2D 和 AWT 的。

            松散的線程耦合

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

            Robocode 內部結構

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

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

            戰斗管理器線程

            戰斗管理器線程管理機器人、炮彈及它們在戰場上的生成。仿真“時鐘”是根據戰場上生成的幀的數目來標記的。用戶可以調整真實的幀的速度。

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

            以下是戰斗管理器線程執行的邏輯的偽代碼:


            清單 3. 戰斗管理器的邏輯的偽代碼
            												
            														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
            
            												
            										

            請注意,在 for 循環內部,戰斗管理器線程的等待時間不會超過最大的時間間隔。如果機器人線程沒有及時調用阻塞 API(典型情況下是由于一些應用程序邏輯錯誤或無限循環),那么,它將繼續進行戰斗。生成一個 SkippedTurnEvent 并將其加入機器人事件隊列中,用來通知高級機器人。

            可替換的生成子系統

            AWT 和 Java 2D 線程就是當前實現中的生成子系統,它從戰斗管理器中獲取命令并生成戰場。它同系統的其余部分是完全分離的。我們可以預見到,在這個生成子系統將來的修訂版中,它可以被替換掉(比如,用 3-D 生成器)。在當前的實現中,只要 Robocode 應用程序被最小化,生成就禁用了,這可以以更快的速度進行仿真。





            回頁首


            Robocode 的未來

            通過 alphaWorks Robocode 站點上的一個討論組(請參閱 參考資料 ),Mathew Nelson 可以同 Robocode 用戶社區保持緊密的反饋聯系。許多反饋都并入了真實的代碼中。Mathew 已計劃即將要進行的一些改進有:

            • 通過不同的物體和障礙來定制戰場地圖
            • 基于團隊的戰斗
            • 對聯賽或聯盟的集成支持
            • 用戶可選擇坦克車體/炮/雷達/武器的樣式




            回頁首


            擋不住的 Robocode 風潮

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

            顯然,Robocode 已經填補了大眾化的寓教于樂領域的空白 ― 它為學生們和熬夜的工程師們提供簡便、有趣、非脅迫卻富競爭力的方式,釋放他們的創造力,而且有可能實現他們征服世界的夢想。

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

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

            ????我在中國的這兩年來,工作中最大的享受是到國內各高校與學生們進行交流。這些訪問和交流使得我有機會與成千上萬的青年學生就他們所關心的事業、前途等問題進行面對面的溝通。中國學生的聰明、好學和上進給我留下了非常深刻的印象。   

              在與這些青年學生的交流過程中,我發現有一些問題是大家都十分關心的。那些已經獲得國外大學獎學金的學生,大都希望我談一談應該如何度過自己在美國的學習生涯;那些決定留在國內發展的學生,非常關心如何確定一個正確的方向,并以最快的速度在科研和學業方面取得成功;還有那些剛剛踏進大學校門的學生,則希望我能講給他們一些學習、做人的經驗之談。最近,更有一些學生關心網絡信息產業的發展,希望了解美國的大學生是如何創業和致富的。看到這么多雙渴求知識、充滿希望的眼睛,我突然產生了一種沖動,那就是給中國的學生們寫一封信,將我與同學們在交流過程中產生的一些想法以及我要對中國學生的一些忠告寫出來,幫助他們在未來的留學、工作或者創業的過程中能夠人格更完美,生活更順利,事業更成功。   

            堅守誠信、正直的原則
              我在蘋果公司工作時,曾有一位剛被我提拔的經理,由于受到下屬的批評,非常沮喪地要我再找一個人來接替他。我問他:“你認為你的長處是什么?”他說:“我自信自己是一個非常正直的人。”我告訴他:“當初我提拔你做經理,就是因為你是一個公正無私的人。管理經驗和溝通能力是可以在日后工作中學習的,但一顆正直的心是無價的。”我支持他繼續干下去,并在管理和溝通技巧方面給予他很多指點和幫助。最終, 他不負眾望,成為一個出色的管理人才。   

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

              我在微軟研究院也曾碰到過類似的問題。一位來這里實習的學生,有一次出乎意料地報告了一個非常好的研究結果。但是,他做的研究結果別人卻無法重復。后來,他的老板發現,這個學生對實驗數據進行了挑選,只留下了那些合乎最佳結果的數據,而舍棄了那些“不太好”的數據。我認為,這個學生永遠不可能實現真正意義的學術突破,也不可能成為一名真正合格的研究人員。   

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

            生活在群體之中
            與大多數美國學生比較而言,中國學生的表達能力、溝通能力和團隊精神要相對欠缺一些。這也許是由于文化背景和教育體制的不同而造成的。今天,當我們面對一個正在走向高度全球化的社會時,生活在群體之中,做出更好的表現,得到更多的收獲,是尤為重要的。   

              表達和溝通的能力是非常重要的。不論你做出了怎樣優秀的工作,不會表達,無法讓更多的人去理解和分享,那就幾乎等于白做。所以,在學習階段,你不可以只生活在一個人的世界中,而應當盡量學會與各類人交往和溝通,主動表達自己對各種事物的看法和意見,甚至在公眾集會時發表演講,鍛煉自己的表達能力。   

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

              對于一個集體、一個公司,甚至是一個國家,團隊精神都是非常關鍵性的。微軟公司在美國以特殊的團隊精神著稱。像Windows2000這樣的產品的研發,有超過3000名開發工程師和測試人員參與,寫出了5000萬行代碼。沒有高度統一的團隊精神,沒有全部參與者的默契與分工合作,這項工程是根本不可能完成的。   

              以前我在別的公司時卻也曾見到過相反的現象。一項工程布置下來,大家明明知道無法完成,但都心照不宣,不告訴老板。因為反正也做不完,大家索性也不努力去做事,卻花更多的時間去算計怎么把這項工程的失敗怪罪到別人身上去。就是這些人和這樣的工作作風,幾乎把這家公司拖垮。   

              為了培養團隊精神,我建議同學們在讀書之余積極參加各種社會團體的工作。在與他人分工合作、分享成果、互助互惠的過程中,你們可以體會團隊精神的重要性。
              在學習過程中,你千萬不要不愿意把好的思路、想法和結果與別人分享,擔心別人走到你前面的想法是不健康的,也無助于你的成功。有一句諺語說,“你付出的越多,你得到的越多”。試想,如果你的行為讓人覺得“你的是我的,我的還是我的”,當你需要幫忙時,你認為別人會來幫助你嗎?反之,如果你時常慷慨地幫助別人,那你是不是會得到更多人的回報呢?   

            在團隊之中,要勇于承認他人的貢獻。如果借助了別人的智慧和成果,就應該聲明。如果得到了他人的幫助,就應該表示感謝。這也是團隊精神的基本體現。
            做一個主動的人   

              三十年前,一個工程師夢寐以求的目標就是進入科技最領先的IBM。那時IBM對人才的定義是一個有專業知識的、埋頭苦干的人。斗轉星移,事物發展到今天,人們對人才的看法已逐步發生了變化。現在,很多公司所渴求的人才是積極主動、充滿熱情、靈活自信的人。   

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

              一個積極主動的人還應該虛心聽取他人的批評和意見。其實,這也是一種進取心的體現。不能虛心接受別人的批評,并從中汲取教訓,就不可能有更大的進步。比爾蓋茨曾經對公司所有員工說過:“客戶的批評比賺錢更重要。從客戶的批評中,我們可以更好地汲取失敗的教訓,將它轉為成功的動力。”   

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

              中國學生大多比較含蓄、害羞,不太習慣做自我推銷。但是,要想把握住轉瞬即逝的機會,就必須學會說服他人,向別人推銷自己或自己的觀點。在說服他人之前,要先說服自己。你的激情加上才智往往折射出你的潛力,一個好的自我推銷策略可以令事情的發展錦上添花。

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

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

              一個一流的人與一個一般的人在一般問題上的表現可能一樣,但是在一流問題上的表現則會有天壤之別。美國著名作家威廉&#8226;福克納說過:“不要竭盡全力去和你的同僚競爭。你更應該在乎的是:你要比現在的你更強。”你應該永遠給自己設立一些很具挑戰性、但并非不可及的目標。

            在確立將來事業的目標時,不要忘了捫心自問:“這是不是我最熱愛的專業?我是否愿意全力投入?”我希望你們能夠對自己選擇所從事的工作充滿激情和想象力,對前進途中可能出現的各種艱難險阻無所畏懼。談到對工作的熱愛,我認識的一位微軟的研究員曾經讓我深有感觸。他經常周末開車出門,說去見“女朋友”,后來,一次偶然機會我在辦公室里看見他,問他:“女朋友在哪里?”他笑著指著電腦說:“就是她呀。 ”

              對于工作的熱愛,比爾&#8226;蓋茨也曾有過非常精彩的闡述,他說:“每天早晨醒來,一想到所從事的工作和所開發的技術將會給人類生活帶來的巨大影響和變化,我就會無比興奮和激動。”   

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

            有一句話說,“真理往往掌握在少數人手中”。這句話的意思是,我們看問題應該有自己的眼光,有獨立思考的能力,不一定大多數人認可的,或某個權威說的,就是對的。不論是做學問、搞研究還是經商,我們都不能盲從,要多想幾個為什么。有了客觀的意見,你就應該直截了當地表達。如果做任何事情都像“打太極拳”,會讓人不知所云,也會造成很多誤會。有一次,在微軟研究院工作的一位研究人員就自己所選擇的研究方向來征求我的意見,我作了一番分析,認為這個方向有不少問題,但如果他堅持,我愿意支持他試著去做。結果他認為我這句話的意思實際上就是不允許他去做,所以他就選擇了其他的方向。后來他要出差時,負責行政事務的人告訴他,你可以選擇坐火車或者坐飛機。他認為行政人員實際上是在暗示他坐火車,因為坐飛機太貴。其實,他的猜測都是錯誤的。因為我們的溝通方式是直截了當,而他卻在“打太極拳”。這之后,我們通過一系列的公司文化講座,讓員工們了解到,心里想什么就講什么,不要把簡單的問題復雜化。現在,研究院里這類的誤會少了很多。  

              拐彎抹角,言不由衷,結果浪費了大家的寶貴時間。瞻前顧后,生怕說錯話,結果是變成謹小慎微的懦夫。更糟糕的是還有些人,當面不說,背后亂講,這樣對他人和自己都毫無益處,最后只能是破壞了集體的團結。這樣的人和作風既不能面對社會,也不可能在科學研究中走出新路,更不可能在激烈的商戰中脫穎而出。   

              希望同學們能夠做到開誠布公,敢于說“不”,這才是尊重自己思想意愿的表現。當然,在表達你的意見時,無論反對和批評都應是建設性的,有高度誠意的,而不是為批評而批評,為辯論而批評。我贊成的方式是提供建設性的正面的意見。在開始討論問題時,任何人先不要拒人千里之外,大家把想法都擺在桌面上,充分體現個人的觀點,這樣才會有一個容納大部分人意見的結論。當然,你也要學習用適當的方法和口氣表達你的意見,比如說不要在很多人面前讓別人難堪。這樣,你的批評才會奏效。   


            珍惜校園學習生活   
              幾天前,報紙上登出一條消息,說有中學生輟學去開網絡公司。我認為這并不值得提倡。對絕大多數學生來講,在校生活是系統地學習基礎理論知識,學習思考和解決問題方式的好機會。這些知識將成為你未來發展過程中所需要的最基本的知識和技能。就像建一棟高樓,如果不打好基礎,是經不起風吹雨打的。   

              在全球范圍內,美國的研究水平無疑是世界一流的。而除了美國之外,你會發現英國的研究水平也是相當突出的。究其原因,其實就是語言問題。英國人可以毫無阻礙地閱讀美國乃至全球各種最新的英文研究報告和資料。這對于他們把握研究方向,跟蹤最新進展,發表研究成果都有很大的幫助。因此,英語學習對于我們作研究的人來說,是相當重要的。只有加強這方面素質的培養,才能適應將來的發展。我建議,學英語先聽說,再學讀寫,而且務必在大學階段完全解決英語學習的問題。等到年齡大了,要付出的代價相比就會大得多。   

              除了英語之外,數學、統計學對理工科學生也是很重要的基礎課程,是不可忽視的。數學是人類幾千年的智慧結晶,你們一定要用心把它學好,不能敷衍了事。我今天就很后悔自己當初沒有花更多功夫把數學 學得 更好些。另外,計算機應用、算法和編程也都是每一個工科學生應該 熟悉 和掌握的,它們是將來人人必須會用的工具。   

              科技的發展可謂日新月異。在校學習的目的,其實就是掌握最基本的學習工具和方法。將來利用這些工具和方法,再去學習新的東西。比如:上課學會了C++,能否自己學會Java?上課學會了HTML,能否自己學會 XML?與其說上大學是為了學一門專業,不如說是為了學會如何學習 ,讓自己能夠“無師自通”。   

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

              每次到清華和其他學校訪問,被問到最多的就是學生打工的問題。我認為,打工從總體來說對學生是一件好事,是拓寬視野的一種方式。例如,在研究機構打工,可以學到最新的科技;在產品部門打工,可以學到開發的技術和技能;在市場部門打工,可以理解商業的運作。我認為每一個學生都應該有打工的經驗,但不要打一些“沒用的工”。首先要明白打工只是學生生活中的一種補充,學習才是最重要的。打工的目的是開闊眼界,不是提前上班。如果你把翻譯書本、錄入數據庫所花的時間投入學習,將來可以賺更多的錢。那些錢將遠遠超出目前打工的收入。   ??

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

              比爾&#8226;蓋茨也曾說過:“如果你正在考慮自己成立一家新公司,你應該首先明確地知道:創辦公司需要巨大的精力投入,要冒巨大的風險。我覺得你們不必像我,一開始就創辦一家公司。你應該考慮加盟其他公司并在這家公司中學習他們的工作、創業方法。”   


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

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

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

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

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

              上述一些觀點,是我在與同學們交往過程中的一些感受。我希望這些建議和想法能對正在未來之路上跋涉的你們有所啟發,能對你們目前的學習有所幫助。或許因為觀點不同、人各有志,或許因為忠言逆耳,這封信可能無法為每一位同學所接受。但是只要一百位閱讀這封信的同學中有一位從中受益,這封信就已經比我所作的任何研究都更有價值。我真誠地希望,在新的世紀,中國學生無論是在國內,還是國外;無論是做研究,還是經商,都顯得更成熟一些,成功的機率更大一些。
            posted @ 2006-07-19 17:02 Merlin 閱讀(300) | 評論 (0)編輯 收藏

            作為程序員,應該是最為辛苦的一件事情,通宵達旦的熬夜,把自己的血汗無償的捐獻給了Boss ,同時還得小心自己落伍,明天要學習,再學習,因為技術更新實在是太快,JDK1.4還沒有搞定, JDK5.0已經開始普及了,等俺們開始用上了5.0,6.0已經開始發布測試版了,7.0也在磨刀霍霍之中,危機感始終是籠罩在自己頭上,怎么辦? 難道我們程序員就是這樣的生活?

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

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

            ?? 第二,經常反省自己,看能不能變得更好。 每天都會有收獲,所以呢,每天都可以發現自己的不足。Matrin Folwer說,如果,兩年后,你還是認為兩年前的自己已經很優秀的話,那說明你沒有進步。

            ?? 第三,要總結,把自己明天的心得都記下來,記錄自己的腳步。

            ?? 第四,要鉆研,要做就把它做好。碰到困難更是要迎難而上,這時候才是學習的最好機會。

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

            ?? 第六,要學會使用文檔,俺的頭這一點最讓人佩服,不會的問題,看文檔,很快就可以搞定,當然,前提是他英語實在是高。沒有語言障礙。

            ????第七,就是上面說的,作為程序員,要學好英語。這是很重要。

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


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

            2006年7月13日 #

            除非你像我一樣學程序語言只是為了到處獻寶,否則你在學一套程序語言前,應該先仔細評估到底要學哪一套。每個程序語言的用途都有很大的差異,走了冤枉路可能會耽誤到計畫實作的進程。
            我大致上把程序語言分成五類,分述如下:

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

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

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

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

            Assembly Languages(匯編語言)
            使用匯編語言,你將嘗試到一磚一瓦堆砌出程序的樂趣(或痛苦)。匯編語言可以說是最接近硬件的語言,學會匯編語言,就可以對計算機的運作有相當程度的了解。不過,目前連開發驅動程序都不太需要用到匯編語言了。恐怕只有做 DSP 和 OS 等極少部份的人需要用到匯編語言。我也好久沒寫匯編程序了,以前 DOS 時代,我還用匯編語言寫過一個 PE 2。

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

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

            2006年7月12日 #

            在論壇上面常常看到初學者對線程的無可奈何,所以總結出了下面一篇文章,希望對一些正在學習使用java線程的初學者有所幫助。

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

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

            多任務是指在一個系統中可以同時運行多個程序,即有多個獨立運行的任務,每個任務對應一個進程,同進程一樣,一個線程也有從創建,運行到消亡的過程,稱為線程的生命周期.用線程的狀態(state)表明線程處在生命周期的哪個階段.線程有創建,可運行,運行中,阻塞,死亡五中狀態.通過線程的控制與調度可使線程在這幾種狀態間轉化每個程序至少自動擁有一個線程,稱為主線程.當程序加載到內存時,啟動主線程.

            [線程的運行機制以及調度模型]
            java中多線程就是一個類或一個程序執行或管理多個線程執行任務的能力,每個線程可以獨立于其他線程而獨立運行,當然也可以和其他線程協同運行,一個類控制著它的所有線程,可以決定哪個線程得到優先級,哪個線程可以訪問其他類的資源,哪個線程開始執行,哪個保持休眠狀態。
            下面是線程的機制圖:
            image

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

            同一時刻如果有多個線程處于可運行狀態,則他們需要排隊等待CPU資源.此時每個線程自動獲得一個線程的優先級(priority),優先級的高低反映線程的重要或緊急程度.可運行狀態的線程按優先級排隊,線程調度依據優先級基礎上的"先到先服務"原則.
            線程調度管理器負責線程排隊和CPU在線程間的分配,并由線程調度算法進行調度.當線程調度管理器選種某個線程時,該線程獲得CPU資源而進入運行狀態.

            線程調度是先占式調度,即如果在當前線程執行過程中一個更高優先級的線程進入可運行狀態,則這個線程立即被調度執行.先占式調度分為:獨占式和分時方式.
            獨占方式下,當前執行線程將一直執行下去,直 到執行完畢或由于某種原因主動放棄CPU,或CPU被一個更高優先級的線程搶占
            分時方式下,當前運行線程獲得一個時間片,時間到時,即使沒有執行完也要讓出CPU,進入可運行狀態,等待下一個時間片的調度.系統選中其他可運行狀態的線程執行
            分時方式的系統使每個線程工作若干步,實現多線程同時運行

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


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


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



            當使用繼承創建線程,這樣啟動線程:
            				new MyThread_1().start()
            		


            當使用實現接口創建線程,這樣啟動線程:
            				new Thread(new MyThread_2()).start()
            		


            注意,其實是創建一個線程實例,并以實現了Runnable接口的類為參數傳入這個實例,當執行這個線程的時候,MyThread_2中run里面的代碼將被執行。
            下面是完成的例子:

            				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();
            }
            }



            執行后將打印出:
            My Name is Thread-0

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



            那么會打印出:
            My Name is Thread-0
            My Name is Thread-1
            My Name is Thread-2


            看了上面的結果,你可能會認為線程的執行順序是依次執行的,但是那只是一般情況,千萬不要用以為是線程的執行機制;影響線程執行順序的因素有幾點:首先看看前面提到的優先級別


            				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);//賦予最高優先級
            t1.start();
            t2.start();
            t3.start();
            }
            }


            再看看結果:
            My Name is Thread-1
            My Name is Thread-0
            My Name is Thread-2



            線程的優先級分為10級,分別用1到10的整數代表,默認情況是5。上面的t2.setPriority(Thread.MAX_PRIORITY)等價與t2.setPriority(10)
            然后是線程程序本身的設計,比如使用sleep,yield,join,wait等方法(詳情請看JDKDocument)

            				public class MyThread implements Runnable
            {
            public void run()
            {
            try
            {
            int sleepTime=(int)(Math.random()*100);//產生隨機數字,
            Thread.currentThread().sleep(sleepTime);//讓其休眠一定時間,時間又上面sleepTime決定
            //public static void sleep(long millis)throw InterruptedException (API)
            System.out.println(Thread.currentThread().getName()+" 睡了 "+sleepTime);
            }catch(InterruptedException ie)//由于線程在休眠可能被中斷,所以調用sleep方法的時候需要捕捉異常
            {
            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();
            }
            }


            執行后觀察其輸出:

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




            上面的執行結果是隨機的,再執行很可能出現不同的結果。由于上面我在run中添加了休眠語句,當線程休眠的時候就會讓出cpu,cpu將會選擇執行處于runnable狀態中的其他線程,當然也可能出現這種情況,休眠的Thread立即進入了runnable狀態,cpu再次執行它。
            [線程組概念]
            線程是可以被組織的,java中存在線程組的概念,每個線程都是一個線程組的成員,線程組把多個線程集成為一個對象,通過線程組可以同時對其中的多個線程進行操作,如啟動一個線程組的所有線程等.Java的線程組由java.lang包中的Thread——Group類實現.
            ThreadGroup類用來管理一組線程,包括:線程的數目,線程間的關系,線程正在執行的操作,以及線程將要啟動或終止時間等.線程組還可以包含線程組.在Java的應用程序中,最高層的線程組是名位main的線程組,在main中還可以加入線程或線程組,在mian的子線程組中也可以加入線程和線程組,形成線程組和線程之間的樹狀繼承關系。像上面創建的線程都是屬于main這個線程組的。
            借用上面的例子,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。
            另外一個比較多就是關于線程同步方面的,試想這樣一種情況,你有一筆存款在銀行,你在一家銀行為你的賬戶存款,而你的妻子在另一家銀行從這個賬戶提款,現在你有1000塊在你的賬戶里面。你存入了1000,但是由于另一方也在對這筆存款進行操作,人家開始執行的時候只看到賬戶里面原來的1000元,當你的妻子提款1000元后,你妻子所在的銀行就認為你的賬戶里面沒有錢了,而你所在的銀行卻認為你還有2000元。
            看看下面的例子:

            				class BlankSaving //儲蓄賬戶
            {
            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);
            }



            }



            下面是其中一次的執行結果:



            ---------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還沒有結束操作的時候,wife就插了進來,這樣很可能導致意外的結果。解決辦法很簡單,就是將對數據進行操作方法聲明為synchronized,當方法被該關鍵字聲明后,也就意味著,如果這個數據被加鎖,只有一個對象得到這個數據的鎖的時候該對象才能對這個數據進行操作。也就是當你存款的時候,這筆賬戶在其他地方是不能進行操作的,只有你存款完畢,銀行管理人員將賬戶解鎖,其他人才能對這個賬戶進行操作。
            修改public static void oper(String name,BlankSaving bs)為public static void oper(String name,BlankSaving bs),再看看結果:

            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]




            當丈夫完成操作后,妻子才開始執行操作,這樣的話,對共享對象的操作就不會有問題了。
            [wait and notify]
            你可以利用這兩個方法很好的控制線程的執行流程,當線程調用wait方法后,線程將被掛起,直到被另一線程喚醒(notify)或則是如果wait方法指定有時間得話,在沒有被喚醒的情況下,指定時間時間過后也將自動被喚醒。但是要注意一定,被喚醒并不是指馬上執行,而是從組塞狀態變為可運行狀態,其是否運行還要看cpu的調度。
            事例代碼:

            				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();
            }
            }




            執行結果如下:
            Enter Thread_1 and wait
            Enter Thread_2 and notify
            Thread_1 be notified


            可能你注意到了在使用wait and notify方法得時候我使用了synchronized塊來包裝這兩個方法,這是由于調用這兩個方法的時候線程必須獲得鎖,也就是上面代碼中的lock[],如果你不用synchronized包裝這兩個方法的得話,又或則鎖不一是同一把,比如在MyThread_2中synchronized(lock)改為synchronized(this),那么執行這個程序的時候將會拋出java.lang.IllegalMonitorStateException執行期異常。另外wait and notify方法是Object中的,并不在Thread這個類中。最后你可能注意到了這點:int[] in=new int[0];為什么不是創建new Object而是一個0長度的數組,那是因為在java中創建一個0長度的數組來充當鎖更加高效。

            Thread作為java中一重要組成部分,當然還有很多地方需要更深刻的認識,上面只是對Thread的一些常識和易錯問題做了一個簡要的總結,若要真正的掌握java的線程,還需要自己多做總結
            posted @ 2006-07-12 16:38 Merlin 閱讀(387) | 評論 (0)編輯 收藏

            第一,談談final, finally, finalize的區別。

              
            final—修飾符(關鍵字)如果一個類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個類不能既被聲明為 abstract的,又被聲明為final的。將變量或方法聲明為final,可以保證它們在使用中不被改變。被聲明為final的變量必須在聲明時給定初值,而在以后的引用中只能讀取,不可修改。被聲明為final的方法也同樣只能使用,不能重載。

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

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


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

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


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

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

              
            注: 靜態內部類(Inner Class)意味著1創建一個static內部類的對象,不需要一個外部類對象,2不能從一個static內部類的一個對象訪問一個外部類對象


              
            第四,&和&&的區別。

              
            &是位運算符。&&是布爾邏輯運算符。


              
            第五,HashMap和Hashtable的區別。

              
            都屬于Map接口的類,實現了將惟一鍵映射到特定的值上。

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

              
            Hashtable 類似于 HashMap,但是不允許 null 鍵和 null 值。它也比 HashMap 慢,因為它是同步的。


              
            第六,Collection 和 Collections的區別。

              
            Collections是個java.util下的類,它包含有各種有關集合操作的靜態方法。

              
            Collection是個java.util下的接口,它是各種集合結構的父接口。



              
            第七,什么時候用assert。

              
            斷言是一個包含布爾表達式的語句,在執行這個語句時假定該表達式為 true。如果表達式計算為 false,那么系統會報告一個 Assertionerror。它用于調試目的:

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

              

            斷言可以有兩種形式:

              
            assert Expression1 ;

             
            assert Expression1 : Expression2 ;

              
            Expression1 應該總是產生一個布爾值。

              
            Expression2 可以是得出一個值的任意表達式。這個值用于生成顯示更多調試信息的 String 消息。

              
            斷言在默認情況下是禁用的。要在編譯時啟用斷言,需要使用 source 1.4 標記:

              
            javac -source 1.4 Test.java

              
            要在運行時啟用斷言,可使用 -enableassertions 或者 -ea 標記。

              
            要在運行時選擇禁用斷言,可使用 -da 或者 -disableassertions 標記。

              
            要系統類中啟用斷言,可使用 -esa 或者 -dsa 標記。還可以在包的基礎上啟用或者禁用斷言。

              
            可以在預計正常情況下不會到達的任何位置上放置斷言。斷言可以用于驗證傳遞給私有方法的參數。不過,斷言不應該用于驗證傳遞給公有方法的參數,因為不管是否啟用了斷言,公有方法都必須檢查其參數。不過,既可以在公有方法中,也可以在非公有方法中利用斷言測試后置條件。另外,斷言不應該以任何方式改變程序的狀態。


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

              
            GC是垃圾收集器。Java 程序員不用擔心內存管理,因為垃圾收集器會自動進行管理。要請求垃圾收集,可以調用下面的方法之一:

              
            System.gc()

              
            Runtime.getRuntime().gc()


              
            第九,String s = new String("xyz");創建了幾個String Object?

              
            兩個對象,一個是"xyx",一個是指向"xyx"的引用對象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;有什么錯? short s1 = 1; s1 += 1;有什么錯?

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


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

              
            sleep()方法是使線程停止一段時間的方法。在sleep 時間間隔期滿后,線程不一定立即恢復執行。這是因為在那個時刻,其它線程可能正在運行而且沒有被調度為放棄執行,除非

            (a)"醒來"的線程具有更高的優先級。

              
            (b)正在運行的線程因為其它原因而阻塞。

              
            wait()是線程交互時,如果線程對一個同步對象x 發出一個wait()調用,該線程會暫停執行,被調對象進入等待狀態,直到被喚醒或等待時間到。


              
            第十三,Java有沒有goto?

              
            Goto—java中的保留字,現在沒有在java中使用。


              
            第十四,數組有沒有length()這個方法? String有沒有length()這個方法?

              
            數組沒有length()這個方法,有length的屬性。

              
            String有有length()這個方法。


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

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


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

              
            Set里的元素是不能重復的,那么用iterator()方法來區分重復與否。equals()是判讀兩個Set是否相等。

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


              
            第十七,給我一個你最常見到的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有什么區別?

              
            error 表示恢復不是不可能但很困難的情況下的一種嚴重問題。比如說內存溢出。不可能指望程序能處理這樣的情況。

              
            exception 表示一種設計或實現問題。也就是說,它表示如果程序運行正常,從不會發生的情況。


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

              
            List,Set是

              
            Map不是


              
            第二十,abstract class和interface有什么區別?

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

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


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

              
            都不能


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

              
            接口可以繼承接口。抽象類可以實現(implements)接口,抽象類是否可繼承實體類,但前提是實體類必須有明確的構造函數。


             
            第二十三,啟動一個線程是用run()還是start()?

              
            啟動一個線程是調用start()方法,使線程所代表的虛擬處理機處于可運行狀態,這意味著它可以由JVM調度并執行。這并不意味著線程就會立即運行。run()方法可以產生必須退出的標志來停止一個線程。


              
            第二十四,構造器Constructor是否可被override?

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


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

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


              
            第二十六,當一個線程進入一個對象的一個synchronized方法后,其它線程是否可進入此對象的其它方法?

              
            不能,一個對象的一個synchronized方法只能由一個線程訪問。


              
            第二十七,try {}里有一個return語句,那么緊跟在這個try后的finally {}里的code會不會被執行,什么時候被執行,在return前還是后?

              
            會執行,在return前執行。


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

              
            有C背景的程序員特別喜歡問這種問題。


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

             
            不對,有相同的hash code。


              
            第三十,當一個對象被當作參數傳遞到一個方法后,此方法可改變這個對象的屬性,并可返回變化后的結果,那么這里到底是值傳遞還是引用傳遞?

              
            是值傳遞。Java 編程語言只由值傳遞參數。當一個對象實例作為一個參數被傳遞到方法中時,參數的值就是對該對象的引用。對象的內容可以在被調用的方法中改變,但對象的引用是永遠不會改變的。


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

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


              
            第三十二,編程題: 寫一個Singleton出來。

              
            Singleton模式主要作用是保證在Java應用程序中,一個類Class只有一個實例存在。

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

              
            第一種形式: 定義一個類,它的構造函數為private的,它有一個static的private的該類變量,在類初始化時實例話,通過一個public的getInstance方法獲取對它的引用,繼而調用其中的方法。

              
            public class Singleton {

              
            private Singleton(){}

              
            //在自己內部定義自己一個實例,是不是很奇怪?

              
            //注意這是private 只供內部調用

              
            private static Singleton instance = new Singleton();

              
            //這里提供了一個供外部訪問本class的靜態方法,可以直接訪問  

              
            public static Singleton getInstance() {

              
            return instance;   

              
            }

              
            }


              
            第二種形式:

              
            public class Singleton {

              
            private static Singleton instance = null;

              
            public static synchronized Singleton getInstance() {

              
            //這個方法比上面有所改進,不用每次都進行生成對象,只是第一次 

                  
             //使用時生成實例,提高了效率!

              
            if (instance==null)

              
            instance=new Singleton();

              
            return instance;   }

              
            }

              
            其他形式:

              
            定義一個類,它的構造函數為private的,所有方法為static的。

              
            一般認為第一種形式要更加安全些

              
            Hashtable和HashMap

              
            Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Map interface的一個實現

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

              
            還有就是,HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因為contains方法容易讓人引起誤解。

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

              
            多個線程訪問Hashtable時,不需要自己為它的方法實現同步,而HashMap

              
            就必須為之提供外同步。

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

            2006年7月11日 #

            《Thinking in Java》
            《J2EE技術實踐》
            《JAVA高效編程指南》

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

            近期到CSDN論壇看看一些網友貼的面試題,其中關于String的問題常常被提及。我一直以為自己很清楚這個東西了,其實深究起來,發現自己并不那么清楚,會犯一些錯誤;同時也產生了一些聯想。小結一下。

            1、"abc"與new String("abc");
            ????經常會問到的面試題:String s = new String("abc");創建了幾個String Object?【如這里創建了多少對象? 和一道小小的面試題 】

            ????這個問題比較簡單,涉及的知識點包括:

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

            ????二、Java中所有的字符串文字[字符串常量]都是一個String的對象。有人[特別是C程序員]在一些場合喜歡把字符串"當作/看成"字符數組,這也沒有辦法,因為字符串與字符數組存在一些內在的聯系。事實上,它與字符數組是兩種完全不同的對象。

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

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

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


            ????這里的輸出顯示,兩個字符串文字保存為一個對象。就是說,上面的代碼只在pool中創建了一個String對象。

            ????現在看String s = new String("abc");語句,這里"abc"本身就是pool中的一個對象,而在運行時執行new String()時,將pool中的對象復制一份放到heap中,并且把heap中的這個對象的引用交給s持有。ok,這條語句就創建了2個String對象。

            				String s1 = new String("abc") ;
            String s2 = new String("abc") ;
            if( s1 == s2 ){ //不會執行的語句}


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

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


            2、字符串的+運算和字符串轉換
            ????字符串轉換和串接是很基礎的內容,因此我以為這個問題簡直就是送分題。事實上,我自己就答錯了。

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

            ????首先看JLS的有關論述:

            ????一、字符串轉換的環境[JLS 5.4 String Conversion]

            ????字符串轉換環境僅僅指使用雙元的+運算符的情況,其中一個操作數是一個String對象。在這一特定情形下,另一操作數轉換成String,表達式的結果是這兩個String的串接。

            ????二、串接運算符[JLS 15.18.1 String Concatenation Operator + ]

            ????如果一個操作數/表達式是String類型,則另一個操作數在運行時轉換成一個String對象,并兩者串接。此時,任何類型都可以轉換成String。[這里,我漏掉了"3"和"4"]

            如果是基本數據類型,則如同首先轉換成其包裝類對象,如int x視為轉換成Integer(x)。
            現在就全部統一到引用類型向String的轉換了。這種轉換如同[as if]調用該對象的無參數toString方法。[如果是null則轉換成"null"]。因為toString方法在Object中定義,故所有的類都有該方法,而且Boolean, Character, Integer, Long, Float, Double, and String改寫了該方法。
            關于+是串接還是加法,由操作數決定。1+2+str+3+4 就很容易知道是"3jf34"。[BTW :在JLS的15.18.1.3中舉的一個jocular little example,真的很無趣。]
            ????下面的例子測試了改寫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";
            ????}
            }


            三、字符串轉換的優化

            按照上述說法,str = 1+2+str+3+4;語句似乎應該就應該生成5個String對象:

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

            ????這里我并不清楚3、4轉換成字符串后是否在池中,所以上述結果仍然是猜測。

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

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

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

            ????現在我仍然不知道怎么回答str = 1+2+str+3+4;創建了多少String的對象,。或許,這個問題不需要過于研究,至少SCJP不會考它。

            3、這又不同:str = "3"+"jf"+"3"+"4";
            ????如果是一個完全由字符串文字組成的表達式,則在編譯時,已經被優化而不會在運行時創建中間字符串。測試代碼如下:

            				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指向同一個對象,這個對象在pool中。所有遵循Java Language Spec的編譯器都必須在編譯時對constant expressions 進行簡化。JLS規定:Strings computed by constant expressions (&yacute;15.28) are computed at compile time and then treated as if they were literals.

            ????對于String str2 ="3"+"jf"+"3"+"4";我們說僅僅創建一個對象。注意,“創建多少對象”的討論是說運行時創建多少對象。

            ????BTW:編譯時優化

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

            ????等價于:

            ????String x = "aaa bbb ";
            ????x = x + "ddd ";
            //這個地方我自己進行了編譯,不過和他的結論不一樣,好像當用x+="ddd"的時候和直接的x="aaa"+"bbb"+"ddd" 不同,但是具體為什么我也不清楚,正在研究中。。。

            4、不變類
            ????String對象是不可改變的(immutable)。有人對str = 1+2+str+3+4;語句提出疑問,怎么str的內容可以改變?其實仍然是因為不清楚:引用變量與對象的區別。str僅僅是引用變量,它的值——它持有的引用可以改變。你不停地創建新對象,我就不斷地改變指向。[參考TIJ的Read-only classes。]

            ????不變類的關鍵是,對于對象的所有操作都不可能改變原來的對象[只要需要,就返回一個改變了的新對象]。這就保證了對象不可改變。為什么要將一個類設計成不變類?有一個OOD設計的原則:Law of Demeter。其廣義解讀是:

            ????使用不變類。只要有可能,類應當設計為不變類。
            posted @ 2006-07-11 22:29 Merlin 閱讀(386) | 評論 (0)編輯 收藏

            abstract class和interface在Java語言中都是用來進行抽象類定義的

            Interface ,給外界的接口,按照規定辦事;
            Abstract??,內部繼承關系;

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

            在面向對象的概念中,所有的對象都是通過類來描繪,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類
            抽象概念在問題領域沒有對應的具體概念,所以用以表征抽象概念的抽象類是不能夠實例化的。

            =====================================================================================================================
            使用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語言中表示的是一種繼承關系,一個類只能使用一次繼承關系
            一個類卻可以實現多個interface

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

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

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

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

            				abstract class MShape
            {
            ????????protected String color;?? //數據成員
            ????????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()??//計算面積
            ????????{??????????
            ??????????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中不僅可以定義一般的方法(即可以進行具體處理的方法),還可以象interface一樣定義抽象方法。
            而在interface中只能定義抽象方法。

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

            僅列出標題  下一頁
            亚洲狠狠婷婷综合久久蜜芽| 7国产欧美日韩综合天堂中文久久久久| 久久66热人妻偷产精品9| 精品久久久久久无码人妻蜜桃| 国产精品九九久久免费视频| 久久水蜜桃亚洲av无码精品麻豆| 偷偷做久久久久网站| 欧美日韩中文字幕久久久不卡| 国产精品午夜久久| 久久久久久久尹人综合网亚洲| 久久久综合九色合综国产| 国产精品99精品久久免费| 国产午夜免费高清久久影院| 99久久人妻无码精品系列蜜桃| 久久99精品国产99久久| 久久ZYZ资源站无码中文动漫| 97久久超碰国产精品旧版| 69久久夜色精品国产69| 国产一久久香蕉国产线看观看| 久久久精品视频免费观看| 国产免费福利体检区久久| 久久夜色精品国产亚洲av| 91麻豆国产精品91久久久| 久久综合亚洲欧美成人| 一级做a爰片久久毛片人呢| 久久久青草青青国产亚洲免观| 2021国内精品久久久久久影院| 99久久无色码中文字幕人妻| 国产婷婷成人久久Av免费高清| 久久青青草原国产精品免费| 国内精品久久久久久久久| 久久精品无码一区二区日韩AV| 久久综合狠狠综合久久| 99久久精品国产一区二区蜜芽| 性高湖久久久久久久久AAAAA| 人妻精品久久久久中文字幕69| 亚洲乱亚洲乱淫久久| 波多野结衣久久精品| 国产成人99久久亚洲综合精品 | 思思久久99热免费精品6| 偷偷做久久久久网站|