教孩子Java編程

jopen 9年前發布 | 34K 次閱讀 Java編程 Java開發

十二年前,我的小兒子Dave出現在我的辦公室,手里拿著Java教程。Dave讓我教他編程,這樣他就能自己寫游戲了。那時候我已經寫了幾本關于 Java的書,還同時教幾門計算機編程課,但那都是面向成人的;Amazon上沒有任何適合用來教孩子編程的書。在Google上搜索了幾個小時,我能找 到的一些為孩子準備的編程教程也只是淺嘗輒止,或者是最基礎的那種類似于“聰明兔(譯者注:即reader rabbit,美國著名幼兒教育品牌)”的書。所以我決定自己寫一本書。

那時我的大兒子Yuri在大學里主修動漫,他答應為我的書畫插圖。當我完成草稿的時候,沒有出版商愿意出版它,原因有兩個:

  • 少兒編程書根本沒有市場。
  • 我希望這本書能彩印,較之于黑白印刷,這大大增加了成本。
  • </ul>

    沒什么大不了的。我在網上發布了此書的pdf版本供大家免費下載。一年后,幾位好心的法國家長把它譯成了法語,然后一些來自東歐的Java愛好者又把它譯成了俄語和烏克蘭語。這些版本仍然可以從網上免費下載到。


    今年早些時候,我收到了一封意外的電子郵件,來自于No Starch出版社——問我是否有興趣寫一本給孩子看的Java編程書籍?我又問了一次,“你們愿意彩印嗎?”,出乎我意料的是,他們馬上同意了,并且給 我看了很多他們出版的教孩子編程的書籍,是其他語種的。時代變了……長話短說,我接受了。一年很快要過去了,這本書將會在2015年春季付印。

    用Java來教孩子編程好嗎?

    為了回答這個問題,我們首先要定義“孩子”這個詞。對于12歲以下的孩子來說,我相信Java作為第一門編程語言有點太復雜了。低齡一點的孩子一開始最好用一些寫好的程序模塊來搭建可視化程序。MIT創建了Scratch,對于8歲大的孩子來說,它是一個很好的激發編程興趣的工具。10歲的小孩就可以更進一步,通過Greenfoot開始學習真正地使用Java來編程。

    但是我認為,任何12歲以上的孩子,只要對編程有興趣,就可以一本正經地去學習Java編程了,并且可以使用專業的工具來學。在之前為孩子寫的那本書里,我使用Eclipse作為IDE,但在現在這本新書里,我選擇了IntelliJ IDEA社區版,它也是免費的。

    教成人和教小孩Java的區別在于,孩子們對于編寫GUI程序的反響更熱烈,而Java也很擅長做這個。我說的是JavaFX;Swing框架已經 過時了,想用Swing來寫出點像樣的程序,需要很專業的知識。JavaFX則提供了豐富的工具,并且非常優雅地隔離了界面和應用邏輯。JavaFX自帶 了“Scene Builder”,一個可視化的GUI設計工具,它可以生成用FXML描述的GUI;FXML是一種基于XML的語言,可以通過聲明的方式來創建GUI。 不過不用擔心,孩子們不需要自己去寫FXML——他們只需要把UI控件拖拽到畫布(canvas)上,Scene Builder就會生成FXML。

    少兒Java教育家

    如果說12年前的孩子對編程還不是那么感興趣的話,那么今天的很多孩子已經很喜歡編程了。時代變了……于是,世界各地都有編程愛好者在花時間和精力給孩子介紹編程。我們要向Stephan Janssen致敬,他創立了Devoxx4Kids運 動,用一種創造性的方式來教孩子編程。這種運動最早開始于比利時,但如今很多國家都加入了。在美國,舊金山分會的領導人是Arun Gupta,而Matt Raible運營著丹佛分會。如果有位于曼哈頓的公司愿意提供場地給孩子們搞活動的話,我已經準備好貢獻我的時間,在紐約建立一個分支機構。

    我要為Stephen Chin獻上掌聲,他來自Oracle,他經常背著一個袋子滿世界走,那個袋子里裝滿了可編程設備。今年早些時候,我參加了他的演講“瑪麗有個小小的lambda表達式”(譯者注:英文名“Mary Had a Little Lambda”,此名字借用了著名的英語兒歌“Mary Had a Little Lamb”,lamb和lambda詞形相近),在演講中他通過演示復雜的游戲解釋了Java。今年夏天,我參加了在希臘舉行的JCrete“非 會議”(譯者注:unconference,一種顛覆傳統式會議的新形式,會議內容由參與者自己制定,主張開放式討論)。其他與會者都帶著筆記本電腦 來,Stephen卻帶來了兩打硬件開發套件,他舉行了一個研討會,在會上孩子們用Java編了一個機器人,可以跳Sirtaki舞(譯者注:希臘民間舞 蹈)。

    我肯定世界各地還有其他的好心人在給孩子們普及Java。已經誕生20年之久的Java語言正在越變越年輕。

    本書節選

    感謝有這樣的機會能給InfoQ的讀者呈現我將要出版的書籍“Java for Kids”中的兩段節選。在本書中我使用了IntelliJ IDEA社區版,JetBrains出品的免費又好用的IDE。第一段節選是關于類和對象的簡單介紹。第二段來自于Tic-Tac-Toe(譯者注:一種 棋類游戲)章節。教孩子的時候,程序的可視化程度越高越好。這就是為什么我要在總共12章中的5章都使用了JavaFX。讀者們需要編寫一個計算器和兩個 游戲:Tic-Tac-Toe和Ping-Pong。

    本書節選1:類和對象

    在現實世界中你會看到和用到各種對象,每個對象都屬于某個“種類”,比如玩具、食物、動物、電子產品等等。在Java中我們不說一種對象,而說一類對象。類就像是一個對象的藍圖。你將要編寫的所有程序都是由各種類組成的。

    Java定義了各種數據類型。有些很簡單,像int,代表整數。有些復雜一點,它們就是類。比如System類,它可以用于在屏幕上打印文字、退出程序或清理計算機的內存。

    你安裝了Java后,數千個Java類被下載到你的計算機中。你的Java程序中包含的類也可能代表來自真實世界的對象。如果說類是一種數據類型,那么對象就代表了一種特殊的類型。舉個例子,你看到街上有十只狗,他們都代表了Dog這個類。

    程序員在開始寫程序之前,先要決定需要使用哪些類,每個類要創建多少對象。比如,在游戲應用中他們可以定義Player類,并以此創建兩個對象。

    當程序員互相交流的時候,他們可能會說“對Player類做某些操作”或者“用Player對象做某些操作”。我們需要分辨對象這兩個詞的不同含義。

    我們來看看Java類是如何組成的。最基礎的類可能什么都不包含。看看下面的類聲明:

    class VideoGame {}

    這是個空的類——它不帶有任何信息,也干不了任何事,因為兩個大括號之間沒有任何代碼。從Java語法的角度看,這個類是合法的,計算機不會報錯——class是一個有效的關鍵字,緊接著是名字VideoGame,大括號要成對出現。但如果我們的程序想干點什么,我們需要定義有實際意義的類。所以我們需要給類加裝方法和屬性:

    • 方法定義了一個類所能做的操作。
    • 屬性描述了一個類的各種性質。
    • </ul>

      我們來給VideoGame類填上內容。這個類可以有一些方法,告訴我們這個類的對象能做什么:開始游戲、停止游戲、保存分數、要求上非死book點贊等等。這個類也可以有一些屬性(也叫域):顏色、價格和其他。代表VideoGame類的一個對象看起來是這樣的:

      class VideoGame { 
        String color;
        int price; 
        void start () {
           // 開始游戲的代碼放在這里
        } 
        void stop () {
           // 停止游戲的代碼放在這里
        } 
        void saveScore(String playerName, int score) {
           // 保存分數的代碼放在這里
        }
      }

      這個類有兩個屬性colorpricecolor屬性是String類型的,這種類型用于保存文本。priceint型的,用于保存整數。VideoGame類有三個方法:startstopsaveScore。這些都是我們的視頻游戲能采取的動作。目前,這些方法只有以雙斜杠//開頭的一行字。

      教孩子Java編程 如果一行文字以雙斜杠開頭,那它就是單行的注釋——只是對代碼段的描述。如果你需要寫多行的注釋,只要輸入一個斜杠和一個星號/*,然后輸入任意行的文字,最后以一個星號和一個斜杠結尾*/,代表注釋結束。

      我們不會去創造一個真正的視頻游戲,因為我們才開始學編程。但到本書的后面部分,我們會開發Tic-Tac-Toe和Ping-Pong游戲。

      但是難道你不覺得所有游戲都有共同點嗎?每個游戲都需要有一種方法來開始和停止或保存分數。當你以面向對象的方式編寫一個程序,你要開始思考如何使類擁有的屬性和方法保持絕對的最少。然后你可以基于第一個類來添加更多特殊的功能——在本章節后面部分你會學到繼承。這就是為什么VideoGame類只擁有視頻游戲所共有的屬性和方法。

      教孩子Java編程

      圖1:視頻游戲的對象

      類還是對象

      在本節中我將向你展示如何基于類來創建對象實例,并向你介紹繼承的概念。

      為了復用你或者其他人已經寫好的代碼,你可以基于一個類創建另一個,它會繼承前一個類的所有屬性和方法。繼承別的類創建的類稱為“子類”,被繼承的類稱為“父類”。下面的代碼展示了繼承VideoGame類的新類PlayStation4

      class PlayStation4 extends VideoGame{
         String hardDiskSize;
         // 其他屬性和方法可以在這里聲明
         // 方法shareOn非死books檢查用戶是否已經登錄了
         // 如果沒有,它會顯示一個窗口,帶有以下信息
         // “在分享你的分數之前請先登錄非死book”
         void shareOn非死book(){
            // 在非死book上分享的代碼在這里
            System.out.println("Hey, 非死book, I got PlayStation4 with " + hardDiskSize);
         }
         void shareOn推ter(){
            // 在推ter上分享的代碼在這里
            System.out.println("Hey, 推ter, I got PlayStation4 with " + hardDiskSize);
         }
      }

      語句extends VideoGame表示PlayStation4類是VideoGame類的子類。我們也可以說PlayStation4類繼承了VideoGame類或者說“擴展”了VideoGame類,這也意味著子類(PlayStation4)既可以使用父類(VideoGame)中定義的屬性,也可以使用父類(VideoGame)中定義的所有方法(并擴展它們),我在書的后面部分會解釋。注意PlayStation4類即使沒有定義屬性price和color,以及方法start、stop和savaScore,但這個類的對象還是可以使用所有這些屬性和方法。它們是從VideoGame類繼承過來的,這些代碼不需要拷貝/粘貼到PlayStation4類中。

      當我們創建一個對象的實例時,我們真正所做的是基于某個類的聲明,在計算機內存中創建了一個對象。舉個例子,下面的CreatePlayStation4Objects程序使用new運算符創建了兩個PlayStation4類的實例。它聲明了兩個PlayStation4型的變量,分別是firstPlayStationsecondPlayStation,每個都指向了內存中的一個獨立對象。注意這些對象的屬性hardDiskSize有不同的值(500GB和1TB)。這個程序對第一個對象調用了shareOn非死book方法,而對第二個對象調用了shareOn推ter

      public class CreatePlayStation4Objects { 
          public static void main(String[] args) { 
              // 創建一個PlayStation4類的實例
              PlayStation4 firstPlayStation = new PlayStation4();
              firstPlayStation.hardDiskSize = "500GB"; 
              // 對第一個實例調用shareOn非死book方法
              firstPlayStation.shareOn非死book(); 
              // 創建另一個PlayStation4類的實例
              PlayStation4 secondPlayStation = new PlayStation4();
              secondPlayStation.hardDiskSize = "1TB"; 
              // 對第二個實例調用shareOn非死book方法
              secondPlayStation.shareOn推ter();
          }

      運行CreatePlayStation4Objects會打印以下內容:

      Hey, 非死book, I got PlayStation4 with 500GB 
      Hey, 推ter, I got PlayStation4 with 1TB

      如果一個游戲公司要生產10000個這樣的游戲,那么程序員可以說他們創建了10000個PlayStation4的實例。游戲公司和一個真正的游戲的關系就類似于Java類和它在內存中的實例的關系。在現實世界中游戲公司制作一個真正的游戲,和Java編程世界中創建PlayStation4對象實例類似。只是每個實例會有些不一樣,比如本例中的內部磁盤大小。

      教孩子Java編程

      圖2:一個類,兩個實例

      一般情況下,程序先創建Java類的對象實例,才能使用它的屬性和方法。游戲公司也一樣——他們使用同一份原本生產出數千份游戲拷貝。即使這些拷貝代表了同一個類,它們還是可能有不一樣的屬性——有些是黑的色,另一些則是銀色的。有些有500GB硬盤,有些則有1TB。

      本書節選2:改變樣式和使用效果

      這是第十章的節選,讀到那里讀者已經掌握了JavaFX的基礎,寫過一個登錄窗口和一個計算器,并且知道如何在界面上應用CSS樣式。Tic- Tac-Toe游戲的基本功能也已經實現,但是如果能使制勝的三顆棋子一目了然就更好了(譯者注:Tic-Tac-Toe以三子在一直線上為勝)。

      加亮制勝棋子

      制勝棋子的樣式應該可以動態改變(在運行的時候)。首先,我們需要給CSS文件添加一個樣式來顯示制勝的X-O棋子。然后Controller類可以對棋子調用setStyle方法,決定制勝的棋子使用哪種樣式。

      我想改變制勝棋子的背景,但是這次我不想用單色了,我想用漸變色。在計算機圖形中,漸變色是指用混合的顏色去填充一個區域,并且相鄰顏色之間是平滑過渡。顏色漸變分線性的和放射狀的,這篇維基百科的文章有這兩者的例子。

      我們的游戲中使用放射狀漸變。我們可以使用兩種或更多的顏色來組成漸變色。我們給制勝棋子使用三種顏色吧。棋子的背景色會從白色轉變到淡黃色,再到草綠色。棋子上的文字標簽,我們使用紅色。

      要動態改變GUI組件的樣式,你可以調用setStyle,并指定顏色作為參數,舉個例子:

      myButton.setStyle("-fx-text-fill: red;");

      但是,在你的Java程序中寫死CSS規則不是一個好主意。如果你想改變樣式該怎么辦(比如把顏色從紅色改成粉色)?你不想搜遍所有的Java文件 來找出所有使用這個樣式的地方。而且,改變嵌在代碼中的樣式,會導致程序必須重新編譯,誰會為了一個簡單的修改這么干!所以把樣式定義放在外部的CSS文 件中會比較好,改起來就比較靈活。

      至此,我們已經使用了CSS類型選擇器來改變指定組件的樣式。但是,CSS允許你定義一個樣式并給它取名,這樣,就不僅僅是特定的組件類型可以用它,各種組件都可以通過指定名字來使用它。在CSS中,這種樣式叫做類選擇器(class selectors)。我們來給tictactoe.css添加一個叫做.winning-square的類選擇器。

      .winning-square {
          -fx-text-fill: red;
          -fx-background-color: radial-gradient( radius 100%, white, lightyellow, lawngreen);
      }

      這里的樣式選擇器.winning-square包括了兩條樣式規則:一條是要把按鈕的顏色設為紅色,另一條是要把按鈕的背景色設為我們的放射狀漸變色。我們的Java程序必須得到按鈕現有樣式的引用,然后再添加一個.winning-square,這就會覆蓋按鈕原來的文字和背景顏色。方法highlightWinningCombo看起來是這樣的:

      private void highlightWinningCombo(Button first, Button second, Button third){
          first.getStyleClass().add("winning-square");
          second.getStyleClass().add("winning-square");
          third.getStyleClass().add("winning-square");
      }

      在給Controller類添加完find3InARowhighlightWinningCombo方法后,試著玩玩這個游戲。制勝的棋子看起來就是下面這個樣子:

      教孩子Java編程

      圖3:我們贏了!

      JavaFX包括了多種視覺效果變換動畫,這些可以使你的界面變得更有意思。

      要使用這些效果和動畫,你需要在javafx.scene.effectjavafx.animation包中進行相應的選擇。我會給你演示一下如何在我們的制勝棋子上使用淡出的變換效果。每個制勝棋子不停地淡出,然后又回復到初始狀態。我們要給Controller類添加一個applyFadeTransition方法。

      private void applyFadeTransition(Button winningButton) { 
        FadeTransition ft = new FadeTransition(Duration.millis(1000), winningButton); 
        ft.setFromValue(1.0);
        ft.setToValue(0.1);
        ft.setCycleCount(10);
        ft.setAutoReverse(true);
        ft.play();
      }

      這段代碼創建了一個動畫類FadeTransition的實例,這個動畫會持續1000毫秒(等于1秒),然后把這個動畫分配給制勝棋子。然后它又設置了淡出的參數,把棋子的透明度從1改到了0.1(0.0意味著完全透明)。

      把樣式數量設為10代表動畫會播放10次。因為調用了setAutoReverse(true),這個動畫會在第一個周期中正向播放,在第二個周期中反向播放,如此循環往復。play方法則啟動了動畫。給highlightWinningCombo添加以下三行代碼,這個動畫就會在winningButton組件上播放。

      applyFadeTransition(first);
      applyFadeTransition(second);
      applyFadeTransition(third);

      下面的截屏告訴你動畫播放結束后的樣子。

      教孩子Java編程

      圖4:淡出的制勝棋子
      把這張圖和前面一張比一比。或者運行書中的代碼,看看動畫是什么樣子的,就更好了。

      更多閱讀

      我希望在看完這篇文章后,你們中的一些人開始渴望教自己的孩子編程。我給你們帶來了好消息。出版商讓我把早期未經修改的初稿放在網上,這樣我們就可以在此書付印前收集一些來自社區的反饋。你們可能會看到一些標點遺漏或其他語法錯誤,但是在出版前編輯們會搞定這些問題。

      本書的示例代碼可分享給大家,我把它們發布在GitHub上。如果你發現示例代碼有bug或者有更好的方案,請告訴我。

      教你們的孩子Java!和你的另一半一起享受Java!也把Java介紹給你們的父母!

      關于作者

      教孩子Java編程 Yakov Fain是一個Java擁護者,以及兩個軟件公司的聯合創始人:Farata Systems和SuranceBay。他寫過幾本技術書籍和很多關于軟件開發的文章。他領導著普林斯頓Java用戶小組和紐約Dart用戶小組。最近,Yakov與人合著了《Enterprise Web Development 》(O'Reilly出版社)一書。他有兩本書會在2015年出版:《Java For Kids》(No Starch出版社)和《Java 24-Hour Trainer》第二版(Wrox出版社)。

      查看英文原文:Teaching Kids Java Programming

      來自:http://www.infoq.com/cn/articles/Teaching-Kids-Java

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!