- Java Web应用开发给力起飞
- 白灵等编著
- 7263字
- 2020-08-28 21:35:27
1.3 第一个任务——日记本
单纯地学习一门语言不是本书的目的,将知识转化为实际的运用才是笔者的意图。现在开始本章的实践任务——日记本程序。
也许读者会问,最终要完成的不是一个Web社区系统吗,做这个日记本有什么用呢?因为Web社区系统虽然比较庞大,但其核心的机能不过只有一条:信息发布。信息虽然多种多样,但是从本质上来讲它们都一样——不都是文字嘛。日记也是一种文字信息,把“信息发布”这个核心机能抽取出来,就成了日记本程序这个小玩意儿。读者在日记本程序上积累的经验,完全可以迁移到社区系统上。
此外,在这个程序的完成过程中,读者会熟悉 Java 的类、接口等基础知识的具体应用,为以后的任务挑战打好基础。
1.3.1 设计日记本程序的类
“哎呀,你那么多废话,我早就听得不耐烦了,快告诉我怎么写这个该死的日记本程序的代码吧!”
先别着急,程序开发的第一步应该是分析设计。大多数人在初学编程的时候,都喜欢上手就开始写代码,而不习惯事先做一些设计思考,更别提将这些设计付诸于笔端了。这有两个方面的原因:一是因为和“设计”这样看似虚无缥缈的东西比起来,代码是实实在在的,运行起来就很有成就感;二是初学编程时写的都是一些小程序,前期设计的作用在这些小规模的程序上无法体现。但请读者记住,在实际的编程之前做一些前期设计,必要时动笔在纸上写一写、画一画,是有百利而无一害的。简单的设计图表等能帮助程序员整理思路,回避一些不必要的错误。读者如果能养成这样的习惯,一定能受益匪浅。好了,下面就请读者跟随笔者花两分钟做些“烦人”的设计吧。
面向对象的程序,本质上是对象之间的关系,所以设计的第一步就是找出这个程序里究竟有哪些对象。方法说来也很简单:分析现实应用情景,从这些情境中抽出相应的“角色”,这些“角色”就是程序中的对象。
什么是“角色”呢?读者可以把它理解为现实情境中的人和物。程序的根本目的在于解决现实中的应用问题,日记本程序就是为了解决“写日记”这件事。这个人们再熟悉不过的“写日记”的情景,涉及的人和物有哪些呢?
如图1-8所示,笔者简单抽出了以下角色:
图1-8
■ 写日记的人——可以称之为用户。
■ 用于写日记的工具(日记本、笔等)。
■ 日记本身。
角色有了,与其对应的对象也就有了。下一步开始打造这些对象的模板——类。为简单起见,这里暂时只关注User(用户)和Diary(日记)两个类。
User:在这个程序中,User 类只用于承载用户信息,所以只为它设置几个简单属性,即name(姓名)、gender(性别)、age(年龄)。
Diary:title(标题)、content(内容)、time(时间)这3个属性不难发现。此外,authorName (作者姓名)也作为属性加入。
这两个类的任务都只是信息的承载,除了属性的读取和设置的get、set方法之外,没有其他的方法(在后面章节的Web开发任务中,读者会经常遇到这样的类),用图简单表示它们,如图1-9所示。
图1-9 User类和Diary类
1.3.2 将类的设计转为代码
前期准备做好了,现在就请读者把注意力转向开发工具Eclipse,如图1-10所示。接下来,笔者要用这个开发工具将前面的设计转化为代码。在此之前,请确认JDK和Eclipse等开发环境已经准备完毕,笔者在附录里详细地介绍了安装配置的方法。
图1-10 打开Eclipse
Eclipse是一个开源项目,由著名的IBM公司投入资金主导,关于它的名称也有不少趣闻。Java的“生父”是原Sun公司(目前Sun公司已被Oracle公司收购),Sun的字面意思为太阳,而Eclipse的意思为“日食”(见图1-10)。IBM为什么取Eclipse这个名字呢?
“这真的很巧合,”IBM总监Sutor表示,“我也不清楚当初为何会选上这个名称。”
真的只是巧合吗?不管怎样,这个名字有待商榷的东西已经成为Java领域最为著名的开发工具,有数不清的组织和个人为它不断增添新功能。时至今日,Eclipse已经成为一个庞然大物,用“博大精深”来形容它绝不过分,即使是有丰富开发经验的高手,也不敢说自己能玩转它。所以,不要被它多得吓人的按钮和选项吓到了,它们中的很大部分,读者今后都不一定用得到,学习Eclipse 最好的方法是用到什么学什么。在例子学习中,只要按照讲解一步一步地做就行了。此外,笔者也会将Eclipse的一些有用技巧告诉读者。
【第1步】现在开始Eclipse之旅。打开Eclipse进入工作空间后,显示如图1-11所示的主界面。
图1-11 Eclipse主界面
【第 2 步】新建一个工程作为类的容身之所。单击左上角的“File”菜单项,在弹出的菜单中选择第一项“New”,出现如图1-12所示的菜单(也可使用快捷键“Alt+Shift+N”调出该菜单),选择“Project”。
图1-12 新建工程
Eclipse的快捷键
要用好一个开发工具,关键是熟悉它的快捷键,这比起用鼠标在菜单或按钮上移来点去要快得多。Eclipse为用户提供了很多方便的快捷键,按“Ctrl+Shift+L”组合键可以随时调出当前可用的快捷键列表进行查看,如图1-13所示。
图1-13 Eclipse快捷键
如果对一些功能的快捷键设置不习惯,或者快捷键和Windows系统快捷键(如输入法快捷键)有冲突,还可以对快捷键进行更改,方法是在按“Ctrl+Shift+L”组合键调出快捷键列表后,再次按下“Ctrl+Shift+L”组合键调出设置窗口,如图1-14所示。
图1-14 快捷键设置窗口
“这两个‘Ctrl+Shift+L’组合键还真是简单啊,Eclipse 快捷键的威力还真不小。‘工欲善其事,必先利其器。’很好,很强大!”
【第3步】选择之后,弹出如图1-15所示的窗口,在此可以选择创建各种不同的工程,这里选择“Java”项下的“Java Project”。
图1-15 创建Java Project
【第4步】选定后,单击下方的“Next”按钮,出现如图1-16所示的画面,这一步是对新建的工程进行配置。在“Project name”后的文本框中输入工程的名称“diary”,其他的选项保持默认,然后单击“Finish”按钮。
图1-16 创建工程diary
【第5步】初始状态下,Eclipse的透视图是“Java EE”透视图,所以工程建立之后,Eclipse会弹出如图1-17所示对话框,提示是否切换到Java 透视图,单击“Yes”按钮。如果勾选对话框左下方的“Remember my decision”,则以后创建工程时,Eclipse均会自动切换到相应的透视图。
图1-17 提示是否切换到Java透视图
Eclipse透视图
Eclipse开发环境是由一个个小窗口——视图(view)组成的。例如,用于浏览工程的“Project Explorer”视图和用于管理任务的“Task”视图。一个透视图就是若干个视图的组合,打开一个透视图实际上就是打开与之关联的一组视图。
如图1-18所示,名为“diary”的Java工程已经创建好了,同时Java透视图包含的视图也打开了——右上角的等按钮用于切换透视图。
图1-18 diary工程界面
【第6步】工程建立好了,现在来创建User和Diary这两个类。再次使用快捷键“Alt+Shift+N”调出新建菜单,单击“Class”新建一个类,出现如图1-19所示的对话框。在这里对新建的类进行设置:在“Package”后的文本框中输入包名“chapter1.diary.bean”;在“Name”后的文本框中输入类名“User”;其他的选项保持默认。然后单击“Finish”按钮。完成以上步骤后,Eclipse 生成了标识符为public的类User,User类创建与之同名的源文件“User.java”。
图1-19 新建User类
包与类的访问修饰符
包(package)的存在主要是为了保证类名的唯一性,同名的类只要位于不同的包中,就不会产生冲突。包还可以组织类的层次关系,如在标准的Java包中,“java.lang”包下存放着Object和String等Java语言基础类,“java.net”包下存放着Socket和URL等网络应用程序类。包的嵌套关系就像操作系统中目录的嵌套一样,但是子包和父包之间、同级别的包之间没有任何关系。一个包中的类可以任意使用同包中的其他类,但若想要使用其他包中的类,则需要通过import引入那个类,或是引入类所在的包。
访问修饰符可以有两种:public和默认(什么都不写)。只有标志为public的类才能被其他包中的类引入使用。一个Java源文件只能有一个声明为public的类,且该类必须与Java源文件同名(如类A对应源文件A.java)。
【第7步】User类创建完成之后,如图1-20所示(用快捷键“Ctrl+M”可最大化当前视图,再次按“Ctrl+M”组合键则可复原),为它加上name、gender、age 3个属性。如果没有特别的目的,类属性的访问修饰符应为private(私有)。这3个属性下的黄色波浪线表示属性在类中从未被访问过(将鼠标移动至编辑视图左侧的黄色感叹号上,可以看到相应的提示信息),暂时无须理会。
图1-20 定义属性
属性及方法的访问修饰符
可用于方法的访问修饰符有3种:public、private、默认(就是什么都不写)。
与类的访问修饰符类似,标记为public的方法具有最宽松的访问权限,它能被任意的其他类访问(无论是同包还是不同包);private只有类自身的方法可以访问;而使用默认的访问修饰符的方法,只有同一个包中的类才能使用。
属性的修饰符用法与方法完全相同,不过在没有特殊目的的情况下,一般都将其设为private。
【第8步】现在来生成各属性的get和set方法。选择顶部菜单Source→Generate Getters and Setters,打开的对话框如图1-21所示。
图1-21 生成get和set方法
【第9步】单击右上方的“Select All”按钮,选择全部3个属性,然后单击“OK”按钮,自动生成3个属性的get和set方法,结果如图1-22所示。
图1-22 生成的方法
【第10步】为了方便,笔者为User类加上了一个构造函数。选择顶部菜单Source→Generate Constructor using Fields,打开如图1-23所示的对话框,在这里可以决定构造函数初始化哪些属性。默认情况下,全部属性已经选中,直接单击下方的“OK”按钮即可。
图1-23 生成构造函数
结果如图1-24所示,Eclipse已经创建好了构造函数。该构造函数接收3个参数,分别用于初始化3个属性。
图1-24 构造函数
关于super()
构造函数的第一句“super()”是做什么用的呢?它的作用是“调用该类的父类的无参数构造函数”。虽然这里没用到继承,但Java中的任何类,包括用户自己创建的类,都是继承自同一个“根”——Object类。由于继承的存在,对象的创建过程是比较复杂的:假设读者写了A和B两个类,其中B继承自A,那么在B的构造函数的第一步必须调用A的构造函数(如果A还有父类,那么继续调用该父类的构造函数,依此类推,直到回溯至Object这个根)。这句代码如果不写,Java编译器会自动插入一个对A的无参数构造函数的调用——super()。所以User构造函数中的super()实际上是不用写的,不过为了加深读者对它的印象,笔者没有删除它。
如果类B没有无参数构造函数呢?这时就不能指望编译器帮忙了,读者只能手工加入对A的有参数构造函数的调用:super(参数1, 参数2,…)。
【第 11 步】一个类如果已经定义了构造函数,那么编译器就不会自动为其创建无参数构造函数了,所以笔者再按上面的方法为User类创建一个无参数构造函数,如图1-25所示。
图1-25 无参构造函数
如果读者在编写代码的过程中,觉得代码挤在一起太难看,可以用代码格式化快捷键“Ctrl+Shift+F”,效果如图1-26所示。是不是清爽多了?
图1-26 自动调整格式
小提示
使用代码格式化快捷键时,Eclipse是按照当前的格式模板来格式化代码的,格式模板中设定了换行、缩进及代码对齐的方式等。
如果要更改当前的格式模板或建立自己的格式模板,可以单击顶部菜单Window→Preferences,在弹出的Preferences窗口的左侧树形菜单中,选择Java→Code Style→Formatter;在右侧界面中,可选择要使用的代码模板,初始情况下有3套内建模板可供选择,分别是Java Conventions(Java传统格式)、Eclipse(默认)及Eclipse2.1。单击“new”即可基于3套模板之一建立自己的模板。
【第12步】用同样的方法建立Diary类,其中属性time为GregorianCalendar类型(Java提供的日历系统类型),title、content和authorName为String字符串类型。完成后的Diary类如图1-27所示。
图1-27 Diary类
现在需要测试一下这两个类。首先,在User类中产生main方法。读者应该还记得main方法的写法,不记得也没关系,这里要向读者介绍Eclipse中最方便的功能——内容辅助(Content Assist)。
【第1步】在要插入main方法的地方,输入“main”,然后按快捷键“ALT+/”。在main的右方会出现浮动窗口,浮动窗口内列出了可供插入的代码,如图1-28所示。
图1-28 浮动窗口
【第2步】默认选中的第1项“main-method”就是需要的main方法,直接按“Enter”键或是双击这一项即可,结果如图1-29所示。
图1-29 添加main方法
小提示
内容辅助可以说是Eclipse中最常用的辅助键了。长长的类名、变量名记不住?没关系,只要输入类名的前几个字母,按内容辅助键。Eclipse就会将符合条件的类名或变量名列出。
for和while等循环语句懒得写?没关系,只要输入一个for或while,按内容辅助键,Eclipse就会列出许多种循环语句的代码让你选择……总之,内容辅助键简直就是对付代码的神兵利器,多研究并利用它,可以节省很多的时间。
现在请读者来关注这个用于测试User类和Diary类的main方法的内容(参见清单1-3):如下的代码模拟了这样一个简单过程:一个名叫“JavaWeb爱好者”的20岁男用户不停地写了3篇日记,第i篇日记的标题为“第i篇日记”,内容为“第i篇日记的内容”(i=1,2,3)。
清单1-3
这段代码很简单,首先创建一个User对象,接着用User对象的name作为authorName创建5个Diary对象,将这5个对象放入一个ArrayList容器中。最后,从ArrayList容器中依次取出5个Diary对象,向控制台输出每个Diary对象的信息。
请读者注意代码中,GregorianCalendar类型提供了get方法,该方法接受类本身提供的一系列类常量作为参数,返回对应的年、月、日等时间值。注意GregorianCalendar中的月份是0~11,换算成实际的月份需要加1。
增强型for循环与泛型
从 JDK 1.5 开始支持的增强型 for 循环能自动遍历数组等容器中的对象,类似其他语言中的 for each。其语法简单,使用起来非常方便。
JDK 1.5也支持“泛型”。它主要应用于ArrayList、HashTable等容器类中。在泛型出现以前,容器类对一切类型的对象都来者不拒:比如一个ArrayList,User类和Diary类的对象都可以往里装。这样固然方便,但是也有明显的缺点:第一,容易错误地装入不恰当类型的对象,想象一下,一个全是“羊”类型对象的数组里,突然混入一个“狼”类型的对象是什么情景;第二,从容器中取出的对象一概被识别为Object,只能通过强制类型转换将其还原为原本的类型,如:
Diary diary = (Diary)diaries.get(0); (取出diaries容器中的第一个对象)
应用了泛型之后,带有<E>类型参数的容器类,只能装入E类的对象,不仅减少了出错的可能,对象取出之后也不必再进行强制类型转换了,使用更加方便,而且不易出错。
类常量
一个类中被public static final修饰的属性称为类常量。3个修饰符的共同作用造就了这种特殊的类属性,public在前文已有阐述,那么static和final是什么呢?
static(静态)修饰的属性可以直接通过“类名.属性名”的方式进行访问。它修饰的方法也可以通过“类名.方法名”的方式进行访问。static就像是一块将属性和方法从对象级别垫高到类级别的“砖头”。
final(终态)修饰的类不能被继承;final修饰的方法不能在继承中被覆盖;final修饰的属性必须在声明时直接初始化或在构造函数中初始化,一旦初始化,其值就不能被更改。final就像是一个将类、属性、方法固定住的“定型胶水”。
综上,类常量是类层次的恒值属性。一些“工具值”常常以类常量的形式出现,如java.lang.Math类中表示圆周率的PI和表示自然对数底数的E等。
【第3步】在Eclipse中运行一下这段代码,当前激活窗口为User.java的情况下,选择顶部菜单Run→Run As→Java Application(或使用快捷键“Alt+Shift+X,J”)即可。运行完毕后,在如图1-30所示的Console视图中显示出了程序的输出语句。注意,其中的时间是作者运行该程序时的时间,读者的运行结果取决于当时的具体时间。如果Console视图没显示在当前透视图中或误将其关闭,选择顶部菜单Window→Show View→Console或使用快捷键“Alt+Shift+Q,C”即可。
图1-30 Console窗口
现在Use类和Diary类已顺利完工。下一小节就将用这两个类组装出日记本程序了。
1.3.3 组装日记本程序
在本节中,读者的任务是用已经创建好的User类和Diary类,结合本书提供的图形界面类,组装出一个带有用户界面的日记本程序。
界面框架使用Java swing的GUI (Graphical User Interface,图形用户界面)库搭建。Java GUI只是作为任务辅助,不在本书的讲解范围内,读者对其中的代码细节大可不必理会。
【第 1 步】首先为图形界面类创建独立的包,使用快捷键“Alt+Shift+N”调出新建菜单,单击“Package”新建一个包。在“Name”后的文本框中输入“chapter1.diary.gui”,单击“Finish”按钮,如图1-31所示。
图1-31 新建包
如图1-32所示,在Package Explorer视图中新建的包出现了。不过,它现在只是一个空包。
图1-32 包浏览器窗口
【第2步】打开资源包中的chapter1文件夹,复制其中的DiaryWindow.java、boy.png等文件。然后在Package Explorer视图中用鼠标右键单击刚才新建的包,在弹出的菜单中单击“Paste”粘贴,将3个文件导入包中(也可以直接采取拖曳的方式,将3个文件拖入包中)。完成后如图1-33所示。
图1-33 导入文件
【第3步】还需要新建一个包“chapter1.diary.main”,在该包下新建一个类作为运行日记本程序的主类,类名为DiaryMain,它只有一个main方法。直接选择新建一个类,如图1-34所示,在“Package”后的文本框中填写“chapter1.diary.main”,在“Name”后的文本框中填写“DiaryMain”。
图1-34 创建DiaryMain类
【第4步】参考前面的内容,为DiaryMain添加main方法,结果如图1-35所示。
图1-35 main方法
新建完DiaryMain类之后,工程的包结构图就变成了如图1-36所示的样子。
图1-36 diary工程包结构图
接下来,将要为读者讲解如何编写这个开启日记本程序的main方法。
首先,读者需要了解DiaryWindow这个界面窗口类的使用方法。DiaryWindow需要读者关注的只有两个方面:
怎样创建它?——它的构造函数是什么?
怎样显示它?——调用的方法是什么?
现在就来解决这两个方面的问题,首先来看看DiaryWindow的构造函数:
chapter1.diary.gui.DiaryWindow public DiaryWindow (User user)
这个构造函数非常简单,只需要传入一个User对象即可,DiaryWindow会用这个User对象的各项属性值显示作者信息。
接下来,要显示这个窗口只需调用以下这个方法:
chapter1.diary.gui.DiaryWindow 继承自 java.awt.window public void setVisible (boolean b)
这个方法接收一个boolean类型的参数,若为“true”则显示窗口,若为“false”则隐藏窗口。窗口创建和显示的问题都解决了,现在可以动手来写DiaryMain类的main方法了(参见清单1-4)。
清单1-4
清单1-4是笔者给读者的DiaryMain示例代码,请读者可以模仿并创建与自己的个人信息相同的User对象传入,试验一下。
下面来示范一下用户是如何在这个程序里写入并保存日记的。
【第1步】执行该main方法,显示的程序窗口如图1-37所示。
图1-37 新日记窗口
【第2步】当前还没有任何日记。单击“写新日记”按钮,就会显示如图1-38所示的窗口。读者可以输入新日记标题及内容,然后单击“保存”按钮。
图1-38 保存窗口
【第3步】为了避免误操作,这个程序还需要用户确认是否保存日记,如图1-39所示。
图1-39 确认保存
【第4步】单击“确定”按钮保存,日记就保存完毕了,如图1-40所示。
图1-40 保存成功
用户使用同样的方法,可以不断添加日记。当用户需要查看某个日记的具体内容时,只需要在图1-37所示的列表中,双击该日记即可。
另外,这个程序还提供了一个“选项”菜单,读者单击其中的“主人信息”就会显示如图1-41所示的对话框,其内容与传入的user对象的属性完全一致,根据user对象的gender属性,显示的小人图标也会不一样。读者可以尝试将传入参数user的gender设为“女”试试。
图1-41 主人信息
这里要提醒读者,因为这个程序是作为基础讲解的,所以并未设置严格的错误处理。比如,user的 gender 属性完全可以赋值为“男”和“女”之外的任意字符串,所以请读者注意将属性参数设置正确,并严格按照之前的讲解配置各种源文件及图像文件,否则可能会导致运行出错。
虽然简陋了点,但至此,读者的日记本程序算是初步完工了。一直到这里的任务,如果读者都顺利完成的话,可以为自己小小地庆祝一下了!