Java编程也要从娃娃抓起

因为市面上没有教孩子编程的教程书,于是本文作者自己编了一本。InfoQ的用户朋友们有没有教自己孩子编程的呢?我司倒是有一个教自家跳小苹果的孩子学C语言的。

十二年前,我的小儿子Dave出现在我的办公室,手里拿着Java教程。Dave让我教他编程,这样他就能自己写游戏了。

那时候我已经写了几本关于Java的书,还同时教几门计算机编程课,但那都是面向成人的;Amazon上没有任何适合用来教孩子编程的书。在Google上搜索了几个小时,我能找到的一些为孩子准备的编程教程也只是浅尝辄止,或者是最基础的那种类似于“聪明兔(译者注:即reader rabbit,美国著名幼儿教育品牌)”的书。所以我决定自己写一本书。

那时我的大儿子Yuri在大学里主修动漫,他答应为我的书画插图。当我完成草稿的时候,没有出版商愿意出版它,原因有两个:

少儿编程书根本没有市场。
我希望这本书能彩印,较之于黑白印刷,这大大增加了成本。
没什么大不了的。我在网上发布了此书的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,大括号要成对出现。但如果我们的程序想干点什么,我们需要定义有实际意义的类。所以我们需要给类加装方法和属性:

方法定义了一个类所能做的操作。
属性描述了一个类的各种性质。
我们来给VideoGame类填上内容。这个类可以有一些方法,告诉我们这个类的对象能做什么:开始游戏、停止游戏、保存分数、要求上Facebook点赞等等。这个类也可以有一些属性(也叫域):颜色、价格和其他。代表VideoGame类的一个对象看起来是这样的:

class VideoGame {
String color;
int price;
void start () {
// 开始游戏的代码放在这里
}
void stop () {
// 停止游戏的代码放在这里
}
void saveScore(String playerName, int score) {
// 保存分数的代码放在这里
}
}**

这个类有两个属性color和price。color属性是String类型的,这种类型用于保存文本。price是int型的,用于保存整数。VideoGame类有三个方法:start、stop和saveScore。这些都是我们的视频游戏能采取的动作。目前,这些方法只有以双斜杠//开头的一行字。

如果一行文字以双斜杠开头,那它就是单行的注释——只是对代码段的描述。如果你需要写多行的注释,只要输入一个斜杠和一个星号/,然后输入任意行的文字,最后以一个星号和一个斜杠结尾/,代表注释结束。

我们不会去创造一个真正的视频游戏,因为我们才开始学编程。但到本书的后面部分,我们会开发Tic-Tac-Toe和Ping-Pong游戏。

但是难道你不觉得所有游戏都有共同点吗?每个游戏都需要有一种方法来开始和停止或保存分数。当你以面向对象的方式编写一个程序,你要开始思考如何使类拥有的属性和方法保持绝对的最少。然后你可以基于第一个类来添加更多特殊的功能——在本章节后面部分你会学到继承。这就是为什么VideoGame类只拥有视频游戏所共有的属性和方法。

图1:视频游戏的对象

类还是对象

在本节中我将向你展示如何基于类来创建对象实例,并向你介绍继承的概念。

为了复用你或者其他人已经写好的代码,你可以基于一个类创建另一个,它会继承前一个类的所有属性和方法。继承别的类创建的类称为“子类”,被继承的类称为“父类”。下面的代码展示了继承VideoGame类的新类PlayStation4。

class PlayStation4 extends VideoGame{```

String hardDiskSize;
// 其他属性和方法可以在这里声明
// 方法shareOnFacebooks检查用户是否已经登录了
// 如果没有,它会显示一个窗口,带有以下信息
// “在分享你的分数之前请先登录Facebook”
void shareOnFacebook(){
// 在Facebook上分享的代码在这里
System.out.println("Hey, Facebook, I got PlayStation4 with " + hardDiskSize);
}
void shareOnTwitter(){
// 在Twitter上分享的代码在这里
System.out.println("Hey, Twitter, 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型的变量,分别是firstPlayStation和secondPlayStation,每个都指向了内存中的一个独立对象。注意这些对象的属性hardDiskSize有不同的值(500GB和1TB)。这个程序对第一个对象调用了shareOnFacebook方法,而对第二个对象调用了shareOnTwitter。

public class CreatePlayStation4Objects {
public static void main(String[] args) {
// 创建一个PlayStation4类的实例
PlayStation4 firstPlayStation = new PlayStation4();
firstPlayStation.hardDiskSize = "500GB";
// 对第一个实例调用shareOnFacebook方法
firstPlayStation.shareOnFacebook();
// 创建另一个PlayStation4类的实例
PlayStation4 secondPlayStation = new PlayStation4();
secondPlayStation.hardDiskSize = "1TB";
// 对第二个实例调用shareOnFacebook方法
secondPlayStation.shareOnTwitter();
}

运行CreatePlayStation4Objects会打印以下内容:

Hey, Facebook, I got PlayStation4 with 500GB
Hey, Twitter, I got PlayStation4 with 1TB

如果一个游戏公司要生产10000个这样的游戏,那么程序员可以说他们创建了10000个PlayStation4的实例。游戏公司和一个真正的游戏的关系就类似于Java类和它在内存中的实例的关系。在现实世界中游戏公司制作一个真正的游戏,和Java编程世界中创建PlayStation4对象实例类似。只是每个实例会有些不一样,比如本例中的内部磁盘大小。

图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类添加完find3InARow和highlightWinningCombo方法后,试着玩玩这个游戏。制胜的棋子看起来就是下面这个样子:

图3:我们赢了!

JavaFX包括了多种视觉效果和变换动画,这些可以使你的界面变得更有意思。

要使用这些效果和动画,你需要在javafx.scene.effect和javafx.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);
下面的截屏告诉你动画播放结束后的样子。

图4:淡出的制胜棋子

把这张图和前面一张比一比。或者运行书中的代码,看看动画是什么样子的,就更好了。

喜欢小编轻轻点个关注哦!

原文地址:http://blog.51cto.com/13952975/2323921

时间: 2024-10-03 22:54:08

Java编程也要从娃娃抓起的相关文章

9岁玩转Python,11岁创作游戏,学python从娃娃抓起!!!

近日,一份上海幼升小孩子的简历,吸引了不少关注."比不过一个五岁小孩",成为了网友评论中的一大热门关键句.而在河南省漯河市,也有一位05后"程序员",在别人还在学习拼音时,他已经开始玩转Python,在11岁时独立创作了一款小游戏.他是怎么学习的?又是如何走上编程之路的? 学编程从娃娃抓起,11岁用Pyhton创作游戏 我们都知道Python容易学,但是就是不知道如何去学,去×××资料,机器学习,人工智能,深度学习,都在这学习,小编推荐一个学习平台 欢迎加入pyth

异常笔记--java编程思想

开一个新的系列,主要记一些琐碎的重要的知识点,把书读薄才是目的...特点: 代码少,概念多... 1. 基本概念 异常是在当前环境下无法获得必要的信息来解决这个问题,所以就需要从当前环境跳出,就是抛出异常.抛出异常后发生的几件事: 1.在堆上创建异常对象. 2.当前的执行路径中止                                          3. 当前环境抛出异常对象的引用.                                         4. 异常处理机制接

《Java编程思想》第十三章 字符串

<Java编程思想>读书笔记 1.String作为方法的参数时,会复制一份引用,而该引用所指的对象其实一直待在单一的物理位置,从未动过. 2.显式地创建StringBuilder允许预先为他指定大小.如果知道字符串多长,可以预先指定StringBuilder的大小避免多次重新分配的冲突. 1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月1日 下午4:03:59 4 */ 5 public class UsingStringBuilder {

Java编程练习之输出考试成绩的前三名

在慕课网学习的时候遇到了这样一个Java编程练习题,正好对所学习的Java基础知识检验一下: 请根据所学知识,编写一个Java程序,实现输出考试成绩的前三名 要求: 1考试成绩已保存在数组scores中,数组元素依次为89 , -23 , 64 , 91 , 119 , 52 , 73 2要求通过自定义方法来实现成绩排名并输出操作,将成绩数组作为参数传入 3要求判断成绩的有效性( 0-100 ),如果成绩无效,则忽略此成绩 我自己分析了一下这个程序的过程: (1)首先是定义一个包含整型数组参数的

《Java编程那点事儿》读书笔记(七)——多线程

1.继承Thread类 通过编写新的类继承Thread类可以实现多线程,其中线程的代码必须书写在run方法内部或者在run方法内部进行调用. public class NewThread extends Thread { private int ThreadNum; public NewThread(int ThreadNum){ this.ThreadNum = ThreadNum; } public void run(){ try{ for(int i = 0;i < 10;i ++){ T

Java编程思想【温故知新】

第一章:对象导论 1. 抽象过程(类与对象的关系) 类是一类对象的共同行为(成员函数)与状态(成员变量),对象是具体类的实例化.(Eg.人类是一个类,共同的行为:吃,状态:名字.) [类创建者需要考虑这件事情,回头看看这个概念四个字醍醐灌顶,每次创建这个类的时候,想一想这个类是需要什么成员函数与成员变量来满足单一职责的原则] 2. 每个对象都提供服务:程序设计本身的目标就是去创建能够提供服务来解决问题的一系列对象. 3. 被隐藏的具体实现:类创建者与客户端程序员使用者. 往往来说,每个程序员都是

Java编程思想 4th 第2章 一切都是对象

Java是基于C++的,但Java是一种更纯粹的面向对象程序设计语言,和C++不同的是,Java只支持面向对象编程,因此Java的编程风格也是纯OOP风格的,即一切都是类,所有事情在类对象中完成. 在Java中,使用引用来操纵对象,在Java编程思想的第四版中,使用的术语是"引用(reference)",之前有读过Java编程思想第三版,在第三版中,使用的术语是"句柄(handle)",事实上,我觉得第三版的术语"句柄"更加形象传神,就像你用一个

Java编程中“为了性能”尽量要做到的一些地方

下面是参考网络资源总结的一些在Java编程中尽可能要做到的一些地方. 1. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面: 第一,控制资源的使用,通过线程同步来控制资源的并发访问: 第二,控制实例的产生,以达到节约资源的目的: 第三,控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信. 2. 尽量避免随意使用静态变量 要知道,当某个对象被定义为stataic变量所

Google Java编程风格指南--命名约定

命名约定5.1 对所有标识符都通用的规则标识符只能使用ASCII字母和数字,因此每个有效的标识符名称都能匹配正则表达式 \w+ .在Google其它编程语言风格中使用的特殊前缀或后缀,如 name_ ,  mName ,  s_name 和 kName ,在Java编程风格中都不再使用.5.2 标识符类型的规则5.2.1 包名包名全部小写,连续的单词只是简单地连接起来,不使用下划线.5.2.2 类名类名都以 UpperCamelCase 风格编写.类名通常是名词或名词短语,接口名称有时可能是形容