Java SE实践教程
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.2 练习

下面我们将通过一些练习来帮助您进一步认识Java及学习如何运用NetBeans IDE进行Java程序开发。

1.2.1 搭建Java开发环境

在开始Java程序设计之前,我们先来学习如何搭建Java程序开发环境。本书用到的Java程序开发环境由Java开发工具包Java SE Development Kit(JDK™)6.0及Java程序设计集成环境Java Integrated Development Environment(IDE)NetBeans 6.1组成。

工具下载地址如下:

Java Development Kit(JDK)6.0 ,http://java.sun.com/javase/downloads/

NetBeans 6.1 ,http://download.netbeans.org/netbeans/6.1/final/?pagelang=zh_CN

本练习的具体操作步骤如下。

下载、安装并配置JDK

下载JDK

打开浏览器,在地址栏内输入JDK下载网址http://java.sun.com/javase/downloads/,下载最新版本的JDK。为了和本书使用的JDK版本(JDK 6u7)保持一致,您可以到http://java.sun.com/products/archive/ 下载JDK6 Update 7,在JDK/JRE-6下拉选择框中选中“6 Update 7”,点击后面的“GO”按钮。如图1-3所示,在新页面中选择“Windows”平台,“Multi-language”多国语言版,并且在许可证协议前打勾,按“Continue>>”按钮继续。

图1-3 JDK下载

在随后出现的下载页面中,选择Windows Offline Installation的exe文件,点击其链接,将其下载到本地。

安装JDK

双击我们刚刚下载的名为jdk-6u7-windows-i586-p.exe的可执行文件,进行JDK的安装。随后弹出JDK安装向导,它将协助你一步步完成整个JDK的安装过程。在安装过程中,须要注意如图1-4所示界面,正确选择JDK安装路径及要安装的内容。

图1-4 JDK安装

系统提示JDK安装成功后,点击“完成”按钮退出JDK安装界面,此时JRE的安装界面会自动弹出,同样须要注意其安装路径,最好和刚刚安装的JDK 放在同一目录下。当安装向导再次提示安装完成后,整个JDK的安装才算真正完成。此时你的Java目录结构应该如图1-5所示。

图1-5 Java目录结构

设置环境变量

步骤如下:

回到桌面,鼠标右击“我的电脑”→“属性”→“高级”→“环境变量”。

1.系统变量→新建→变量名:JAVA_HOME,变量值:你选择安装Java的目录,例如C:\Program Files\Java\jdk1.6.0_07,如图1-6所示。

图1-6 设置系统环境变量

2.系统变量→编辑→变量名:Path,在变量值的最前面加上:%JAVA_HOME%\bin;。

3.系统变量→新建→变量名:CLASSPATH,变量值:.;。

说明:CLASSPATH后面的那个"."代表当前目录。

下载并安装NetBeans IDE

在浏览器中输入NetBeans下载网址http://www.netbeans.org/downloads/index.html,可以下载到最新的NetBeans版本。为了和本书使用的NetBeans版本一致,您可以到http://www. netbeans.org/downloads/6.1/index.html 下载NetBeans6.1简体中文版。如图1-7所示,选择语言为“简体中文”,选择平台为“Windows2000/XP/Vista”,选择“全部”下载包,点击“下载”按钮开始下载。

图1-7 下载NetBeans IDE安装程序

下载完成后,双击安装程序进行NetBeans IDE的安装。NetBeans IDE安装程序通常能够自动识别你机器上的JDK安装路径,要是你装有多个版本JDK,请在如图1-8的界面中具体说明将用于NetBeans IDE的相关JDK的安装位置。

图1-8 设置系统环境变量

NetBeans IDE安装完成后,安装向导将显示成功安装界面,点击“完成”按钮退出。至此, NetBeans IDE安装完毕。

下载Java API文档

Java API文档是Java最重要的编程手册,也是我们在整个Java学习及Java程序设计过程中查询的宝典。Sun在其网站(http://java.sun.com/reference/api/)上提供了各个版本Java的在线文档。你也可以选择把它打包下载到本地查阅。

打开浏览器,输入网址http://java.sun.com/javase/downloads/,选择Java SE 6 Documentation,如图1-9所示,点击右侧的“Download”按钮,下载文档压缩包。

图1-9 下载Java SE文档

下载完成后,用Winzip或Winrar之类的解压缩软件把jdk-6-doc.zip包解压到本地任意目录下,例如C:\Program Files\Java\jdk-6-doc,你就可以脱机查询全套Java的API文档了。

为了更方便地配合开发过程中快速查询的需要,我们还可以把Java API文档整合到NetBeans开发环境中,具体方法如下:

1. 打开NetBeans IDE,从IDE主窗口中选择“工具”→“Java平台”。

2.在弹出的对话框的右侧面板中,选择“Javadoc”标签页。

3. 单击“添加ZIP/文件夹”,指定Javadoc文件的位置。如图1-10所示,点击“关闭”保存设置。

图1-10 导入Java API文档

至此我们可以在编码的过程中,直接将鼠标指针放在要查看的代码中,按Alt+F1组合键来查看相关代码的Java API文档了!

另外,如果你不习惯看英文,还可以从Sun中国技术社区(http://developers.sun.com.cn/)下载中文版的API文档。

1.2.2 体验Java程序开发

本练习包括两个小练习,旨在向你展示如何在命令行方式下进行Java程序开发,以及带你体验NetBeans IDE给Java程序开发带来的便捷。

“同一个世界,同一个梦想”

本练习将使用JDK提供的命令行方式来编译及运行一个简单Java程序,目的是将北京2008奥运会的口号“同一个世界,同一个梦想”输出打印在屏幕上。

具体步骤如下:

1. 首先在C盘根目录下创建一个名为code的文件夹,用来存放我们练习中将要用到的文件。

2. 鼠标点击桌面左下角“开始”→“所有程序”→“附件”→“记事本”,在“记事本”中敲入如下所示代码。

    public class BeijingOlympicSlogan {
    /**
        * 打印2008北京奥运口号程序
        */
       public static void main( String[] args ){
                 // 把字符串 "同一个世界,同一个梦想" 打印在屏幕上
          System.out.println("同一个世界,同一个梦想");
       }    
    }

点击“文件”→“另存为…”,给文件取名为BeijingOlympicSlogan.java,存放在C:\code目录下。

3. 鼠标点击桌面左下角“开始”→“运行…”,键入CMD,点击确定,此时弹出一个命令提示符窗口。

4.在提示符“>”后敲入命令cd C:\code,按回车,此时你的命令行提示符变成C:\code>。敲入命令 javac BeijingOlympicSlogan.java,按回车,此时JDK的编译器对源文件BeijingOlympicSlogan.java 进行编译,其结果是在同一目录下生成一个名为BeijingOlympicSlogan.class的字节码文件。

5.在当前命令行提示符下敲入dir命令并按回车来查看BeijingOlympicSlogan.class文件是否存在。

6.在当前命令行提示符下敲入java BeijingOlympicSlogan,按回车,此时你会欣喜地发现,北京奥运会的宣传口号“同一个世界,同一个梦想”自豪地打印在你的屏幕上,如图1-11所示。

图1-11 命令行方式编译、运行Java程序

课外练习

1.通过命令java –version来查看当前系统的java版本。

2.通过命令java –help来查看java的用法。

3.通过命令javac –help来查看编译器的用法。

工欲善其事,必先利其器

本练习学习如何使用NetBeans IDE新建项目,任务依然是在屏幕上打印出北京2008奥运会口号字符串。

本练习操作步骤如下。

双击NetBeans IDE 6.1的图标,打开NetBeans IDE。

打开“文件”菜单→“新建项目”,在弹出的“新建项目”对话框中,如图1-12所示,分别在“类别”栏中选择Java,在“项目”栏中选择“Java应用程序”,点击“下一步”。

图1-12在NetBeans中新建项目

弹出界面如图1-13所示,在“项目名称”中输入BeijingOlympicSlogan,“项目位置”选C:\code,“创建主类”也输入BeijingOlympicSlogan,点击“完成”按钮。

图1-13在NetBeans中新建应用程序

你会发现如图1-14所示的一个空的NetBeans项目框架在IDE中自动打开了,并且一个包含main函数的BeijingOlympicSlogan类已经在右侧编辑窗口内打开。

图1-14 NetBeans编程界面

你可以把main函数里的注释“// TODO code application logic here”删除,在其原来的位置上敲入sout,并按Tab键,你将看到系统自动生成了System.out.println("");语句,而且光标位于引号之间。此时我们可以在光标位置处输入“同一个世界,同一个梦想”的奥运口号。打开“运行”菜单→“运行主项目”,或按快捷键F6,NetBeans将帮我们保存刚刚修改的java文件并且编译,要是编译顺利通过,它将继续帮我们运行编译后生成的class文件。

运行结果如图1-15所示,北京奥运的口号又一次不出所料地打印在屏幕上,不过这次不是在命令提示符窗口中,而是在NetBeans IDE的输出控制台上。

图1-15 控制台上的程序输出结果

至此,我们只写了一行代码就几乎完成了之前在命令行方式下所做的所有工作。现在我们将程序的功能稍微扩展一下,提问让用户回答北京奥运的口号,并把用户的输入答案输出打印在控制台上。用如下4行代码替换之前的一行输出北京奥运口号的代码。

    System.out.print("请问2008年北京奥运会的口号是什么?");
    Scanner input = new Scanner(System.in);
    String s = input.next();
    System.out.println("2008年北京奥运会的口号是: "+s);

此时NetBeans的代码编辑器里出现了如图1-16所示红色惊叹号和带红色惊叹号的黄色小灯泡。

图1-16 带惊叹号和小灯泡的出错代码

当你将鼠标悬浮在小灯泡或惊叹号上面时,NetBeans会给出如图1-17所示的报错提示,此提示的含义为类Scanner找不到符号。

图1-17 鼠标悬浮后得到的提示

我们可以用鼠标点击这小灯泡来获得NetBeans给出的参考修正建议,如图1-18所示。

图1-18 NetBeans给出的修正建议

我们双击第一个建议“添加java.util.Scanner的import”,此时文件最顶部多出 import java.util.Scanner;语句,同时小灯泡、惊叹号也都消失了。我们再按F6,将出现“请问2008年北京奥运会的口号是什么?”的屏幕提示,我们可输入“同一个世界,同一个梦想”按回车确定,得到的结果如图1-19所示。

图1-19 功能扩展后的运行结果

至此这个练习做完了,我们从中感受了NetBeans是如何智能地帮助程序开发人员纠错的。你可以尝试将这个例子继续按照自己的想法扩充下去,借机摸索和熟悉NetBeans IDE的众多优秀功能。我们将此任务作为课外练习留给你自己去完成。

课外练习

熟悉NetBeans IDE,重构源代码,扩充练习的功能。

1.2.3 J2SE 5.0新特性实践

下面我们将在NetBeans IDE中实践J2SE 5.0的一些语言新特性。

学生成绩管理系统:ScoreManager

本练习我们将使用J2SE 5.0提供的语言新特性来对一个用J2SE 1.4编写的学生管理系统ScoreManager进行改写,从而帮助您更好地理解J2SE 5.0的各种语言新特性,以及体会其带来的安全性的增强与便捷度的提高。

具体步骤如下。

1. 下载源文件并打开项目。

浏览前言中提到的本书配套网址,找到并下载第1章的练习源代码压缩包。将其解压到本地任意目录,例如C:\code。启动NetBeans IDE 6.1简体中文版,打开“文件”菜单→“打开项目(E)…”

如图1-20所示,在“打开项目”对话框中,查看文件解压的目录并选择ScoreManager项目,勾选“作为主项目打开”,点击“打开项目”按钮,此时项目在IDE中打开。

图1-20 打开项目对话框

2. 分析源代码。

此NetBeans项目中包含了Main、Student和Result 3个Java源文件,我们可以读一下这3个Java源文件的代码,分析它们的作用。Result.java用于处理科目成绩的对象,主要有“科目”subject和“得分”score这两个成员变量,并且用getGrade()方法把一个具体的得分按照其采用的HD/D/C/P/CP/F等级评分体系给出一个成绩,例如:得分87分,处于[85,100]区间,成绩应该是HD(High Distinction的缩写)。Student.java用于表示学生的对象,有“学生学号”studentNumber及“成绩”results(是个List容器)两个成员变量,其中addResult(String subject, int score)方法,会调用Result类的构造函数将每门科目及其相对应的成绩装入学生的成绩容器里。Main.java用来接受控制台输入及负责打印输出,将用户输入的每位学生的科目及成绩打印在控制台上。我们可以按F6先运行一下整个程序,对它完成的功能有个直观印象,之后再返回去分析源代码,这样就容易理解多了。按照屏幕提示输入学号、科目及成绩等信息,运行结果如下:

    init:
    deps-jar:
    Compiling 2 source files to C:\code\ScoreManager\build\classes
    注意:C:\code\ScoreManager\src\javase\book\chapter1\scoremanager\Main.java
    使用了未经检查或不安全的操作。
    注意:要了解详细信息,请使用-Xlint:unchecked 重新编译。
    compile:
    run:
    Please input student number(input Q to finish):
    1
    Please input subject name(input Q to finish):
    语文
    Please input score of 语文(input Q to finish):
    86
    Please input subject name(input Q to finish):
    数学
    Please input score of 数学(input Q to finish):
    90
    Please input subject name(input Q to finish):
    英语
    Please input score of 英语(input Q to finish):
    65
    Please input subject name(input Q to finish):
    q
    Please input student number(input Q to finish):
    2
    Please input subject name(input Q to finish):
    语文
    Please input score of 语文(input Q to finish):
    70
    Please input subject name(input Q to finish):
    数学
    Please input score of 数学(input Q to finish):
    63
    Please input subject name(input Q to finish):
    物理
    Please input score of 物理(input Q to finish):
    78
    Please input subject name(input Q to finish):
    q
    Please input student number(input Q to finish):
    q
    **************************************************************
    ScoreManager is now listing all the score you have just input:
    **************************************************************
    1
         语文       86       HD
         数学       90       HD
         英语       65       C
    2
         语文       70       C
         数学       63       P
         物理       78       D
    成功生成(总时间:1 分钟 32 秒)

3. 静态导入。

在Main.java里面添加如下静态导入语句:

这样在Main类里就可以对静态导入的java.lang.Short的静态变量 MAX_VALUE 及java.lang.Integer的静态方法 parseInt 进行直接调用了。现在我们将 Main.java里面用到Short.MAX_VALUE及Integer.parseInt的第25行、第30行及第42行,都改写成MAX_VALUE及parseInt的直接调用形式。

4. 注释。

注释的用法有很多种,最能发挥其优点的用法也许要数用户自定义注释了。但是我们今天要用的是J2SE 5.0中预定义的3种标准注释之一的@Override,它注释了此方法覆盖其父类的同名方法。

在NetBeans IDE里打开Student.java源文件后,你会发现代码左侧有一些带黄色三角形惊叹号的小灯泡。我们先用鼠标单击一下第57行的小灯泡,结果如下:

系统提示要“添加@Override标注”,点击选择“添加@Override标注”,如下所示的代码@Override会自动被添加到Student.java中的相应位置。

贴士:如点击@Override前面的绿色Override图标,NetBeans IDE会帮你打开其父类的源文件,定位到其同名方法供你参考。

除了NetBeans IDE自动帮我们添加@Override注释外,我们也可以手工添加这一行@Override。接下来,我们在Student.java里剩下的toString()及hashCode()方法前面都加入这一行@Override,对其进行注释。

同样,我们在Result.java里面,也对tostring()、equals(Object 0)及hashCode()方法手工加入@Override进行注释。但此时我们发现tostring()前面出现了一个红色惊叹号,单击它将出现如下所示“方法不会覆盖或实现超类型的方法”的标示。

此时我们发现,原来是把 toString()拼写成了tostring(),大小写搞错了。其父类中根本不存在tostring()这个方法,所以也就无从覆盖了。

我们用鼠标选中tostring,点右键,出现以下界面,选择“重构”→“重命名(R)…”

在如图1-21所示的弹出对话框中,填入新名称:toString,点击“重构(R)”按钮确定。

图1-21 重命名重构对话框

5. 泛型。

为了允许编译器捕获类型的不匹配,提高类型安全性,须把程序中用到的集合类型改成泛型表示。

我们先把Main.java里第21行的学生容器初始化语句List students = new ArrayList();改成类型为Student的泛型List<Student> students = new ArrayList<Student>();,接下来把第53行for循环里的Iterator也改成泛型Iterator<Student>,这样第54行的赋值语句就不用类型转换了,可以把(Student)iterStudent.next()改成iterStudent.next();。

下面对Student.java进行改写。同样,在第12行容器初始化时可以直接定义为Result类型的容器,语句可改成private List<Result> results = new ArrayList<Result>();。另外,第25行的getResults()方法的返回值类型及第31行的setResults(List results)的参数类型,也都应该改成泛型List<Result>。接下来把第51行对成绩容器进行遍历的Iterator改成泛型Iterator<Result>,第52行的赋值语句就不用强制类型转换了,可以把(Result)iterator.next()改成iterator.next();。

下面把Student.java里面的Student类实现的接口Comparable改成泛型Comparable<Student>,如下所示:

这样一来,我们实现的Comparable接口的compareTo方法可以做如下改动。

改变前:

改变后:

泛型事先限定了类型,使得类型安全,不会在运行时抛出ClassCastException的类型转换异常。

6. 增强的for循环。

增强的for-each循环简化了对集合和数组的遍历。我们可以将Main.java里对students容器的遍历及Student.java里对results容器的遍历用增强的for循环做如下简化。

Main.java改写前:

Main.java改写后:

Student.java改写前:

Student.java改写后:

这样改写以后,import java.util.Iterator;就可以不用了,请在Main.java和Student.java中分别删除它。

7.自动装箱/拆箱。

下面再来看看如何利用J2SE 5.0提供的自动装箱/拆箱特性来改进这个程序。我们注意到在Main.java里面,当调用Student的构造函数对student 进行初始化和赋值时,以及当调用addResult()方法读入成绩时,为了避免类型不匹配,参数都用了parseInt来进行强制转换。例如,Sutdent的构造函数为Student(int studentNumber),参数studentNumber必须是int类型,所以在Main.java里调用它时,必须将String类型的studentNumber强制转换成int类型, Student(parseInt(studentNumber))。其实我们可以在调用Student构造函数时,参数直接给出Integer包装类型,用Java自动拆箱的新特性,让编译器来完成参数传递时Integer类型和int类型的自动类型转换,例如:Student(new Integer(studentNumber))。

我们来看看代码改写前后的变化。

改写前:

改写后:

此时之前静态导入的方法import static java.lang.Integer.parseInt;也可以不要了,如图1-22所示,点击代码前带黄色三角的小灯泡,删除未使用的导入。

图1-22 删除未使用的导入

8. 枚举类型。

下面我们来看看如何用J2SE 5.0提供的新关键字enum来实现Result类中对成绩等级的划分。HD/D/C/P/CP/F等级评分体系把0~100分的成绩按照区间划分成6等,分别为HD(85, 100)、D(75, 84)、C(65, 74)、P(50, 64)、CP(45, 49)、F(0, 44)。这样我们就可以用枚举类型enum来列举这6种成绩等级。

在NetBeans IDE右侧窗口的“项目”标签页中,如图1-23所示,选中项目“ScoreManager”,右击选择“新建”→“Java类...”

图1-23 新建Java类

在弹出的对话框中,如图1-24所示,输入类名 Grade,选择包 javase.book.chapter1. scoremanager,点击“完成”按钮确定。

图1-24 新建Java类对话框

在打开的Grade.java编辑窗口输入如下代码:

    package javase.book.chapter1.scoremanager;
    /**
    * 用于表示成绩登记的枚举类型
    * Improvement 7 枚举类型
    */
    enum Grade {
        HD(85, 100), D(75, 84), C(65, 74), P(50, 64), CP(45, 49), F(0, 44);
        /**
        * 成员变量
        */
        private int min, max;
        /**
        * 构造函数
        *
        * @param min
        *          该级别的最小值
        * @param max
        *          该级别的最大值
        */
        private Grade(int min, int max){
            this.min = min;
            this.max = max;
        }
        /**
        * 根据成绩获得等级
        *
        * @param mark
        *          考试成绩
        * @return 对应的等级
        */
        public static Grade getInstance(int mark){
            if(mark < 0)
                return null;
            else if(mark <= F.max)
                return F;
            else if(mark <= CP.max)
                return CP;
            else if(mark <= P.max)
                return P;
            else if(mark <= C.max)
                return C;
            else if(mark <= D.max)
                return D;
            else if(mark <= HD.max)
                return HD;
            else
                return null;
        }
        /**
        * 下面的Override注释指示了toString方法是覆盖自父类
        */
        @Override
        public String toString(){
            return super.toString()+ "(" + min + "-" + max + ")";
        }
    }

我们新建了一个特殊的类 Grade,它的类型是enum。阅读代码你可以发现,它不仅例举了HD/D/C/P/CP/F各个等级,而且它有自己的成员变量、构造函数及方法。接下来我们要稍微修改一下Result.java,让它可以利用好这个枚举类型。我们来修改getGrade()这个方法。

修改前:

修改后:

9.可变参数。

我们再来看看如何使用可变参数,我们对Student.java里的addResul(t String subject, int score)函数进行改写,改成如下可变参数形式:

        public boolean addResult(Result... resultArray){
            if(resultArray == null || resultArray.length == 0)
                return false;
            for(Result result : resultArray)
                if(!results.add(result))
                    return false;
            return true;
        }

这样在Main.java里面对Student的addResult方法进行调用时,就可以将原本student.addResult(subject, new Integer(score));的代码改写成可变参数的形式student.addResult(new Result(subject, new Integer(score)));。再按F6运行,看看改写完成后的输出结果:

    init:
    deps-jar:
    compile:
    run:
    Please input student number(input Q to finish):
    1
    Please input subject name(input Q to finish):
    数学
    Please input score of 数学(input Q to finish):
    89
    Please input subject name(input Q to finish):
    物理
    Please input score of 物理(input Q to finish):
    71
    Please input subject name(input Q to finish):
    q
    Please input student number(input Q to finish):
    q
    **************************************************************
    ScoreManager is now listing all the score you have just input:
    **************************************************************
    1
          数学       89       HD(85-100)
          物理       71       C(65-74)
    成功生成(总时间:21 秒)

10. 尾声。

至此,我们将讲解中介绍到的J2SE 5.0提供的7种语言新特性,都一一运用到了ScoreManager这个学生成绩管理系统中,对它进行了改写,使它更高效、简洁和安全。相信您一定对这些语言新特性及其使用方式有了更深刻的理解。

说明:第1章的源代码中还提供了一个名为ScoreManagerStepByStep的项目,供读者借鉴和学习。