Java编程技术大全

978-7-115-50100-4
作者: 魔乐科技(MLDN)软件实训中心 编著 张玉宏 主编 周喜平
译者:
编辑: 张天怡
分类: Java

图书目录:

详情

本书面向Java的零基础读者,用实际案例引导读者学习。本书主要包括基础知识、核心技术、高级应用和项目案例等4篇内容,帮助读者系统、全面地学习。 为了增强实用性,还特别赠送了精选的考试认证、求职面试等题库,供读者研究学习。最后,为帮助初入职场的从业者顺利进入角色,还赠送了职业规划建议及相关开发文档。

图书摘要

版权信息

书名:Java编程技术大全(上下册)

ISBN:978-7-115-50100-4

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

编  著 魔乐科技(MLDN)软件实训中心

主  编 张玉宏

副   周喜平

责任编辑 张 翼

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315



本书主要面向零基础读者,用实例引导读者学习,深入浅出地介绍Java的相关知识和实战技能。

本书第Ⅰ篇“基础知识”主要讲解Java开发环境搭建、Java程序要素,并逐一介绍常量、变量、运算符、表达式、语句、流程控制、数组、枚举、类、对象以及方法等;第Ⅱ篇“核心技术”主要介绍类的封装、继承、多态,并逐一介绍抽象类、接口、Java常用类库以及异常的捕获与处理等;第Ⅲ篇“高级应用”主要介绍多线程、文件I/O操作、GUI编程、Swing GUI编程、Java Web、常用设计框架以及Android编程基础等;第Ⅳ篇“项目实战”主要介绍智能电话回拨系统、理财管理系统、我的饭票网以及Hadoop下的数据处理等。

本书提供了与图书内容全程同步的教学视频。此外,还赠送大量相关学习资料,以便读者扩展学习。

本书适合任何想学习Java的初学者,无论初学者是否从事计算机相关行业,是否接触过Java,均可通过对本书内容的学习快速掌握Java的开发方法和技巧。


本书是专为Java初学者量身打造的一本学习用书,由专业计算机图书策划机构“龙马高新教育”精心策划编写而成。

本书主要面向Java初学者和爱好者,旨在帮助读者掌握Java基础知识、了解开发技巧并积累一定的项目实战经验。

荀子曰:“不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之。”

实践对学习的重要性由此可见一斑。纵观当前编程图书市场,理论知识与实践经验的脱节,是一些Java图书中经常出现的情况。为了避免这种情况,本书立足于实战,从项目开发的实际需求入手,将理论知识与实际应用相结合。目的就是让初学者能够快速成长为初级程序员,并拥有一定的项目开发经验,从而在职场中拥有一个高起点。

本书总结了作者多年的教学实践经验,为读者设计了合适的学习路线。

无论读者是否从事计算机相关行业,是否接触过Java,是否使用Java开发过项目,都能从本书中获益。

本书结合实际工作中的范例,逐一讲解Java的各种知识和技术。最后,还通过实际开发项目总结本书所学内容,帮助读者在实战中掌握知识,轻松拥有项目经验。

每章首页给出了“本章要点”,以便读者明确学习方向。每章最后的“实战练习”则根据本章的知识点精心设计而成,读者可以随时自我检测,巩固所学知识。

本书在讲解过程中使用了“提示”“注意”“技巧”等小栏目,帮助读者在学习过程中更清楚地理解基本概念,掌握相关操作,并轻松获取实战技巧。

涵盖本书所有知识点,详细讲解每个范例和项目的开发过程及关键点,帮助读者更轻松地掌握书中的所有Java程序设计知识。

赠送大量电子资源,包括Java和Oracle项目实战教学视频、Java SE类库查询手册、Eclipse常用快捷键说明文档、Eclipse提示与技巧电子书、Java常见面试题、Java常见错误及解决方案、Java开发经验及技巧大汇总、Java程序员职业规划、Java程序员面试技巧。

读者可以申请加入编程语言交流学习群(QQ:829094243),可在群中获得本书的学习资料,并和其他读者进行交流,帮助你无障碍地快速阅读本书。

为了方便读者学习,本书提供了大量视频教程的二维码。读者使用微信、QQ的“扫一扫”功能扫描二维码,即可通过手机观看视频教程。

如下图所示,扫描标题旁边的二维码即可观看对应章节的视频教程。

本书主编为张玉宏,副主编为周喜平、姜斌、曹鹤玲。其中第0~9章、第12~16章、第18~21章、第30章及附录由河南工业大学张玉宏编写,第10~11章、第17章、第24章及第25章由郑州大学西亚斯学院周喜平编写,第27章和第29章由郑州大学西亚斯学院姜斌编写,第22~23章、第26章及第28章由河南工业大学曹鹤玲编写。参与本书编写、资料整理、多媒体开发及程序调试的人员有孔万里、周奎奎、张田田、常俊杰、黄月、谢洋洋、刘江涛、张芳、江百胜、尚梦娟、张会锋、王金丽、贾祥铎、陈小杰、左琨、邓艳丽、崔姝怡、侯蕾、左花苹、刘锦源、普宁、王常吉、师鸣若、钟宏伟、陈川、刘子威、徐永俊、朱涛和翟桂花等。

在本书的编写过程中,我们竭尽所能地将更好的讲解呈现给读者,但也难免有疏漏和不妥之处,敬请广大读者不吝指正。若读者在阅读本书时遇到困难或疑问,或有任何建议,可发送邮件至zhangtianyi@ptpress.com.cn。

 

编者

❶ Java和Oracle项目实战教学视频

❷ Java SE类库查询手册

❸ Eclipse常用快捷键说明文档

❹ Eclipse提示与技巧电子书

❺ Java常见面试题

❻ Java常见错误及解决方案

❼ Java开发经验及技巧大汇总

❽ Java程序员职业规划

❾ Java程序员面试技巧


Java是一门优秀的编程语言,它的优点是与平台无关,可以实现“一次编写,到处运行”。Java是一门面向对象的语言,它简洁高效,具有高度的可移植性。本章介绍Java的来源、基本思想、技术体系、应用领域、前景以及学习Java的技术路线。

本章要点(已掌握的在方框中打钩)

目前,常用的编程语言就有数十种,令人应接不暇,到底哪一种语言更值得我们学习呢?要知道,学习任何一种语言,都需付出昂贵的时间成本(甚至金钱成本),如何选择一种真正需要的编程语言来学,就是一门学问了。

在现实生活中,有个很有意思的经验。当我们来到一个陌生的城市,自然想找一家比较有特色的饭馆,但面对矗立街头、琳琅满目的饭馆,该选择哪家最好呢?有人说,哪家人少去哪家,因为这样不用等!但有经验的“吃货”会告诉你,哪家人多,特别是等的人多,就去哪家。为什么呢?逻辑很简单,之所以人多,是因为好吃。之所以等的人多,是因为它值得人等。一句话,大样本得出的推荐建议,总还是比较信得过的。

对于初学者来说,编程语言的选择,犹如饭馆的挑选——追随多数人的选择,纵然可能没有满足你个性化的需求,但绝对不会让你错得离谱。目前,我们既然正处于大数据的时代,就要善于“让数据发声”。

根据TIOBE统计的数据1,在2018年5月编程语言前10名排行榜中,Java名列榜首。虽然在不同的年份,Java、C和C++的前3名地位可能有所互换,但多年来,Java在整个编程领域前三甲的地位,基本上没有动摇。

1TIOBE编程社区指数是编程语言流行趋势的一个指标,每月更新一次。排名数据的获取主要源自著名的搜索引擎或知名网站搜索(或点击)次数,这些网站大致为Google、Blogger、Wikipedia、YouTube、Baidu、Yahoo!、Bing、Amazon。需要说明的是,这个排行榜利用了关键词搜索热度来代表流行程度:某个语言搜索的次数越多,说明这门语言越受人关注(也就更加流行)。TIOBE编程社区指数,简而言之,只是一个关键字查询(点击)排行榜,在某种程度上,只反映一门编程语言的流行度,并不能据此说明某门编程语言的优劣高下。

从上表反映的情况可以看出,Java作为一门编程语言,其关注度长期高居各种编程语言流行榜的榜首,这也间接说明了Java应用领域的广泛程度。事实上,Java的开放性、安全性和庞大的社会生态链以及其跨平台性,使得Java技术成为很多平台事实上的开发标准。在很多应用开发中,Java都是作为底层代码的操作功能的调用工具。

当下,不论是桌面办公还是网络数据库,不论是PC还是嵌入式移动平台,不论是Java小应用程序(Applet)还是架构庞大的J2EE企业级解决方案,处处都有Java的身影。

目前,随着云计算(Cloud Computing)、大数据(Big Data)时代的到来以及人们朝着移动领域的扩张,越来越多的企业考虑将其应用部署在Java平台上。无论是面向智能手机的Android开发,还是支持高并发的大型分布式系统开发,无论是面向大数据批量处理的Hadoop开发,还是解决公共云/私有云的部署,都和Java密不可分,Java已然形成一个庞大的生态系统。

此外,Java的开放性,也对打造其健壮的生态系统贡献非凡。基本上,无论我们有什么新的想法,都可以在Java的开源世界中找到对应的实现,而且其中很多解决方案还非常靠谱。例如服务器相关的Tomcat、计算框架相关的Hibernate、Spring和Struts,大数据处理相关的ZooKeeper、Hadoop和Cassandra,等等。有了基于Java开发的开源软件,开发者们就可以不用从零开始“重造轮子”,这样就大大减轻了开发组的负担,提高了解决问题的效率。

坦率来说,对于很多计算机相关领域的从业人员,找份好工作是学习某门编程语言本质的驱动力。而Java应用领域之广泛,也势必促使面向Java开发者的就业市场,呈现欣欣向荣之态势。根据国际数据公司(International Data Corporation,IDC)的统计数据,在所有软件开发类人才的需求中,对Java工程师的需求,达到全部需求量的60%~70%。这一高分数字,足以让Java语言初学者,跃跃欲试。

一言蔽之,学好用好Java,可以解决诸多领域的问题,这就是Java如此重要的原因。

著名人类学家费孝通先生曾指出,我们所谓的“当前”,其实包含着从“过去”历史中拔萃出来的投影和时间选择的积累。历史对于我们来说,并不是什么可有可无的点缀之饰物,而是实用的、不可或缺的前行之基础。

Java从诞生(1995年)发展到现在,已经度过了20多年。了解Java的一些发展历史,有助于我们更好地认识Java,看清这纷杂的编程语言世界,进而用好Java。

说到Java的发展历程,就不能不提到它的新老两个东家——Sun(太阳)公司和Oracle(甲骨文)公司。先说Sun公司,事实上,Sun的本意并非“太阳”,而是斯坦福大学校园网(Stanford University Network)的首字母缩写,跟“太阳”并没有关系。不过,由于这个缩写的蕴意不错,“太阳”就这样叫开了。

1982年,Sun公司从斯坦福大学产业园孵化而成,后来成为一家大名鼎鼎的高科技IT公司,其全称是太阳微系统公司(Sun Microsystems)。Sun的主要产品是服务器和工作站,产品极具竞争力,自然市场表现斐然。在硬件方面,他们于1985年研制出了自己的SPARC精简指令(RISC)处理器,能将服务器的性能提高很多,在软件方面,他们引以为傲的操作系统Solaris(UNIX的一个变种)比当时的Windows NT能更好地利用计算机资源,特别是在用户数急剧上升,计算机系统变得非常庞大的情况下,Solaris表现更佳。

20世纪90年代,互联网兴起。Sun公司就站在那个时代的潮流之上,所以它的服务器和工作站销量极佳,以至于这家公司在自己的广告中宣称:“我们就是.com前面的关键一点(We are the dot in the .com)”。言外之意,没有我们这画龙点睛的一点(服务器+操作系统),互联网公司就难以开起来。其得意之情,溢于言表。

Sun公司之所以敢于高抬自己,也不是吹嘘出来的,它实力的确非常雄厚,在当时足以傲视群雄。其重要的软实力,就是人才济济。在任何年代,人才都是稀缺的(不光是21世纪)。

Sun公司创始人之一史考特•麦克尼里(Scott McNealy),可谓是一代“枭雄”,他非常重视研发。在他的主持下,Sun公司先后开发了基于SPARC系列的处理器、工作站和Solaris操作系统,这些产品为Sun公司带来了丰厚的利润。

但如果我们把格局放大一些的话,从科技史的角度来看,可能Sun公司给人类带来的最有意义的产品,并不是前面提及软件和硬件,而是我们即将要介绍的重要内容——Java编程语言。

现在,让我们简单地回顾一下Java诞生的背景。在20世纪90年代,世界上的计算机多处于两种状态:要么孤零零地“宅着”——不联网,要么小范围地“宅着”——企业内部局域网互联,那时可供公众分享的资源是非常有限的。

后来,互联网蓬勃发展,不同类型的计算机系统需要连接、信息需要共享的需求就产生了,亟需一种跨越不同硬件和不同操作系统的新平台——这就是那个时代的“痛点”。任何时候,能解决时代的痛点,就会出现划时代的产品。能解决时代的痛点,就抓住了时代的发展方向。

Sun公司的创始人麦克尼里,对网络计算有着超前的洞察力。在他的带领下,Sun公司的网络视野,并未仅仅定格于计算机之间的互联,它还看得更远——计算机与非计算机彼此也是隔断的,它们也需要彼此连接!

在Sun公司,麦克尼里一直在推行“网络即计算机(The Network is the computer)”的理念。这个关于无限连通世界观念的表述,推动着Sun公司参与时代的发展。事实上,这个理念和现在火热的云计算理念,也是一脉相承的。

2016年4月28日,全球移动互联网大会(GMIC)在北京举行,当时的腾讯副总裁程武发表了《共享连接的力量》主题演讲。他提到,3年前,腾讯就提出“连接一切”。无论连接人与人、服务、设备,互联网根本上是在满足人的延伸,让网络中的个体获得更多的资源和能力,去实现更大的价值。

这样的认知,其实是梅特卡夫定律(Metcalfe's Law)的体现,其内容是:网络的价值等于网络节点数的平方,网络的价值与联网的用户数的平方成正比。梅特卡夫认为,“连接”革命后,网络价值会飙升,网络中的个体有望实现更大的价值。

回顾起来,不论是现在流行的物联网(Internet of things,IoT)概念,还是腾讯的“连接一切”理念,其实和Sun公司30多年前的理念相差无几。因此可以说,Sun公司在那个时代的视角,不可谓不“高瞻远瞩”。

Sun公司认为,如果能把计算机和非计算机(主要指的是电子消费品,如家电等)系统这两者连接起来,将会带来一场计算机革命,这是一个巨大的机遇,而连接二者的媒介自然就是网络。

无限连通的世界,令人怦然心跳。但心动不如行动。Sun公司行动的结果,就是Java语言的诞生。

后来被称为Java之父的詹姆斯•高斯林(James Gosling)说:“放眼当时的市场,两个领域的厂家各自为政,没有形成统一的网络。因此很多时候不得不重复大量的实验,但这些其实早在30年前的计算机科学中已得到解决。”

那么核心问题在于,当时的电子消费品制造者,压根并没有考虑使用网络,例如没有哪家生产商想生产一台会上网的冰箱。一流的企业,如苹果公司,是引导用户需求,而不是满足用户需求。因为有时候,用户压根也不能明确知道自己的需求。

为了解决计算机与计算机之间、计算机与非计算机之间的跨平台连接,麦克尼里决定组建一个名叫Green的、由詹姆斯•高斯林领衔的项目团队。其目的在于开发一种新的语言,并基于这种语言,研制专为下一代数字设备(如家电产品)和计算机使用的网络系统,这样就可以将通信和控制信息通过分布式网络,发给电冰箱、电视机、烤面包机等家用电器,对它们进行控制和信息交流。想一想,这不正是当下很热门的物联网思维吗?

最初Green项目的工程师们准备采用C++实现这一网络系统。但C++比较复杂,最后经过裁剪、优化和创新,1990年,高斯林的研发小组基于C++开发了一种与平台无关的新语言Oak(即Java的前身)。Oak的取名,缘于高斯林办公室外有一棵枝繁叶茂的橡树,这在硅谷是一种很常见的树。

Oak主要用于为各种家用电器编写程序,Sun公司曾以Oak语言投标一个交互式电视项目,但结果被SGI(硅图公司,1982年成立于美国)打败。由于当时智能化家电的市场需求比较低迷,Oak的市场占有率并没有当初预期的高,于是“见风使舵”的Sun公司放弃了该项计划(事实上,“见风使舵”在市场决策中并不是一个贬义词,而是一种灵活的市场策略)。就这样,Oak几近“出师未捷身先死”。其实也不能全怪Sun公司,想一想,即使在30多年后的今天,物联网、智能家居的概念虽然很火,但接地气、成气候的项目,至今也屈指可数。

恰逢这时,Mark Ardreesen(美国软件工程师,曾创办网景通讯公司)开发的Mosaic浏览器(互联网历史上第一个获普遍使用且能够显示图片的网页浏览器)和Netscape浏览器(网页浏览器,市占率曾位居主导地位)启发了Oak项目组成员,让他们预见Oak可能会在互联网应用上“大放异彩”,于是他们决定改造Oak。

及时地调整战略,把握住了时代的需求,Oak于是又迎来了自己的“柳暗花明又一村”。也就是说,计算机与非计算机之间的连接,由于太超前而失败了,但是计算机与计算机之间的连接需求(更加接近那个时代的地气)又救活了Oak。

1995年5月23日,Oak改名为Java。至此,Java正式宣告诞生。Oak之所以要改名,其实也是情非得已,因为Oak作为一个商标,已早被一家显卡制造商注册了。Oak若想发展壮大,在法律层面上,改头换面,势在必行。

其实Java本身也韵意十足,它是印度尼西亚“爪哇”(注:Java的音译)岛的英文名称,该岛因盛产咖啡而闻名。这也是Java官方商标为一杯浓郁咖啡的背后原因,而咖啡也是“爱”加班、“爱”熬夜的程序员们提神的最佳饮品之一。

当时,Java最让人着迷的特性之一,就是它的跨平台性。在过去,计算机程序在不同的操作系统平台(如UNIX、Linux和Windows等)上移植时,程序员通常不得不重新调试与编译这些程序,有时甚至需要重写。

Java的优点在于,在设计之初就秉承了“一次编写,到处运行”(“Write Once, Run Everywhere”,WORE;有时也写成“Write Once, Run Anywhere”,WORA)思想,这是Sun 公司为宣传Java语言的跨平台特性而提出的口号。

传统的程序,通过编译,可以得到与各种计算机平台紧密耦合(Coupling)的二进制代码。这种二进制代码可以在一个平台运行良好,但是换一个平台就“水土不服”,难以运行。

而Java的跨平台性,是指在一种平台下用Java语言编写的程序,在编译之后,不用经过任何更改,就能在其他平台上运行。比如,一个在Windows环境下开发出来的Java程序,在运行时,可以无缝地部署到Linux、UNIX或macOS环境之下。反之亦然,在Linux下开发的Java程序,同样可在Windows等其他平台上运行。Java是如何实现跨平台性的呢?我们可用下面的图来比拟说明。

比如说,中国人(一个平台)说了一句问候语:“你好,世界!”美国人、法国人、德国人及日本人(其他平台)都能理解中国人的“问候”。之所以能这样,这得益于英语、法语、德语及日语翻译们的翻译。

类似的,Java语言的聪明之处在于,它用一个名为Java虚拟机(Java Virtual Machine,JVM)的机制屏蔽了这些“翻译”的细节。各国人尽管尽情地表达(编写Java代码),通过编译,形成各个平台通用的字节码(Byte Code),然后JVM“看平台下菜”,在背后默默地干起了“翻译沟通”的活。正是因为有JVM的存在,Java程序员才可以做到“一次编写,到处运行”——这也是Java的精华所在。

在经过一段时间的Java学习后,读者就会知道由Java源代码编译出的二进制文件叫.class(类)文件,如果使用十六进制编辑器(如UltraEdit等)打开这个.class文件,你会发现这个文件最前面的32位将显示为“CA FE BA BE”,连接起来也就是词组“CAFE BABE ”(咖啡宝贝),如下图所示。每个Class文件的前4个字节,都是这个标识,它们被称为“魔数”,主要用来确定该文件是否为一个能被虚拟机接受的Class文件。其另外一个作用就是,让诸如James Gosling等这类具有黑客精神的编程天才尽情表演,他们就是这样,在这些不经意的地方“雁过留声,人过留名”。

Java class文件的中“咖啡宝贝”

或许,正是麦克尼里看到了Java的这一优秀特性,在Java推出以后,Sun公司便赔钱做了大量的市场推广。仅3个月后,当时的互联网娇子之一——网景(Netscape)公司,便慧眼识珠,决定采用Java。

由于Java是新一代面向对象的程序设计语言,不受操作系统限制,对网络支持很强,加之对终端用户是免费的,Java一下子就火了。很快,很多大公司诸如Oracle、Borland、SGI、IBM、AT&T和英特尔等都纷纷加入了Java阵营。当Java逐渐成为Sun的标志时,Sun公司索性就把它的股票代码“SUNW”直接改为了“JAVA”。Sun公司对Java的重视程度,可见一斑。

1997年,Sun公司推出64位处理器,同年推出Java 2,Java渐渐风生水起,市场份额也越做越大。1998年,Java 2 按适用的环境不同,被分化为4个派系(见下图):Java 2 Micro Edition(J2ME)、Java 2 Standard Edition(J2SE)、Java 2 Enterprise Edition(J2EE)以及Java Card。ME的意思是小型设备和嵌入系统,这个小小的派系,其实是Java诞生的“初心”。

(1)Java SE(Standard Edition,标准版):支持面向桌面级应用(如Windows下的应用程序)的Java平台,提供了完整的Java核心API,这个版本2005年以前称为J2SE。

(2)Java EE(Enterprise Edition,企业版):以Java SE为基础向外延伸,增加了许多支持企业内部使用的扩充类,同时支持使用多层架构的企业应用(如ERP——企业资源计划系统、CRM——客户关系管理系统的应用)的Java平台。除了提供Java SE API外,还对其做了大量的扩充并提供了相关的部署支持。这个版本2005年以前称为J2EE。

(3)Java ME(Micro Edition,微型版):Java ME同样以Java SE为基础,但相对精简。它所支持的只有核心类的子集合,它支持Java程序运行在移动终端(手机、PDA——掌上电脑)上的平台,加入了针对移动终端的支持。这个版本2005年以前称为J2ME。Java的微型版主要是进行嵌入式开发,目前渐渐被Android开发所替代。

(4)Java Card(智能卡版):由于服务对象定位更加明确化,Java Card版本比Java ME(微型版)更加精简。它支持一些Java小程序(Applets)运行在小内存设备(如容量小于64KB的智能卡)的平台上。

但是,Java的技术平台不管如何划分,都是以Java SE为核心的,所以掌握Java SE十分重要,这也是本书的主要讲解范围。如果想进行Java EE的开发,Java SE是其中必要的组成部分,这也是为什么在学习Java EE 之前要求读者一定要有扎实的Java SE基础。

当时专为连接智能家电而开发的Java,不曾想“有心栽花花不开,无心插柳柳成荫”,在家电市场毫无起色,却因其“一次编程,到处运行”的跨平台特性,赶上了互联网的高速发展时机,在企业级市场上大放异彩。

Java ME一度在翻盖手机应用上得到极大推广,成为当时的标配。但后来,随着安卓(Android)的兴起,也慢慢中落。Java之父高斯林后来也说,“ME已经做得足够好了,在当时是最强大的智能电话开发平台之一。不过现在渐渐被遗忘,因为Android太耀眼了。”

有起有落,螺旋上升,是事物发展的常态。Java的发展历程,也不例外。Oracle Java平台开发副总裁、OpenJDK管理委员会核心成员Georges Saab曾经这样说道:“在20世纪90年代,大多数开发者都把精力投入到桌面应用的编写之上。到了2000年,Pet.com(一家美国宠物网站)的成功吸引了大批的跟风者。业界又把焦点从桌面转移到了HTML应用。随着智能电话和平板电脑的到来,基于触摸屏的移动应用又站在了潮流前端。所以对于下一个流行趋势是很难把握的,这涉及天时、地利、人和。”

然而,Java对于Sun来说,是“华而不实”的资产。因为,除了带来日渐高涨的声誉外,Java并没有直接给Sun带来与其声誉对等的回报。用华尔街的话来说,Java是赔钱赚吆喝。吆喝Java是赚到了,但赚钱盈利才是生存之道。

现在具备互联网思维的公司都知道,“免费”的目的是不免费,不免费的对象要发生转移,其实是要让“羊毛出在猪身上”,最后“让狗来买单”。但那是30多年前,Sun公司还没有很强的互联网赚钱思维,它到“死”(直到被Oracle收购)都没有想明白,为什么抱着一个金饭碗,却要不到饭。

事实上,除了生产处理器、服务器和操作系统之外,Sun还开发了办公软件OpenOffice。1995年到2000年,是Sun公司高速增长的时期。这期间互联网飞速发展,它曾经和Oracle共同提出了网络计算机(Network computer,NC)的概念 ,主要就是指没有硬盘的计算机,其实也就是低价台式机,是瘦客户机(或称无盘工作站)。

但在2000年之后,网络泡沫破碎,绝大多数的“.com”公司都关门了,苟延残喘活下来的公司,也急刹车般地停止了扩张采购。服务器市场一下子低迷起来,Sun公司这个当初意气风发誓言成为互联网公司的“关键的一点的”公司,已经不再关键了。老的盈利点(服务器市场)不盈利了,新的盈利点(如Java市场)又找不到,Sun公司突然陷入风雨飘摇的境地。

有道是“月满则亏,水满则溢”。Sun公司从1982年成立,到2000年达到顶峰,用了将近20年,而走下坡路只用了仅仅一年。这种断崖式的毁灭,足以让今天的创业者引以为戒。

2008年爆发的金融危机,让持续亏损的Sun公司,更加雪上加霜。到了2009年,由于业绩不佳,Sun公司的市值又比2007年下降了一半,终于跌到了对它期盼已久的Oracle公司可以买得起的价格。2009年4月,这个市值曾经超过2000亿美元的Sun公司,在最低潮的时候,以74亿美元的便宜价被Oracle收购,这个价格仅仅为Sun公司顶峰市值的3%。作为Sun公司的核心资产之一的Java,自然也换了新东家——Oracle。

按照Oracle老板拉里•埃里森(Larry Ellison)的话讲,Sun公司有很好的技术,也有很好的工程师,但它们的管理层实在是太烂了(Astonishingly bad managers),而且做了很多错误的决策,这样才导致Oracle能以很便宜的价格捡了漏。

2015年5月23日,在北京中关村3W咖啡屋,作者参加了由Oracle(中国)举办的Java诞生20周年庆典。在概括Java成功的原因时,Oracle开发人员关系团队总监Sharat Chander总结了三点:社区排在第一,这是Java成功的基础;Java技术的不断进步排在第二;而排在第三位的,才是Oracle对Java的管理。

在收购Sun后,Oracle一方面继续积极推动Java社区发展,另一方面及时将社区成果反馈、集成到新版本产品中。Oracle承诺,大型版本的更新每2年一次发布,小型版本的更新每6个月一次。

在版本推新上,Oracle极大尊重Java社区的意见,Java 7就是在与社区深入交流的基础上推出的,尽管当时并非推出Java 7的最好时机,其后续功能在Java 8里进行了补全。

对于Java的发展,的确不能忽视Java社区的重要性。Oracle认为自己并非Java的管家,他们是在与Java社区一起来管理Java,而Java社区也被誉为Java成功的基础。对此Sharat Chander介绍,Java社区拥有314个Java用户组、900多万Java开发人员、超过150个Java Champion(技术领袖)。

2009年12月,企业版的升级版Java EE 6发布。2011年7月28日,Java SE 7发布。

CPU多核(many-core)时代的兴起,让程序员们纷纷探索起怎么编写并行代码。一番折腾后,大家发现很多编程的好思想,都来自一个叫函数式编程的程序范式。这个曾束之高阁的好理念又被人重拾起来。2014年3月19日,Oracle公司发布Java 8.0正式版,提供了大家望眼欲穿的Lambda。

当然,Java也不是没有缺点的。曾经,有人采访C++之父Bjarne Stroustrup,问他如何看待Java的简洁,他的回答却是,时间不够长。大师之见,果然深邃。Java之美,早已不是简洁,而是开发高效。其为之付出的代价是,各种类库、框架的异常复杂而臃肿。通常,即使一个专业级的Java程序员,也需耗费不菲的(包括时间上或金钱上的)学习成本。但这符合事物的发展规律,就像我们不能期望一个横纲级的相扑运动员力大无穷,却又期望他身轻如燕。

这就是我们的Java!它不甚完美,却非常能干!

Java作为Sun公司推出的新一代面向对象程序设计语言,特别适于互联网应用程序的开发,但它的平台无关性直接威胁到了Wintel(即微软的Windows操作系统与Intel CPU所组成的个人计算机)的垄断地位,这表现在以下几个方面。

信息产业的许多国际大公司购买了Java许可证,这些公司包括IBM、Apple、DEC、Adobe、Silicon Graphics、HP、TOSHIBA以及Microsoft等。这一点说明,Java已得到了业界的高度认可,众多的软件开发商开始支持Java软件产品,例如Inprise公司的JBuilder、Oracle公司自己维护的Java开发环境JDK与JRE。

Intranet正在成为企业信息系统最佳的解决方案,而其中Java将发挥不可替代的作用。Intranet的目的是将Internet用于企业内部的信息类型,它的优点是便宜、易于使用和管理。用户不管使用何种类型的机器和操作系统,界面都是统一的Internet浏览器,而数据库、Web页面、Applet、 Servlet、JSP等则存储在Web服务器上,无论是开发人员、管理人员还是普通用户,都可以受益于该解决方案。

Java技术的开放性、安全性和庞大的社会生态链以及其跨平台性,使得Java技术成为智能手机软件平台的事实性标准。在未来发展方向上,Java在Web、移动设备以及云计算等方面的应用前景也非常广阔。虽然面对来自网络的类似于Ruby on Rails这类编程平台的挑战,但Java依然还是事实上的企业Web开发标准。随着云计算(Cloud Computing)、移动互联网、大数据(Big Data)的扩张,更多的企业考虑将其应用部署在Java平台上,那么无论是本地主机,还是公共云,Java都是目前最合适的选择之一。Java应用领域之广,也势必促使Java开发者的就业市场呈现欣欣向荣的发展态势。

学习Java不仅是学习一门语言,更多的是学习一种思想,一种开发模式。对于从事软件行业的工作人员,掌握了Java语言,可以让自己日后的事业发展得更加顺利。Java语言的内容相对完整,因此Java开发人员可以轻松转入到手机开发、.NET、PHP等语言的开发上,以后也可以更快地跨入到项目经理的行列之中。

目前,Java人才的需求量旺盛,并且企业提供的薪水也不菲,通常来说,具有3年以上开发经验的工程师,年薪10万元以上是一个很正常的薪酬水平。但IT企业却很难招聘到合格的Java人才。所以读者朋友如果想让自己成为合格的受企业欢迎的Java程序员,需要做好自己的职业发展规划。

首先,要定位自己的目标,然后再有的放矢地进行自我提升。对于Java工程师来说,大致可以从3个大方向来规划自己的职业蓝图。

(1)继续走技术工作之路

从技术发展方向来看,Java工程师可以由最初的初级软件工程师(即程序员)逐渐晋升至中级软件工程师(高级程序员)、高级软件工程师及架构师等。走这条路,通常可进入电信、银行、保险等相关软件开发公司从事软件设计和开发工作。在信息时代,越来越多的公司重视信息化,而信息化落实起来离不开软件开发,而软件开发中Java当属挑大梁者。如果选择这个方向,程序员要脚踏实地,一步一个脚印地练好Java的基本功。对于初(中)级程序员来说首先掌握Java的基本语法(如类与对象、构造方法、引用传递、内部类、异常、包、Java常用类库、Java IO及Java类集等)。如果读者定位高级程序员以上的目标,那么目标的实现主要依赖三点:一是前期扎实的Java基础,二是后期对软件开发的持续性热爱,三是靠程序员个人的领悟。

(2)定位成为技术类管理人员

此类管理人员通常包括产品研发经理、技术经理、项目经理及技术总监职位等。如果选择管理方向,首先要有一定的“基层”经验,即你至少要有几年的Java开发经验。否则,即使偶然因素让你“擢升”至管理层,那么也会因为“外行指导内行”而饱受诟病。所以如果定位管理人员,那么成功的第一步就是至少成为一名中级以上的Java程序员,前面所言的Java基础也是需要掌握的。想成为技术类管理人员,还要深谙Java设计模式及软件工程的思想,从而能把控软件开发的全局。一个好的技术类管理人员,不仅要自身具有很强的技术管理能力,同时也要有很强的技术体系建设和团队管理的能力,对自己所处的行业技术发展趋势和管理现状具有准确的判断。统筹全局、集各个层次的技术人员之合力,高质量完成软件项目,是成为技术类管理人员的挑战。

(3)在其他领域成就大业

Java软件开发发展前景好,运用范围也广,具备Java基础的工程师,还可以尝试着在其他领域成就一番大业。例如,Java工程师可以从事JSP网站开发、移动领域应用开发、电子商务开发等工作。如果从事Web开发,那么在此之前一定要熟练掌握HTML、JavaScript、XML。Web开发的核心就是进行数据库的操作,先从JSP(Java Server Pages)学习,并可以使用JSP + JDBC(Java Data Base Connectivity,Java数据库连接)或者是JSP + ADO(ActiveX Data Objects)完成操作。JSP技术是以Java语言作为脚本语言的。之后再学习MVC设计模式,它是软件工程中的一种软件架构模式,把软件系统分为3个基本部分:模型(Model)、视图(View)和控制器(Controller)。掌握了MVC设计,读者也就可以轻松地掌握AJAX(Asynchronous JavaScript and XML)和Struts技术。AJAX 是在不重新加载整个页面的情况下与服务器交换数据并更新部分网页的手段。Struts 是Apache软件基金会(ASF)赞助的一个开源项目。使用Struts机制可以帮助开发人员减少在运用MVC设计模型来开发Web应用的时间。

之后,再学习Hibernate和Spring等轻量级实体层开发方法等。Hibernate是一个开放源代码的Java语言下的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可便利地使用对象编程思维来操纵数据库。Spring Framework是一个开源的Java/Java EE全功能栈,其应用程序框架内包含了一些基于反射机制写的包,有了它以后程序员便可以将类的实例化写到一个配置文件里,由相应的Spring包负责实例化。

以上3条与Java相关的职业发展规划之路,都以夯实Java基础为根本。每一条路要走到顶层,都需要重视基础,一步一个脚印,做事由浅入深,由简入繁,循序渐进。《礼记•中庸》有言:“君子之道,辟如行远必自迩,辟如登高必自卑。”这句话告诉我们,君子行事,就像走远路一样,必定要从近处开始;就像登高山一样,必定要从低处起步。

本书主要面向初、中级水平的读者。针对本书,Java学习可以大致分为3个阶段。

对于读者来说,Java学习的路线在整体上需遵循:初级阶段→中级阶段→高级阶段。循序渐进地学习(见下图),不建议读者一开始就“越级”学习,需知“欲速则不达”。在这3个阶段各自内部的知识点,没有必然的先后次序,读者可根据自己的实际情况“有的放矢”地学习。不管处于哪个学习阶段,读者都要重视Java的实战练习。等学习到高级阶段后,还要用一些项目实训来提升自己。

成为一名Java高手,可能需要经历多年的时间。一些读者担心,自己可能等不到成为高手那一天,就无力开发Java了。其实,Java相关的开发行业也如陈年美酒,愈陈愈香。想一想,前面提到Java的核心设计者James Gosling,发髯皆白,却依然意气风发,时常给比他年轻很多的软件开发精英们讲解Java发展之道,那种指点江山的气势,是何等的豪迈!Java软件开发行业职业寿命很长,能提供给从业人员更广阔的发展方向。如果想在Java开发相关的领域有所建树,多一份持久的坚持是必需的。

从一个Java的初学者,升级为一个编程高手,从来都没有捷径。其必经的一个成长路线正如下图所示:编写代码→犯错(发现问题)→纠错(解决问题)→自我提升→编写代码→犯错(发现问题)→纠错(解决问题)→自我提升……积累了一定的感性认识后,才会有质的突变,提升至新的境界。总之,想成为一个高水平的Java程序员,一定要多动手练习,多思考。

2000多年前,孔夫子就曾说过,“学而时习之,不亦说乎?”杨伯峻先生在《论语译注》中对这句话有精辟的注解:“学了,然后(按一定的时间)去实习它,不也高兴吗?”对于Java的学习,也应是这样,仅仅懂得一堆Java语法,毫无意义,我们必须亲自动手实践它。

最后需要说明的是,Java高手绝对没有什么捷径可走,也绝不是一本书就能成就的,需要学习者不断地自我迭代,在理论上提升自己(如在读完本书后,还可以接着读读《编程之美》《设计模式之禅》《企业应用构架模式》《97 things software architec should know》等),并在实战中反复地练习。只要这样,才能让自己操作代码的“动作”收放自如,才能让自己的“招式”炉火纯青。

各位Java爱好者,想在这个计算为王的大千世界放马驰骋吗?赶快动手吧(Just do IT)!


第 1 章  小荷才露尖尖角——Java开发环境搭建

第 2 章 初识庐山真面目——Java 程序要素概览

第 3 章 九层之台,起于垒土——Java 编程基础

第 4 章 基础编程元素——运算符、表达式、语句与流程控制

第 5 章 常用的数据结构——数组与枚举

第 6 章  面向对象设计的核心——类和对象

第 7 章  重复调用的代码块——方法


通过上一章的阅读,相信读者对Java语言已经有了大概的了解,本章更进一步地介绍如何在Windows操作系统中下载与安装JDK,并详细描述在Windows操作系统下开发环境的配置。最后介绍如何编译和运行第1个Java程序,再简要介绍在Eclipse环境下如何开发Java程序。

本章要点(已掌握的在方框中打钩)

学习Java的第一步,自然就是要搭建Java开发环境(Java Development Kit,JDK),在操作系统(如Windows、Linux等)下,JDK是搭建Java最基本的开发环境之一,目前由Oracle公司维护开发并免费提供。

JDK由一个处于操作系统层之上的开发环境和运行环境组成,如下图所示。JDK除了包括编译(javac)、解释(java)、打包(jar)等工具,还包括开发工具及开发工具的应用程序接口等。当Java程序编译完毕后,如果想运行,还需要Java运行环境(Java Runtime Environment,JRE)。

JRE是运行Java程序所必需的环境的集合,包含JVM标准实现及Java核心类库。如果仅仅想运行Java程序,安装JRE就够了。也就是说,JRE是面向Java程序的使用者的。但如果想进一步开发Java程序,那就需要安装JDK,它是面向Java程序的开发者的。Java程序的开发者自然也是Java程序的应用者。从下图也容易看出,JDK包含JRE。

由上图可以看出,Java程序开发的第一步就是编写Java语言的源代码。而编写源代码的工具,可以是任何文本编辑器,如Windows 操作系统下的记事本、Linux操作系统下的Vim等。这里推荐读者使用对编程语言支持较好的编辑器,如Notepad++、UltraEdit、Editplus等,这类代码编辑器通常有较好的语法高亮等特性,特别适合开发程序代码。

Java源文件编写完毕后,就可以在命令行下,通过javac命令将Java源程序编译成字节码(Byte Code,Java虚拟机执行的一种二进制指令格式文件),然后通过java命令,来解释执行编译好的Java类文件(文件扩展名为.class)。但如果想正确使用javac和java等命令,用户必须自己搭建Java开发环境。在后续章节,我们将详细介绍相关的配置步骤。

为了提高Java的开发效率,目前在市面上也涌现了很多优秀的Java集成开发环境(Integrated Development Environment, IDE),如NetBeans(由Sun公司开发的老牌IDE)、IntelliJIDEA(由捷克软件公司JetBrains开发的智能IDE,需要付费使用)及Eclipse(免费开源的知名IDE)等。IDE在JDK的基础上,为程序提供了很多辅助功能的支持,极大方便了程序的开发。在本章最后部分,我们将简要地介绍最流行的 IDE之一——Eclipse的使用。

Oracle公司提供多种操作系统下的不同版本的JDK。本节主要介绍在Windows操作系统下安装JDK的过程。

➊ 在浏览器地址栏中输入oracle官方网址,打开Oracle官方网站,如下图所示,映入我们眼帘的是Java 10的下载界面。

但需要提醒读者的是,对于软件开发而言,过度“最新”并非好事,如果你不是有特殊需求,Java 8足够用了。为什么说过度“最新”并非好事呢?这是因为Java 9和Java 10虽然有很多好的新特性,但它依附的生态还没有建立起来。比如说,如果你想学习基于Hadoop的大数据编程,很可能Hadoop的最新版还是由Java 8编译而成,你用Java 10编译出来的程序,难以在Hadoop上运行。所以对于学习编程软件,特别是初学者,我们的建议是保守的,暂时还采用业界广泛使用的Java来编程。事实上,Java 8、 Java 7甚至Java 6,仍在企业界有着广泛应用。作为初级用户,实在没有必要跟风,一定要下载最新的Java版本,因为很多新特性,初学者根本没有机会用到。

或许Oracle公司也知道Java 9和Java 10的更新幅度太大,而Java 8依然是业界开发的主流,于是,在Java 10 同一个下载网页的下方,Oracle给出了Java 8的下载界面,如下图所示。

单击JDK的下载(DOWNLOAD)按钮,出现如下图的下载界面。本书使用的版本是Java SE Development Kit 8u172。

➋ 如前面的章节介绍, Java技术体系可以分为4个平台:Java SE、Java EE、Java ME和Java Card。后面3个版本都是以Java SE为核心的,所以掌握Java SE十分重要,这也是本书的主要讲解范围。

在Java 的发展过程中,由于Sun公司(已被Oracle公司收购)的市场推广部门,举棋不定,导致其版本编号一定的“混乱”,容易让用户产生某种程度的困扰。比如,有的时候读者(特别是初学者)可能在阅读一些Java书籍时,发现版本为Java 2,如J2EE。有时又发现一些书籍说自己代码编译的平台是Java 6或Java 7,那Java 3 或Java 4 去哪里了?因此这里有必要解释一下。下面简要地介绍一下Java版本号的命名规则。

在Java 1.1之前,其命名方式和传统的方式一样。但当Java 1.1升级到Java1.2时,Sun公司的Java市场推广部门觉得, Java的内涵发生很大的变化,应给予Java一个“新”的名称——Java 2,而它内部的发行编号仍是Java 1.2。当Java内部发行版从1.2过渡到1.3和1.4时,Sun公司对外宣称的版本依然是Java 2。Sun公司从来没有发布过Java 3和Java 4。从Java内部发行版的1.5开始,Java的市场推广部门又觉得Java已经变化很大,需要给予一个“更新”的称呼,以便在市场中“博得眼球”,于是Java 1.5 直接对外宣称Java 5,依此类推,Java 1.6 对外宣称Java 6,而目前我们即将学习的Java 8,其内部版本是Java 1.8,如下表所示。

Java内部发行版本

发布时间

Java对外推广版本号

JDK 1.0

1996年1月

Java 1.0

JDK 1.1

1997年2月

Java 1.1

JDK 1.2

1998年12月

Java 2

JDK 1.3

2000年5月

JDK 1.4

2002年2月

JDK 1.5

2004年9月

J2SE 5.0

JDK 1.6

2006年12月

Java SE 6

JDK 1.7

2011年7月

Java SE 7

JDK 1.8

2014年 3月

Java SE 8

JDK 1.9

2017年9月

Java SE 9

JDK 2.0

2018年3月

Java SE 10

为了避免混淆,Oracle公司宣布改变Java版本号命名方式,自JDK 5.0起,Java以两种方式发布更新: (1)Limited Update(有限更新)模式,其包含新功能和非安全修正;(2)Critical Patch Updates(CPUs,重要补丁更新)只包含安全的重要修正。举例来说, Java SE 8u172 的解释如下图所示。

➌ 因为Oracle的Java实施的是“许可证(License)”,所以需要选择“Accept License Agreement(接受许可证协议)”,然后选择与自己的操作系统匹配的SDK版本,如下图所示。

读者可以根据自己的操作系统类型以及位数(32位还是64位),下载所对应的Java JDK。Java 8的JDK软件包通常在100MB以上,下载需要一定的时间。下面介绍JDK在Windows操作系统下的详细安装流程。

在下载过程中,有个小问题需要读者注意:如何识别自己所使用的Windows操作系统版本号。在Windows 7操作系统下,在桌面上右键单击“计算机”图标,选择“属性”命令,在弹出的“属性”窗口中(见下图),“系统类型”处即可显示读者所用的操作系统版本信息。

本书使用的Java 8版本号是Java SE 8u172,但编程语言趋势是一直向上升级,只要大版本“8”不变,“u”后面的小版本号有所变化,都属于Java 8范畴,基本上不会影响普通用户的学习和工作。

安装环境如下。

➊开始安装。

下载完成后,就可以安装Java JDK了。双击“jdk-8u172-windows-x64.exe”,弹出欢迎界面,如下图(左)所示。

➋ 选择安装路径,确定是否安装公共JRE。

公共JRE提供了一个Java运行环境。JDK默认自带了JRE。选择不安装公共JRE,并不会对Java运行造成影响。单击“下一步”按钮,正在安装JDK,如下图(右)所示。

![nnnn.jpg{45%}](/api/storage/getbykey/original?key=1903312fcf9aafd5760c)   ![uuuu.jpg{45%}](/api/storage/getbykey/original?key=190367c83524b484ec6d)

➌ JDK安装完成。

➍ 查看JDK安装目录(C:\Program Files\Java\jdk1.8.0_172)。

本书主要以Windows 7操作系统为平台来讲解Java。而在开发Java程序之前,通常需要先在Windows操作系统中配置好有关Java的系统环境变量(Environment Variable)。

在介绍环境变量的含义之前,我们先举一个形象的例子,给读者一个感性的认识。比如我们喊一句:“张三,你妈妈喊你回家吃饭!”可是“张三”为何人?他在哪里呢?对于我们人来说,认不认识“张三”都能给出一定的响应:如认识他,可能就会给他带个话;而不认识他,也可能帮忙吆喝一声“张三,快点回家吧!”

然而,对于操作系统来说,假设“张三”代表的是一条命令,它不认识“张三”是谁,也不知道“它”来自何处,它会“毫无情趣”地说,不认识“张三”——not recognized as an internal or external command(错误的内部或外部命令),然后拒绝继续服务。

为了让操作系统“认识”张三,我们必须给操作系统有关张三的准确信息,如“XXX省YYY县ZZZ乡QQQ村张三”。但其他问题又来了,如果“张三”所代表的命令是用户经常用到的,每次使用“张三”,用户都在终端敲入“XXX省YYY县ZZZ乡QQQ村张三”,这是非常繁琐的,能不能有简略的办法呢?

聪明的系统设计人员想出了一个简易的策略——环境变量。把“XXX省YYY县ZZZ乡QQQ村”设置为常见的“环境”,当用户在终端仅仅敲入“张三”时,系统自动检测环境变量集合里有没有“张三”这个人,如果在“XXX省YYY县ZZZ乡QQQ村”找到了,就自动替换为一个精确的地址“XXX省YYY县ZZZ乡QQQ村张三”,然后继续为用户服务。如果整个环境变量集合里都没有“张三”,那么再拒绝服务,如下图所示。

操作系统里没有上/下行政级别的概念,但却有父/子文件夹的概念,二者有“异曲同工”之处。对“XXX省YYY县ZZZ乡QQQ村”这条定位“路径”,操作可以用“/”来区分不同级别文件夹,即“XXX省/YYY县/ZZZ乡/QQQ村”,而“张三”就像这个文件夹下的可执行文件。

下面我们给出环境变量的正式定义。

环境变量是指在操作系统指定的运行环境中的一组参数,它包含一个或者多个应用程序使用的信息。环境变量一般是多值的,即一个环境变量可以有多个值,各个值之间以英文状态下的分号“;”(即半角的分号)分隔开来。

对于Windows等操作系统来说,一般有一个系统级的环境变量“Path”。当用户要求操作系统运行一个应用程序,却没有指定应用程序的完整路径时,操作系统首先会在当前路径下寻找该应用程序,如果找不到,便会到环境变量“Path”指定的路径下寻找。若找到该应用程序则执行它,否则会给出错误提示。用户可以通过设置环境变量来指定自己想要运行的程序所在的位置。

例如,编译Java程序需要用到javac命令,其中javac中的最后一个字母“c”,就来自于英文的“编译器”(compiler)。而运行Java程序(.class),则需要java命令来解释执行。事实上,这两个命令都不是Windows操作系统自带的命令,所以用户需要通过设置环境变量(JDK的安装位置)来指定这两个命令的位置。设置完成后,就可以在任意目录下使用这两个命令,而无需每次都输入这两个命令所在的全路径(如C:\Program Files\Java\jdk1.8.0_172)。javac和java等命令都放在JDK安装目录的bin目录下。基于类似于环境变量“Path”相同的理由,我们需要掌握JDK中比较重要的3个环境变量,下面一一给予介绍。

对于环境变量中相关变量的深刻理解极为重要,特别是ClassPath,在日后的Java学习开发过程中会发现,很多问题的出现都与ClassPath环境变量有关。在学习如何配置这些环境变量之前,很有必要深刻理解下面3个环境变量代表的含义。

(1)JAVA_HOME:顾名思义,“JAVA的家”,该变量是指安装Java的JDK路径,它告知操作系统在哪里可以找到JDK。

(2)Path:前面已经有所介绍。该变量是告诉操作系统可执行文件的搜索路径,即可以在哪些路径下找到要执行的可执行文件,请注意它仅对可执行文件有效。当运行一个可执行文件时,用户仅仅给出该文件名,操作系统首先会在当前目录下搜索该文件,若找到则运行它;若找不到,则根据Path变量所设置的路径,逐条到Path目录中,搜索该可执行文件所在的目录(这些目录之间,是以分号“;”隔开的)。

(3)ClassPath:该变量是用来告诉Java解释器(即java命令)在哪些目录下可找到所需要执行的class文件(即javac编译生成的字节码文件)。

对于初学者来说,Java的运行环境的配置比较麻烦,请读者按照以下介绍实施配置。

01 JAVA_HOME的配置

下面我们详细说明Java环境变量的配置流程。

➊ 在桌面中右键单击“计算机”,在弹出的快捷菜单中选择“属性”选项,如下图所示。

➋ 在弹出的界面左上方,选择“高级系统设置”选项,如下图所示。

➌ 弹出“系统属性”对话框,然后单击“高级→环境变量”,如下图所示。

➍ 在“环境变量”对话框中,单击“系统变量”下的“新建”按钮,显示如下图所示。

➎ 在“新建系统变量”对话框中设置变量名为“JAVA_HOME”,变量值为“C:\Program Files\Java\jdk1.8.0_172”。需要读者特别注意的是,这个路径的具体值根据读者安装JDK的路径而定,读者把Java安装在哪里,就把对应的安装路径放置于环境变量之内,不可拘泥于本书演示的这个路径值。然后,单击“确定”按钮,如下图所示。

注意

 

假设JDK安装在“C:\Program Files\Java\jdk1.8.0_ 112”,在设置完毕对应的环境变量JAVA_HOME后,以后再要用到这个变量时,需用两个%将其包括起来。例如,要设置另外一个环境变量值为“C:\Program Files\Java\jdk1.8.0_112\bin”(javac、javadoc及java等命令在该目录下),那么我们可以简单地用“%JAVA_HOME%\bin”代替。

02  Path的配置

➊ 选中系统环境变量中的Path,单击“编辑”按钮,如下图所示。

➋ 在弹出的“编辑系统变量”对话框的“变量值”文本框中,在文本框的末尾添加“;%JAVA_HOME%\bin”,特别注意不要忘了前面的分号“;”,然后单击“确定”按钮,返回“系统属性”对话框,如下图所示。这里的“%JAVA_HOME%”就是指代前面设置的“C:\Program Files\Java\jdk1.8.0_172”。这样的设定是为了避免每次引用这个路径都输入很长的字符串。如果不怕麻烦,“;%JAVA_HOME%\bin”完全可以用全路径“;C:\Program Files\Java\jdk1.8.0_172\bin”代替。这个路径务必设置正确,因为诸如Java语言的编译命令javac和解释命令java等都是在这个路径下,一旦设置失败,这些命令将无法找到。

提示

 

当Path有多个变量值时,一定要用半角(即英文输入法)下的“;”将多个变量值区分开。初学者很容易犯错的地方:① 忘记在上一个Path路径值前面添加分号“;”;② 没有切换至英文输入法,误输入中文的分号“;”(即全角的分号);中英文输入法下的分号,看似相同,实则“大相径庭”,英文分号是1个字节大小,而中文的分号是2个字节大小。

➌ 在“系统属性”对话框中单击“确定”按钮,完成环境变量的设置,如下图所示。

请注意,要检测环境变量是否配置成功,可以进入命令行模式,在任意目录下输入“javac”命令,如果能输出javac的用法提示,则说明配置成功,如下图所示。

进入命令行模式的方法是,单击Windows 7的开始菜单,在搜索框中输入“CMD”命令,然后按“Enter”键即可。

03 ClassPath的指定

对初学者来说,ClassPath的设定有一定的难度,容易配错。如果说JAVA_HOME指定的是java命令的运行路径的话,那么ClassPath指定的就是java加载类的路径。只有类在ClassPath中,java命令才能找到它,并解释它。

在Java中,我们可以使用“set classpath”命令来临时指定Java类的执行路径。下面通过一个例子来了解一下ClassPath的作用,假设这里的“Hello.class”类位于“C:\”目录下。

在“D:\”目录下的命令行窗口执行下面的指令。

set classpath=c:

之后在“D:\”目录下执行“java Hello”命令,如下图所示。

从上图所示的输出结果可以发现,虽然在“D:\”目录中并没有“Hello.class”文件,但是也可以用“java Hello”执行“Hello.class”文件。之所以会有这种结果,就是因为在“D:\”目录中使用了“set classpath”命令,它把类的查找路径指向了“C:\”目录。因此在运行时,Java会自动从ClassPath 中查找这个Hello类文件,而ClassPath中包括了路径“C:\”,所以运行成功。

提示

 

可能有些读者在按照上述的方法操作时,发现并不好用。这里要告诉读者的是,在设置ClassPath时,最好也将ClassPath指向当前目录,即所有的class文件都是从当前文件夹中开始查找“set classpath=.”。在Windows及Linux等操作系统下,一个点“.”代表当前目录,两个点“..”代表上一级目录。读者可以在命令行模式下,分别用“cd .”和“cd ..”感受一下。

但是这样的操作行命令操作模式,实际上又会造成一种局限:这样设置的ClassPath,只对当前命令行窗口有效。一旦命令行窗口重新开启或系统重启,原先ClassPath中设置的变量值都丢失了。如果想“一劳永逸”,可以将ClassPath设置为环境变量。

➊ 参照JAVA_HOME的配置,在“环境变量”对话框中,单击“系统变量”下的“新建”按钮,如下图所示。新建一个环境变量,变量名为“ClassPath”,变量值为“.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar”。注意不要忽略了前面的“.”,这里的小点“.”,代表的是当前路径,既然是路径,自然也需要用分号“;”隔开。JDK的库所在包即tools.jar,也要设置进ClassPath中。

提示

 

在Windows操作系统下,一般只要设置好JAVA_HOME就可以正常运行Java程序。默认的ClassPath是当前路径(即一个点 “.”)。有些第三方的开发包,需要使用到环境变量ClassPath,只有这样才能使用JDK的各种工具。但是最好养成一个良好的习惯,设置好ClassPath。此外,需要注意的是,在Windows操作系统下不区分大小写,ClassPath和CLASSPATH是等同的,读者可根据自己的习惯,选择合适的大小写。而在Linux/UNIX/macOS操作系统下,大小写是完全区分开的。

➋ 在按照步骤➊设置后,如果在Java类(即.class)文件所存储的当前路径下,那么用“java类名”方式解释执行用户类文件,这是没有问题的。但是如果用户更换了路径,现在的“当前路径”并没有包括.class文件的所在文件夹,那么“java”就无法找到这个类文件。

这时,即使在命令行下给出.class文件所在的全路径,java依然会出错,这会让初学者很困惑。下面具体说明,假设Java文件Hello.java存在于“D:\src\chap01\”路径下,由于JAVA_HOME和Path环境变量正确,用户可以正确编译、运行,使用javac和java命令无误,如下图所示。

但是如果用户切换了路径,比如使用“cd”命令切换至“D:\src\”,再次用Java运行Hello类文件,就会得到错误信息“Error: Could not find or load main class Hello”,如下图所示。这是因为Java在ClassPath里找不到Hello.class,因为现在的这个当前路径(也就是那个“.”代表的含义)已经变更为“D:\src\”,而“D:\src\”路径下确实没有Hello.class这个文件。

所以,如果想在任意路径下执行用户的类文件,就必须把用户自己编译出的类文件所在路径(这里指的是“D:\src\chap01”),也加入到ClassPath中,并用分号“;”与前一个变量隔开,如下图所示。

➌ 参照环境变量Path的配置,将环境变量ClassPath添加到Path的最后,如下图所示。其中,ClassPath是环境变量,在另外一个地方作为变量使用时,要用两个%将该变量前后包括起来——%ClassPath%。

需要注意的是,如果用户原来的命令行窗口一直开启着,则需要关闭再重启命令行窗口,这是因为只有重启窗口才能更新环境变量。之后,就可以在任意路径下执行用户自己的类文件,如下图所示。

“Hello World”基本上是所有编程语言的经典起始程序。在编程史上,它占据着无法撼动的历史地位。将“Hello”和“World”一起使用的程序,最早出现于1972年由贝尔实验室成员Brian Kernighan撰写的内部技术文件《Introduction to the Language B》。这里,我们也要向“经典”致敬,就让我们第一个Java小程序也是“Hello World”吧,从中感受一下Java语言的基本形式。

范例 1-1 编写HelloWorld.java程序

01 public class HelloWorld
02 {
03  // main是程序的起点,所有程序由此开始运行
04  public static void main(String args[])
05  {
06    // 下面语句表示向屏幕上打印输出“Hello World”字符串
07    System.out.println(“Hello World”); 
08  }
09 }

将上面的程序保存为“HelloWorld.java”文件。行号是为了让程序便于被读者(或程序员)理解而人为添加的,真正Java源代码是不需要这些行号的。在命令行中输入“javac HelloWorld.java”,没有错误后输入“java HelloWorld”。运行结果如下图所示,显示“Hello World”。

Java程序运行的流程可用下图来说明:所有的Java源代码(以.java为扩展名),通过Java编译器javac编译成字节码,也就是以.class为扩展名的类文件。然后利用java命令将对应的字节码,通过Java虚拟机(JVM)解释为特定操作系统(如Windows、Linux等)能理解的机器码,最终Java程序得以执行。

这里需要注意的是,此处的java命令在Windows操作系统下,不区分大小写,诸如java 和JavA都是等同的。而在诸如Linux、macOS等类UNIX(UNIX-like)操作系统下,由于区分大小写,javac和java等所有命令的字符都必须小写。

对于上面的程序,如果暂时不明白也没有关系,读者只要将程序在任意纯文本编辑器(如Windows操作系统下的记事本、Notepad++等,Linux操作系统下的vim等,macOS操作系统下的TextMate等均可)里敲出来,然后按照步骤编译、执行就可以了。

下面,让我们来解读一下这个Java小程序,让读者对Java程序有个初步的认知。更为详细的知识点读者可以参考后续相关章节进行学习。

第01行,public 是一个关键字,用于声明类的权限,表明这是一个公有类(class),其他任何类都可以直接访问它。class 也是Java的一个关键字,用于类的声明,其后紧跟的就是类名,这里的类名称是HelloWorld。

第02行和第09行,这一对大括号{}标明了类的区域,在这个区域内的所有内容都是类的一部分。

第03行和第06行,这两行为注释行,可以提高程序的可读性。注释部分不会被执行。这种注释属于单行注释,要求以双斜线(//)开头,后面的部分均为注释。

第04行,这是一个main方法,它是整个Java程序的入口,所有的程序都是从public static void main(String[ ] args)开始运行的,该行的代码格式是固定的。String[ ] args不能漏掉,如果漏掉,在一些编辑器中(如Eclipse),该类不能被识别执行。另外,String[] args 也可以写成String[ ] args,String为参数类型,表示为字符串型,args是arguments(参数)的缩写。public 和static都是Java的关键词,它们一起表明main是公有的静态方法。void也是Java的关键词,表明该方法没有返回值。对于这些关键词,读者可以暂时不用深究,在后面的章节中会详细讲解main方法的各个组成部分。

第05行和第08行是main方法的开始和结束标志,它们声明了该方法的区域,在{}之内的语句都属于main方法。

第07行,System.out.println是Java内部的一条输出语句。引号内部的内容"Hello World"会在控制台中打印出来。

Eclipse是IBM花巨资开发的集成开发环境(Integrated Development Environment,IDE),其前身是IBM的Visual Age for Java(VA4J)。Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,通过插件组件来构建开发环境,是可扩展的体系结构,可以集成不同软件开发供应商开发的产品,将他们开发的工具和组件加入到Eclipse平台中。

随着Java应用的日益广泛,各大主要软件供应商都参与到Eclipse架构开发中,使得Eclipse的插件数量与日增多。Eclipse为程序开发人员提供了优秀的Java程序开发环境。

Eclipse的安装非常简单,仅需下载Eclipse安装器,双击安装器(Eclipse Installer),选择“Eclipse IDE for Java Developers”(Java开发者专用Eclipse集成开发环境),如下图所示。

在选择安装目录和接受许可协议之后,这个安装器会自动选择Eclipse IDE的下载镜像地址,需经过较长时间等待下载过程(取决于你的网速),如下图所示。

我们假设读者通过自己的一番操作,经过较长时间等待,完成了Eclipse的下载,单击“LAUNCH”(启用)按钮(见下图),即可完成Eclipse的启动。

然后,Eclipse首先让用户选择一个工作空间(WorkSpace),如下图所示。“工作空间”实际上是一个存放Eclipse建立的项目的目录,包括项目源代码、图片等,以及一些用户有关Eclipse个性化的设置(如用于语法高亮显示的颜色、字体大小及日志等)。一般来说,不同的Java项目,如果设置不同,需要使用不同的工作空间来彼此区分。如果想备份自己的软件项目,只要复制该目录即可。

在“Workspace”文本框中输入你指定的路径,如“C:\Users\Yuhong\workspace”(这个路径可以根据读者自己的喜好重新设定),然后单击“OK”按钮,如下图所示。

然后就可以成功启动Eclipse,如下图所示。Eclipse安装器会自动在桌面创建一个快捷方式,下次启动,直接双击快捷方式即可。

需要说明的是,Eclipse默认安装的语言版本是英文。从初学者的角度考虑,如果集成开发工具是中文版的,可能会让读者在学习和使用的过程中轻松些,但实际上,在计算机领域打拼天下,查阅英文文档已经司空见惯,所以,即使是英文版也无伤大碍,习惯了就好。如果实在不习惯英文,读者可以自行在网络上查阅Eclipse汉化教程,这里就不一一赘述了。

下面我们就介绍一下,如何利用Eclipse完成前面的HelloWorld程序,从而让读者对Eclipse的使用有个初步的感性认识。

在Eclipse中编写应用程序时,需要先创建一个项目。在Eclipse中有多种项目(如CVS项目、Java项目及Maven项目等),其中Java项目是用于管理和编写Java程序的,这类项目是我们目前需要关注的。其他项目属于较为高级的应用,读者在有一定的Java编程基础后,可参阅相关资料来学习它们的应用。创建Java项目的具体步骤如下。

➊ 选择“File(文件)→New(新建)→Java Project(Java项目)”命令,打开“New Java Project”(新建Java项目)对话框。

➋ 在弹出的“New Java Project”(新建Java项目)对话框的“Project name”(工程名称)文本框中输入工程名称“HelloWorld”。

➌ 单击“Finish”(完成)按钮,完成Java项目的创建。在“Package Explorer”(包资源管理器)窗口中便会出现一个名称为“HelloWorld”的Java项目,如下图所示。

通过前面创建Java项目的操作,在Eclipse的工作空间中已经有一个Java项目了。构建Java应用程序的下一个操作,就是要创建HelloWorld类。创建Java类的具体步骤如下。

➊ 单击工具栏中的“New Class”(新建类)按钮(见左下图)或者在菜单栏中执行“File(文件)→New(新建)→Class(类)”命令(见右下图),启动新建Java类向导。

![图像70882.PNG{40%}](/api/storage/getbykey/original?key=19038ca18d06d94da68f)   ![图像70890.PNG{40%}](/api/storage/getbykey/original?key=19037c7b63c9060c033c)

➋ 在“Source folder”(源文件夹)文本框中输入Java项目源程序的文件夹位置。通常系统向导会自动填写,如无特殊情况,不需要修改。

➌ 在“Package”(包)文本框中输入该Java类文件准备使用的包名,系统默认为空,这样会使用Java项目的默认包。

➍ 在“Name”(名称)文本框中输入新建类的名称,如“HelloWorld”。

➎ 选中“public static void main ( String [ ] args )”复选框,向导在创建类文件时,会自动为该类添加main()方法,使该类成为可以运行的主类。

➏ 单击“Finish”(完成)按钮,完成Java类的创建,如下图所示。

在编写代码之前,读者需要了解“类”“包”和“文件”这3个概念(后续的章节会更为详细地讲解)。类可以看作是用户自定义的一种数据类型。由于Java是一门纯面向对象的编程语言,在Java项目中,会用到大量的类。项目大了,难免会产生类的名称是相同的情况。例如,在“圆柱体”工程和“球体”工程中,它们可能都有相同的类名——体积类,而对于Java编译器来说,在相同的作用范围内,类的名称必须是唯一的(即无二义性)。为了解决这个问题,Java就用“包(Package)”的概念,让有可能重名的类处于不同的“包”里。这样,“圆柱体”包里的“体积类”和“球体”包里的“体积类”就可以区分开了。

如同有两个人都叫“张三”,他们客观存在着,且都不想改名,为了区分二位,我们可用“河南的张三”和“河北的张三”来加以识别。这里的“河南”和“河北”,在一定意义上,就可以理解为是不同的“包”。有了“包”的概念,可以在很大程度上避免类和方法等的重名。

Java里“包”的概念,和C++中的“名称空间(Namespace)”有着类似的含义。而所有的类都必须保存于某个特定的文件之中,这也就是源码文件(即.java文件)。

01 打开编辑器

当使用创建Java类向导完成Java类文件的创建后,在Eclipse的工作台上会自动打开Java编辑器新创建的Java类文件。打开Java编辑器的方法如下。

➊ 在“Package Explorer”(包资源管理器)窗口中,双击或者右键单击Java源文件HelloWorld.java,如右图所示。

➋ 在弹出的快捷菜单中执行“Open”(打开)命令,便可打开Java编辑器界面,如下图所示。

02 编写Java程序代码

Eclipse具有强大的Java语法突出显示功能。例如,Java编辑器能以各种样式(如字体加粗或斜体等)和不同的颜色来突出显示Java语法(如用紫色显示Java关键字,绿色显示注释等)。

➊ 在“Package Explorer”窗口中,双击“HelloWorld.java”Java源文件。仅需在第6行代码中输入“System.out.println("Hello World!");”代码,就可以完成输出Hello World!语句的功能。

➋ 在第6行代码中输入System,再输入“.”后,Eclipse会智能地启动代码辅助菜单,使用上下方向键移动选中需要的项,按“Enter”键确认,也可直接用鼠标在辅助菜单中双击选中System项,便可自动输入该项,如下图所示。

➌ 按照相同的方法,完成“System.out.println("Hello World");”语句的输入,如下图所示。

➍ 在输入的过程中,如果出现了漏输入或者错误的输入,将鼠标指针停留在红色处,编辑器还会做出正确的语法提示,比如说,假设我们把字符串“Hello World”少写了一个右边的双引号,则Eclipse在没有编译的情况下,就能“很贴心”地提示用户,“String literal is not properly closed by a double-quote”(字符串文字未用双引号正确地引起来),如下图所示。

➎ 如果完成了完整语法的输入,最后没有输入分号“;”作为语句结束符号,那么Eclipse系统也会非常“尽责地”给出正确的语法提示:“Syntax error,insert";" to complete Block Statement”(语法错误,将“;”插入到完整的块语句声明中),如下图所示。

➏ 纠正输入错误后,完整的代码如下所示。

01 public class HelloWorld {
02   public static void main(String[] args) {
03     //输出"Hello World !"到控制台
04     System.out.println("Hello World");
05   }
06 }

前面所创建的HelloWorld类是包含main()主方法的,它是一个可以运行的主类。具体运行方法如下。

➊ 单击工具栏中的小三角按钮,在弹出的“Save and Launch”(保存并启动)对话框中单击“OK”按钮,保存并启动应用程序。如果选中“Always save resources before launching”(在启动前始终保存资源)复选框,那么每次运行程序前将会自动保存文件内容,从而就会跳过如下图所示的对话框。

➋ 单击“OK”按钮后,程序的运行结果便可在控制台中显示出来,如下图所示。

在前面的小节中,不论是用控制台模式,还是用Eclipse、Java编译器——javac,都会将源代码编译成HelloWorld.class文件,这样有“.class”的类文件,并不能如同可执行文件一样,双击就能执行,而是必须通过java命令,将.class文件送往Java虚拟机(Java Virtual Machine,JVM),通过JVM的解释而完成程序的执行,在这其中,JVM扮演着极其重要的作用。下面我们就JVM的机制进行简单的讨论。

JVM可看作是在机器和编译程序之间加入了一层抽象的虚拟机器。这台虚拟的机器在任何平台上都提供给编译程序一个共同的接口。编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。这种仅供虚拟机理解的代码叫做字节码(ByteCode),它不面向任何特定的处理器,只面向虚拟机。每一种平台的解释器是不同的,但是实现的虚拟机却是相同的。

Java程序得以执行的环境称为Java运行环境(Java Runtime Environment,JRE),它由Java虚拟机和Java 的API构成。一个Java程序若想运行在Java虚拟机之中,源代码的语句需由Java编译器编译成字节码。字节码本质上是一种标准化的可移植的二进制格式。该格式以Java类文件(.class)的形式存在。一个Java程序可由多个不同的.class文件构成。在早期发布大型的Java程序中,通常把多个.class文件打包成一个发布文件.jar ,其扩展名来自于“java archive”(java 归档文件)的简写。

Java虚拟机在执行.class或.jar文件时,使用到“即时编译器”(just-in-time compiler,JIT compiler)。“即时编译器”是一个把Java的字节码(包括需要被解释的指令的程序),转换成可以直接发送给处理器指令的程序。本质上,“即时编译器”是Java程序的第二个编译器,它能把通用的字节码编译成特定系统的机器指令代码。但是这里的二次编译,对用户来说基本上是“透明的”,即它存在但用户无需感知。

值得一提的是,另外一种网络编程常见语言——Python,也可以通过jpython(Python的纯Java实现版本)编译后,与Java编译生成一样的字节码,从而也大大提高了该类程序的可移植性。但Python不在本书的讨论范围。

正如Java之父詹姆斯·高斯林所说,他在乎的是JVM, JVM才是Java生态系统的核心,因为它可以跨平台,把所有东西都联系在一起(What I really care about is the Java Virtual Machine as a concept, because that is the thing that ties it all together)。如下图所示,正是有了JVM,Java既可以让字节码在PC操作系统上运行,也可以让其在手机操作系统上运行。

1.注意Java相对C++的一些特性

因为Java语言的设计者十分熟悉C++语言,所以在设计时很好地借鉴了C++语言。可以说,Java语言是比C++语言“更加面向对象”的一种编程语言。Java语言的语法结构与C++语言的语法结构十分相似,这使得C++程序员学习Java语言更加容易。

如果读者是从C++过渡而来的Java学习者,那么下面几个特性值得读者注意。

① 提供了对内存的自动垃圾回收(Garbage Collection),程序员无需在程序中进行分配、释放内存,那些可怕的内存分配错误不会再打扰设计者了。

② 抛弃了C++语言中容易出错的“指针”,而是用诸如“引用(reference)”的方法来取而代之。

③ 避免了赋值语句(如a = 3)与逻辑运算语句(如a = = 3)的混淆。

④ 取消了多重继承这一复杂的概念。C++中的多重继承会导致类中数据成员的“二义性”等问题,从而使得类的访问结构非常复杂。

2. 重视Java官网的文档

Java 8的语言规范(The Java® Language Specification Java SE 8 Edition)是公开的,可在Oracle官方网站上下载。阅读Java语言的规范是提高技术水平的好方法。

3. 如何在命令行模式下正确运行Java类文件

在使用javac编译java源代码生成对应的.class文件(如范例1-1所示的Hello.class),然后用java来运行这个类文件,初学者很容易犯错,有可能得到如下错误信息。

Error: Could not find or load main class Hello.class

产生这种错误的原因通常有两个。

① Java环境变量JAVA_HOME及ClassPath设置不正确,在设置环境变量时,在前一个环境变量前一定要用分号“;”来区分不同的环境变量。同时要把当前目录“.”放进环境变量中。这里的一个小点“.”,代表的就是.class类文件所在的当前目录。

② 有可能初学者在命令行模式下按如下方式来运行这个类文件。

java HelloWorld.class

正确的方式如下所示。

java HelloWorld

也就是说,java操作的对象虽然是类文件,但是却无需类文件的扩展名.class,加上这个扩展名,就属于画蛇添足,反而让编译器不能识别。

4. 正确保存Java的文件名

需要初学者注意的是,虽然一个.java文件可以定义多个类,但只能有一个public类,而且对于一个包括public类名的Java源程序,在保存时,源程序的名称必须要和public类名称完全保持一致,如下所示的一个类。

public class HelloWorld
{ }

这个公有类名称是HelloWorld,那么这个类所在的源文件必须保存为HelloWorld.java,由于Java是区分大小写的(这和Windows操作系统不区分大小写是不同的),保存的Java文件名(除了扩展名.java)必须和公有类的名称一致,包括大小写也必须一模一样。

假设由于不小心,把公有类的名称写成HElloWorld,而文件却保存为HelloWorld.java,虽然二者仅有一个字符“E”在大小写上有差异,但依然无法通过编译,会得到如下错误。

HelloWorld.java:1: error: class HElloWorld is public, should be declared in file named HElloWorld.java
public class HElloWorld
    ^
1 error

上述错误信息的第一句,就是提示包含公有类HElloWorld的文件,应保存的文件名为HElloWorld.java,而不是目前保存的HelloWorld.java。

需要注意的是,对于没有包括public类的源文件,源文件的名称和非public类的名称可以不相同。

5. Eclipse并不是Java程序开发的首选项

在学习Java的过程中,对于诸如Eclipse之类的IDE,读者要有个客观的认识。事实上,Eclipse仅是一个好用的Java集成开发环境,并不是学习Java的“标配”。一方面,一旦读者有了一定的编程经验,可完全脱离Eclipse来开发Java程序。可用编辑器如Notepad++、UltraEdit等(Linux操作系统下可以使用vim,macOS操作系统下可以用TextMate)来编辑Java源代码,然后用Oracle公司提供的JDK,仅使用javac和java等命令就可实施Java程序的开发。

另一方面,虽然Eclipse之类的IDE工具功能强大,能极大提高Java开发效率,初学者也容易上手,但其也有不好的一面,那就是因为IDE工具为我们做了很多事情,它做得越多,我们对Java应用开发的流程了解得就越少。如同培养孩子,在小时候,父母对孩子做得太多,小孩子自己的独立性和动手能力大抵就不太好。所以,我们并不提倡初学者一开始就去追求使用“很酷很炫”的IDE工具。

编写一个Java程序,运行后在控制台中输出“不抛弃,不放弃,Java, I am coming!”。


麻雀虽小,五脏俱全。本章的实例虽然非常简单,但基本涵盖了本篇所讲的内容。可以通过本章来了解Java程序的组成及内部部件(如Java中的标识符、关键字、变量、注释等)。同时,本章还涉及Java程序错误的检测及Java编程风格的注意事项。

本章要点(已掌握的在方框中打钩)

 

首先说明的是,范例2-1中的行号是为了读者(程序员)便于理解而人为添加的,真正的Java源代码是没有这些行号的。

第01~11行为程序的注释,会被编译器自动过滤。但通过注释可以提高Java源码的可读性,使得Java程序条理清晰。需要说明的是,第01~11行有部分空白行,空白行同样会被编译器过滤,在这里的主要功能是为了代码的美观。编写程序到了一定的境界,程序员不仅要追求程序功能的实现,还要追求源代码外在的“美”。这是一种编程风格,“美”的定义和理解不同,编程风格也各异。

在第12行中,public与class是Java的关键字,class为“类”的意思,后面接上类名称,本例取名为TestJava。public用来表示该类为公有,也就是在整个程序里都可以访问到它。

需要特别注意的是,如果将一个类声明成public,那么就需保证文件名称和这个类名称完全相同,如下图所示。本例中public访问权限下的类名为TestJava,那么其文件名即为TestJava.java。在一个Java文件里,最多只能有一个public类,否则.java的文件便无法命名。

第14行,public static void main(String args[ ])为程序运行的起点。第15~21行({}之内)的功能类似于一般程序语言中的“函数”(function),但在Java中称为“方法”(method)。因此,在C/C++中的main()函数(主函数),在Java中,则称为main()方法(或主方法)。

main()方法的主体(body)从第15行的“{”开始,到第21行的“}”为止。每一个独立的Java程序一定要有main()方法才能运行,因为它是程序开始运行的起点。

第16行“int num”的目的是,声明num为一个整数类型的变量。在使用变量之前,需先声明,后使用。这非常类似于,我们必须先定房间(申请内存空间),然后才能住到房间里(使用内存)。

第17行,“num = 5”为一赋值语句,即把整数5赋给存放整数的变量num。

第19行的语句如下。

程序运行时会在显示器上输出一对括号所包含的内容,包括“这是数字”和整数变量num所存放的值。

System.out是指标准输出,通常与计算机的接口设备有关,如打印机、显示器等。其后续的println,是由print与line所组成的,意思是将后面括号中的内容打印在标准输出设备——显示器上。因此第19行的语句执行完后会换行,也就是把光标移到下一行的开头继续输出。

第21行的右大括号告诉编译器main()方法到这里结束。

第22行的右大括号告诉编译器class TestJava到这里结束。

这里只是简单地介绍了一下TestJava这个程序,相信读者已经对Java语言有了一个初步的了解。TestJava程序虽然很短,却是一个相当完整的Java程序。在后面的章节中,将会对Java语言的细节部分做详细的讨论。

从本章开始,我们正式开启学习Java程序设计的旅程。在本章,除了认识程序的架构外,我们还将介绍标识符、关键字以及一些基本的数据类型。通过简单的范例,让读者了解检测与提高程序可读性的方法,以培养读者良好的编程风格和正确的程序编写习惯。

下面来看一个简单的Java程序。在介绍程序之前,读者先简单回顾一下第1章讲解的例子,之后再来看下面的这个程序,在此基础上理解此程序的主要功能。

范例 2-1 Java程序简单范例(TestJava.java)

01  /**
02  
03   * @ClassName: TestJava
04  
05   * @Description: 这是Java的一个简单范例
06  
07   * @author: YuHong 
08  
09   * @date: 2016年11月15日 
10  
11   */
12  public class TestJava
13  {
14    public static void main(String args[ ])
15    {
16     int num ;  // 声明一个整型变量num
17     num = 5 ;  // 将整型变量赋值为5
18     // 输出字符串,这里用“+” 号连接变量
19      System.out.println("这是数字 " + num); 
20      System.out.println("我有 " + num + "本书!");
21    }
22  }

保存并运行程序,结果如下图所示,注意该图是由Eclipse软件输出的界面。

如果读者现在暂时看不懂上面的这个程序,也没有关系,先把这些Java代码在任意文本编辑器里(Eclipse编辑器、微软的写字板、Notepad++等均可)手工敲出来(尽量不要用“复制+粘贴”的模式来完成代码输入,每一次编程上的犯错,纠正之后,都是进步),然后存盘、编译、运行,就可以看到输出结果。

代码详解

19  System.out.println(“这是数字 "+num);

在本节,我们将探讨Java语言的一些基本规则及用法。

01 大括号、段及主体

将类名称定出之后,就可以开始编写类的内容。左大括号“{”为类的主体开始标记,而整个类的主体至右大括号“}”结束。每个命令语句结束时,都必须以分号“;”做结尾。当某个命令的语句不止一行时,必须以一对大括号{ }将这些语句包括起来,形成一个程序段(segment)或是块(block)。

下面以一个简单的程序为例来说明什么是段与主体(body)。若暂时看不懂TestJavaForLoop这个程序,也不用担心,以后会讲到该程序中所用到的命令。

范例 2-2 简单的Java程序(TestJavaForLoop.java)

01 //TestJavaForLoop,简单的Java程序
02 public class TestJavaForLoop
03 {
04   public static void main(String args[])
05   {
06     int x;
07     for(x = 1;x < 3;x++)
08     {
09     System.out.println(x + "*" + x + "=" + x * x);
10     }
11   }
12 }

运行程序并保存,结果如下图所示。

【范例分析】

在上面的程序中,可以看到main() 方法的主体以大括号{}包围起来;for循环中的语句不止一行,所以使用大括号{}将属于for循环的段内容包围起来;类TestJavaForLoop的内容又被第03行和第12行的大括号{}包围,这个块属于public类TestJavaForLoop所有。此外,应注意到每个语句结束时,都是以分号(;)作为结尾。

02 程序运行的起始点——main() 方法

Java程序是由一个或一个以上的类组合而成,程序起始的主体也被包含在类之中。这个起始的地方称为main(),用大括号将属于main()段的内容包围起来,称为“方法”。

main()方法为程序的主方法,如同中国的古话“家有千口,主事一人”。类似地,在一个Java程序中,不论它有千万行,执行的入口只能有一个,而这个执行的入口就是main()方法,它有且仅有一个。通常看到的main() 方法如下面的语句片段所示。

public static void main(String args[]) // main() 方法,主程序开始
{
   … 
   }

如前一节所述,main() 方法之前必须加上public static void 这3个标识符。public代表main()公有的方法;static表示main()是个静态方法,可以不依赖对象而存在,也就是说,在没有创建类的对象的情况下,仍然可以执行;void英文本意为“空的”,这里表示main()方法没有返回值。main后面括号( )中输入的参数String args[]表示运行该程序时所需要的参数,这是固定的用法,我们会在以后的章节介绍这个参数的使用细节。

我们在学习Java中经常遇到“方法”这个概念,而在学习C或C++时,又会遇到“函数”概念,语言都是相通的,那二者又有什么区别和联系呢?

(1)“函数”是一段实现某种“功能”的代码,函数的操作是对输入数据的处理。函数的英文“function”恰恰有“功能”的含义,可以达到“见名知意”。通过函数的名称来实施函数调用。它能将一些数据(也就是参数)传递进去进行处理,然后返回一些数据(即函数的返回值),也可以没有返回值。所有传递给函数的数据都是显式传递的。而方法的参数传递通常是隐式的,它可以直接操作类内部的数据。

(2)“方法”也是一段完成某项功能的代码,也通过名字来进行调用,但它依赖于某个特定的对象,例如,我们可以说“调用对象X的Y方法”,而不能说“调用Y方法”。简单来讲,方法和对象相关;而函数和对象无关。因为Java是一门完全面向对象编程的语言,所以在Java中只有方法。

C是面向过程的编程语言,所以在C中只有函数。C++是C的超集,既支持面向过程编程,又支持面向对象编程,所以在C++中,如果一个函数独立于类之外,那它就是函数,如果它存在于一个类中,那它就是方法,所不同的是,C++给这种特殊的方法取了一个新名称——成员函数(member function)。

Java中的包(package)、类、方法、参数和变量的名称,可由任意顺序的大小写字母、数字、下划线(_)和美元符号($)等组成,但这些名称的标识符不能以数字开头,也不能是Java中保留的关键字。

下面是合法的标识符。

yourname    your_name    _yourname    $yourname

比如,下面的4个标识符是非法的。

class    6num23    abc@sina  x+y

非法的原因分别是:class是Java的保留关键字;6num23的首字母为数字;abc@sina中不能包含@等特殊字符;x+y不能包含运算符。

此外,读者应该注意,在Java中,标识符是区分大小写的,也就是说,A123和a123是两个完全不同的标识符。

注意

 

标识符的命名规则属于强制性的,不然编译时会报错。一些刚接触编程语言的读者可能会觉得记住上面的规则很麻烦,所以在这里提醒读者,标识符建议用字母开头,而且尽量不要包含其他的符号。规则是必须遵守的,而规范是约定俗成的,鼓励大家都遵守。

和其他语言一样,Java中也有许多关键字(keywords,也叫保留字),如public、static、int等,这些关键字不能当做标识符使用。下表列出了Java中的关键字。这些关键字并不需要读者现在把它们记住,因为在程序开发中一旦使用了这些关键字做标识符,编译器在编译时就会报错,而智能的编辑器(如Eclipse等)会在编写代码时自动提示这些语法错误。在后续的章节中,我们会慢慢学习它们的内涵和用法。

abstract

assert ***

bollean

break

byte

case

catch

char

class

const *

continue

default

do

double

else

enum ****

extends

false

final

finally

float

for

goto *

if

implements

import

instanceof

int

interface

long

native

new

null

package

private

protected

public

return

short

static

stricfp **

synchronized

super

this

throw

transient

true

try

void

volatile

while

注:*表示该关键字尚未启用;**表示在Java 1.2中添加的;***表示在Java 1.3中添加的;****表示在Java 5.0中添加的。

注意

 

虽然goto、const在Java中没有任何意义,却也是保留的关键字,与其他的关键字一样,在程序里不能用来作为自定义的标识符,true 、false、null等看起来像关键词,实际上在Java中,它们仅仅是普通的字符串。Java中的所有关键字均由小写字母构成。

2.2.4 注释

注释在源代码中的地位非常重要,虽然注释在编译时被编译器自动过滤掉,但为程序添加注释可以解释程序的某些语句的作用和功能,提高程序的可读性。特别当编写大型程序时,多人团队合作,A程序员写的程序B程序员可能很难看懂,而注释能起到非常重要的沟通作用。所以本书强烈建议读者朋友养成写注释的好习惯。

Java里的注释根据不同的用途分为以下3种类型。

(1)单行注释。

(2)多行注释。

(3)文档注释。

单行注释,就是在注释内容的前面加双斜线(//),Java编译器会忽略这部分信息,如下所示。

int num ;       //定义一个整数

多行注释,就是在注释内容的前面以单斜线加一个星形标记(/*)开头,并在注释内容末尾以一个星形标记加单斜线(*/)结束。当注释内容超过一行时,一般可使用这种方法,如下所示。

/*
int c = 10 ;
int x = 5 ;
*/

值得一提的是,文档注释是以单斜线加两个星形标记(/**)开头,并以一个星形标记加单斜线(*/)结束。用这种方法注释的内容会被解释成程序的正式文档,并能包含进如javadoc之类的工具生成的文档里,用以说明该程序的层次结构及其方法。

范例2-1中的第01~11行对源代码的注释属于第(3)类注释,通常在程序开头加入作者,时间,版本,要实现的功能等内容注释,方便后来的维护以及程序员的交流。本质上注释类别(3)是(2)的一个特例,(3)中的第2个星号*可看作注释的一部分。由于文档注释比较费篇幅,在后面的范例中,我们不再给出此类注释,读者可在配套资源中看到注释更为全面的源代码。

需要注意的是,第03 ~06行的注释中,每一行前都有一个*,其实这不是必需的,它们是注释区域的一个“普通”字符而已,仅仅是为了注释部分看起来更加美观。前文我们已提到,实现一个程序的基本功能是不够的,优秀的程序员还会让自己的代码看起来很“美”。

2.2.5 变量

在Java程序设计中,变量(Variable)在程序语言中扮演着最基本的角色之一,它是存储数据的载体。计算机中的变量是实际存在的数据。变量的数值可以被读取和修改,它是一切计算的基础。

与变量相对应的就是常量(Constant),顾名思义,常量是固定不变的量,一旦被定义并赋初值后,它的值就不能再被改变。

本节主要关注的是对变量的认知,接下来看看Java中变量的使用规则。Java变量的使用和其他高级计算机语言一样:先声明,后使用,即必须事先声明它想要保存数据的类型。

01 变量的声明

声明一个变量的基本方式如下。

数据类型 变量名;

另外,在定义变量的同时,给予该变量初始化,建议读者使用下面这种声明变量的风格。

数据类型 变量名 = 数值或表达式;

举例来说,想在程序中声明一个可存放整型的变量,这个变量的名称为num。在程序中即可写出如下所示的语句。

int num;      //声明num为整数变量

int为Java的关键字,代表基本数据类型—整型。若要同时声明多个整型的变量,可以像上面的语句一样分别声明它们,也可以把它们都写在同一个语句中,每个变量之间以逗号分开。下面的变量声明的方式都是合法的。

int num1, num2, num3; //声明3个变量num1, num2, num3,彼此用英文逗号“,”隔开
int num1; int num2; int num3; //用3个语句声明上面的3个变量,彼此用英文分号“;”隔开

虽然上面两种定义多个变量的语句都是合法的,但对它们添加注释不甚方便,特别是后一种同一行有多个语句,由于可读性不好,建议读者不要采纳此种编程风格。

02 变量名称

读者可以依据个人的喜好来决定变量的名称,但这些变量的名称不能使用Java的关键字。通常会以变量所代表的意义来取名。当然也可以使用abc等简单的英文字母代表变量,但是当程序很大时,需要的变量数量会很多,这些简单名称所代表的意义就比较容易忘记,必然会增加阅读及调试程序的困难度。变量的命名之美在于:在符合变量命名规则的前提下,尽量对变量做到“见名知意”,自我注释(Self Documentation),例如,用 num 表示数字,用length 表示长度等。

03 变量的赋值

给所声明的变量赋予一个属于它的值,用赋值运算符(=)来实现。具体可使用如下所示的3种方法进行设置。

(1)在声明变量时赋值。

举例来说,在程序中声明一个整数的变量num,并直接把这个变量赋值为2 ,可以在程序中写出如下的语句。

int num = 2 ; //声明变量,并直接赋值

(2)声明后再赋值。

一般来说也可以在声明后再给变量赋值。举例来说,在程序中声明整型变量num1、num2及字符变量ch,并且给它们分别赋值,在程序中即可写出下面的语句。

int num1,num2 ;     //声明2整型变量num1和num2
char  ch ;        //声明1字符变量ch
num1 = 2 ;          //将变量num1赋值为2
num2 = 3 ;         //将变量num2赋值为3
ch = 'z' ;        //将字符变量ch赋值为字母z

(3)在程序的任何位置声明并设置。

以声明一个整数的变量num为例,可以等到要使用这个变量时再给它赋值。

int num ; //声明整型变量num
…
num = 2 ;  //用到变量num时,再赋值

2.2.6 数据类型

除了整数类型之外,Java还提供有多种数据类型。Java的变量类型可以是整型(int)、长整型(long)、短整型(short)、浮点型(float)、双精度浮点型(double),或者字符型(char)和字符串型(String)等。下面对Java中的基本数据类型给予简要介绍,读者可参阅相关章节获得更为详细的介绍。

整型是取值为不含小数的数据类型,包括byte类型、short类型、int类型及long类型,默认情况下为int类型,可用八进制、十进制及十六进制来表示。另一种存储实数的类型是浮点型数据,主要包括float型(单精度浮点型,占4字节)和double型(双精度浮点型,占8字节)。用来表示含有小数点的数据,必须声明为浮点型。在默认情况下,浮点数是double型的。如果需要将某个包括小数点的实数声明为单精度,则需要在该数值后加字母“F”(或小写字母“f”)。

下面的语句是主要数据类型的定义说明。

01  int  num1 = 10;         //定义4字节大小的整型变量num1,并赋初值为10
02  byte  age = 20;        //定义1个字节型变量age,并赋初值为20
03  byte  age2 = 129;        //错误:超出了byte类型表示的最大范围(-128~127)
04  float  price = 12.5f;     //定义4字节的单精度float型变量price,并赋初值为12.5
05  float  price = 12.5;      //错误:类型不匹配 
06  double  weight = 12.5;      //定义8字节的双精度double变量weight,并赋初值为12.5

定义数据类型时,要注意两点。

(1)在定义变量后,对变量赋值时,赋值大小不能超过所定义变量的表示范围。例如,本例第03行是错误的,给age2赋值129,已超出了byte类型(一个字节)所能表示的最大范围(-128~127)。这好比某人在宾馆定了一个单人间(声明byte类型变量),等入住的时候,又多了一个人,要住双人间,这时宾馆服务员(编译器)是不会答应的。解决的办法很简单,需要重新在一开始就定双人间(重新声明age2为short类型)。

(2)在定义变量后,对变量赋值时,运算符(=)左右两边的类型要一致。例如,本例第05行是错误的,因为在默认情况下,包含小数点的数(12.5)是双精度double类型的,而“=”左边定义的变量price是单精度float类型的,二者类型不匹配!这好比一个原本定了双人间的顾客,非要去住单人间,刻板的宾馆服务员(编译器)一般也是不答应的,因为单人间可能放不下双人间客人的那么多行李,丢了谁负责呢?如果住双人间的顾客非要去住单人间,那需要双人间的顾客显式声明,我确保我的行李在单人间可以放得下,或即使丢失部分行李,我也是可以承受的(即强制类型转换),强制类型转换的英文是“cast”,而“cast”的英文本意就是“铸造”,铸造的含义就包括了“物是人非”的内涵。下面的两个语句都是合法的。

float price = 12.5f;          //中规中矩的定义,一开始就保证“=”左右类型匹配
float price = (float)12.5;    //通过强制类型转换后,“=”左右类型匹配

2.2.7 运算符和表达式

计算机的英文为Computer,顾名思义,它存在的目的就是用来做计算(Compute)的。而要运算就要使用各种运算符,如加(+)、减(-)、乘(*)、除(/)、取余(%)等。

表达式则由操作数与运算符所组成,操作数可以是常量、变量,甚至可以是方法。下面的语句说明了这些概念的使用。

int result = 1 + 2;

在这个语句中,1+2 为表达式,运算符为“+”,计算结果为 3,通过“=”赋值给整型变量result。

对于表达式,因为运算符是有优先级的,所以即使有计算相同的操作数和相同的运算符,其结果也是有可能不一样的,例如以下形式。

c = a + b / 100; //假设变量a,b,c为已定义的变量

在上述的表达式中“a + b /100”,因为除法运算符“/”的优先级比加法运算符“+”高,所以c的值为b除以100后的值再加上a之和,这可能不是程序员的本意,如果希望是a+b之和一起除以100,那么就需要加上括号()来消除这种模糊性,如下所示。

c = (a + b) /100; // a+b之和除以100

2.2.8 类

Java程序是由类(class)所组成的。类的概念在以后会详细讲解,读者只要记住,类是一种用户自定义的类型就可以了, Java程序都是由类组成的。下面的程序片段即为定义类的典型范例。

public class Test             // 定义public类 Test
{
…
}

程序定义了一个新的public类Test,这个类的原始程序的文件应取名为Test.java。类Test的范围由一对大括号所包含。public是Java的关键字,指的是对于该类的访问方式为公有。

需要注意的是,由于Java程序由类所组成,因此在一个完整的Java程序里,至少需要有一个类。在前面我们曾提到,Java程序的文件名不能随意命名,必须和public类名称一样(大小写也必须保存一致)。因此,在一个独立的源码程序里,只能有一个public类,却可以有许多non-public(非公有)类。若是在一个Java程序中没有一个类是public,那么对该Java程序的文件名就可以随意命名了。

Java提供了一系列的访问控制符来设置基于类(class)、变量(variable)、方法(method)及构造方法(constructor)等不同等级的访问权限。Java的访问权限主要有4类:default(默认模式)、private(私有)、public(公有)和protected(保护)。对类和接口概念的深度理解,读者可参阅后面的章节,这里仅需读者了解,在Java中有这么4种访问控制方式即可。

2.2.9 输入与输出

 

程序第02行,如果要完全使用Java输入、输出流类模块,就必须导入相应的包库(java.io.*)支持。java.io.*中的字母“i”表示input(输入),字母“o”表示output(输出),“*”是代表任何含义的通配符,它表示输入输出(io)下所有模块。在Java中,“.”表示对象与组件之间的所有关系,为了方便起见,读者可以直接用中文“的”来代替。例如以下形式。

我们可以直接读成“导入java'的'io包库下'的'所有模块”。

程序的第09行表示创建标准输入流对象stdin,来接收键盘System.in的输入。

程序的第11行表示以缓冲流模式来接收stdin。缓冲机制主要是为了处理应用程序和外设(输入/输出)之间速度不匹配的问题。

程序的第15行和第19行,使用的是标准输出对象System.out,这在前面的范例中频繁使用。

程序第22行用System.err对象输出程序的错误信息。

其实程序第22行的功能完全可以用被注释掉的第21行代替,二者均可输出程序的错误信息,在此处可通用。所不同的是,使用System.err代码的可读性更好一点,其中err表示error(错误)。System.err可以理解为专用于输出错误信息的System.out特例。

程序的第13~20行,使用了Java的try-catch错误捕捉处理机制。正如“天有不测之风云”一样,在Java程序设计过程中,程序员虽已尽量考虑全面以避免各种错误,但从软件工程角度来看,在程序运行过程中还是基本上不可避免地发生各种不可预测的异常情况,程序愈大,此类情况愈是明显。对此,一个良好的程序需要有一定的容错机制,即不能因为程序员的某个潜在的设计缺陷或用户可能的操作失误(如输入信息出错),而导致整个程序崩溃。因此,需要添加相应的代码来处理程序中异常(Exception)错误。try-catch机制对于程序的健壮性(Robust)非常重要,我们会在后面的章节介绍这方面的知识,这里读者只需有个感性认识即可。

输入/输出(I/O)是指程序为了完成计算,与外部设备或其他计算机进行交互的操作。几乎所有的程序都具有输入与输出功能,如从键盘上读取数据,向屏幕或文件输出数据等。只有通过输入和输出操作,才能从外界接收信息,或者把信息传递给外界。Java把这些输入与输出操作用流的模式来实现,通过统一的接口来表示,从而使程序设计更为简单。

在Java中,流(Stream)是一个重要的但初学者很容易困惑的概念。流(stream)的概念最早源于Unix操作系统中管道(pipe)的概念。在Unix中,管道是一条不间断的字节流,用来实现进程间的通信,或完成读写外围设备、外部文件之间的信息交互等。一个流必须有起源端和目的端,它们可以是计算机内存的某部分区域,也可以是某个磁盘文件,甚至可以是互联网上的某个统一资源定位器(Uniform Resoure Locator,URL)。

import java.io.*;

为了便于理解,读者可以将Java中的流想象成一种“数据流通的管道”,文件和程序之间一旦有了数据请求,二者之间就会建立某种形式的连接,从而形成了一个数据流。

就如在真正的管道中,可以传输不同形态的东西,既可以是水,也可以是天然气。类似的,Java中的数据流也有不同的形式,既可以是基于二进制的字节流,也可以是基于某种编码方式(如Unicode、UTF-8等)的字符流。

流的方向很重要,根据流的方向,流大致可分为两类:输入流和输出流。当程序需要读取数据时,就会开启一个通向数据源的管道,程序可从该管道中提取数据,这种模式下的流称为输入流。类似地,如果程序想要输出数据,也会建立一个通往输出目的地的管道,一旦建立后,程序就可以经由此管道输出数据,这种模式的流称为输出流。关于数据流,它们的输入、输出关系可用下图来说明。

作为程序输入数据源,其对象可以是键盘,也可以是某个文件或磁盘。作为程序输出数据源,其对象可以是显示器,也可以是某个文件或磁盘。为了方便一些频繁的设备交互,Java语言系统预定了3个可以直接使用的流对象,它们分别如下。

① System.in(标准输入):通常代表键盘输入。

② System.out(标准输出):通常输出到终端显示器。

③ System.err(标准错误输出):通常将错误信息输出到终端显示器。

System.in是个标准的输入流(InputStream)对象,它主要用来连接控制台程序和键盘的输入。目前System.in并不经常用到,这是因为Java命令行应用程序主要是通过命令行参数或配置文件来传递数据的,对于图形用户界面(GUI)程序,则主要是用图形界面来接纳用户的键盘输入。

System.out是打印输出流(PrintStream)对象,主要向控制台输出数据,这个对象经常会被面向控制台的程序使用到,它也常被程序员用作程序调试输出的工具。

System.err也是打印输出流(PrintStream)对象,除了其主要用于错误输出之外,它和System.out没有太大区别。有些应用程序(如Java程序员常用的Eclipse)用System.err以红色字体来输出错误信息。它可以看作一个专门用于输出错误信息的System.out。

数据的输入、输出属于I/O操作部分,Java把处理输入/输出相关的类放在java.io包中,这个包不属于java.lang包,没有被默认加载,所以如果需要使用与I/O相关的类和对象时,需要把java.io显式地导入(import)到相应的程序中。下面我们用范例2-3来说明标准输入和输出的使用。

范例 2-3 简单的输入、输出流使用范例(StreamInTest.java)

01 //Syetem.in、Syetem.out、Syetem.err的使用范例
02  import java.io.*;    // 导入Java中支持I/O类的包
03  public class StreamInTest 
04  { 
05    public static void main(String args[]) 
06    {
07      String str;
08      //创建标准输入流对象stdin 来接收键盘System.in的输入
09      InputStreamReader stdin = new InputStreamReader(System.in); 
10      //以缓冲流模式来接收stdin
11      BufferedReader   bufin = new BufferedReader(stdin);
12      //使用try和catch机制来处理输入的异常
13      try {
14      
15        System.out.print ("请输入字符:");
16        //用str字符串对象来接收键盘输入的一行数据
17        str = bufin.readLine();
18      
19        System.out.println ("你输入的字符为:" + str);
20      } catch (Exception e) {
21        //System.out.println("发生I/O错误!!!"); 
22        System.err.println("发生I/O错误!!!"); 
23        e.printStackTrace();
24      }
25     
26    }
27  }

运行程序并保存,结果如下图所示。

代码详解

2.3 程序的检测

学习到本节,相信读者大概可以依照前面的例子“照猫画虎”,写出几个类似的程序了。而在编写程序时,不可避免地会遇到各种编译时(语法上的)或运行时(逻辑上的)错误,接下来我们做一些小检测,看看读者能否准确地找出下面的程序中存在的错误。

2.3.1 语法错误

通过下面的范例应学会怎样找出程序中的语法错误。

范例 2-4 找出下面程序中的语法错误(SyntaxError.java)

01 //下面程序的错误属于语法错误,在编译的时候会自动检测到
02 public class SyntaxError
03 {
04  public static void main(String args[])
05  {
06   int num1 = 2 ; //声明整数变量num1,并赋值为2
07   int num2 = 3 ; //声明整数变量num2,并赋值为3
08  
09   System.out.println("我有 "+num1" 本书!");
10   System.out.println("你有 "+num2+"本书!")
11  )
12 }

【范例分析】

程序SyntaxError在语法上犯了几个错误,若是通过编译器编译,便可以把这些错误找出来。事实上,在Eclipse中,语法错误的部分都会显示红色的下划线,对应的行号处会有红色小叉(×),当鼠标指针移动到小叉处,会有相应的语法错误信息显示,如下图所示。

首先,可以看到第04行,main()方法的主体以左大括号“{”开始,应以右大括号“}”结束。所有括号的出现都是成双成对的,因此,第11行main()方法主体结束时,应以右大括号“}”做结尾,而这里却以右括号“)”结束。

注释的符号为“//”,但是在第07行的注释中,没有加上“//”。在第09行,字符串“ 本书!”前面,少了一个加号“+”来连接。最后,还可以看到在第10行的语句结束时,少了分号“;”作为结束。

上述的3个错误均属于语法错误。当编译程序发现程序语法有错误时,会把这些错误的位置指出来,并告诉程序设计者错误的类型,程序设计者可根据编译程序所给予的信息加以更正。

程序员将编译器(或IDE环境)告知的错误更改之后,重新编译,若还是有错误,再依照上述的方法重复测试,这些错误就会被一一改正,直到没有错误为止。

2.3.2 语义错误

若程序本身的语法都没有错误,但是运行后的结果却不符合程序设计者的要求,此时可能犯了语义错误,也就是程序逻辑上的错误。读者会发现,想要找出语义错误比找出语法错误更加困难。因为人都是有思维盲点的,在编写程序时,一旦陷入某个错误的思维当中,有时很难跳出来。排除一个逻辑上的语义错误,糟糕时可能需要经历一两天,才突然“顿悟”错误在哪里。

举例来说,想在程序中声明一个可以存放整数的变量,这个变量的名称为num。在程序中即可写出如下所示的语句。

范例 2-5 程序语义错误的检测(SemanticError.java)

01 //下面这段程序原本是要计算一共有多少本书,但是由于错把加号写成了减号,
   //所以造成了输出结果不正确,这属于语义错误
02 public class SemanticError
03 {
04   public static void main(String args[])
05     {
06     int num1 = 4 ; //声明一整型变量num1
07     int num2 = 5 ; //声明一整型变量num2
08 
09    System.out.println("我有 " + num1 +" 本书! ");
10    System.out.println("你有 " + num2 +" 本书! ");
11    //输出num1-num2的值s
12    System.out.println("我们一共有 " + (num1 - num2) + " 本书! "); 
13   }
14 }

保存并运行程序,结果如下图所示,显然不符合设计的要求。在纠正第12行的语义错误之后的输出结果如下图所示。

范例2-5的输出结果图

纠正语义错误的输出结果图

【范例分析】

可以发现,在程序编译过程中并没有发现错误,但是运行后的结果却不正确,这种错误就是语义错误。在第12行中,因失误将“num1+num2”写成了“num1-num2”,虽然语法是正确的,但是却不符合程序设计的要求,只要将错误更正后,程序的运行结果就是想要的了。

2.4 提高程序的可读性

能够写出一个功能正确的程序,的确很让人兴奋。但如果这个程序除了本人之外,其他人都很难读懂,那这就不算是一个好的程序。所以,程序的设计者在设计程序的时候,除了完成程序必需的功能,也要学习程序设计的规范格式。除了前面所说的加上注释之外,还应当保持适当的缩进,保证程序的逻辑层次清楚。

前面的范例程序都是按缩进的方法来编写的。读者可以比较下面的两个范例,相信看完之后,就会明白程序中使用缩进的好处了。

范例 2-6 缩进格式的程序(IndentingCode.java)

01 //以下这段程序是有缩进的样例,可以发现这样的程序看起来比较清楚
02 public class IndentingCode
03 {
04   public static void main(String args[])
05   {
06     int x ;
07    
08     for(x=1;x<=3;x++)
09     {
10     System.out.print("x = " + x + ", ");
11     System.out.println("x * x = " + (x * x));
12     }
13   }
14 }

保存并运行程序,范例2-6结果如下图所示。

范例 2-7 非缩进格式的程序(Indenting)

01 //下面的程序与范例2-6程序的输出结果是一样的
02 //但不同的是,这个程序没有采用任何缩进,代码阅读者看起来很累,代码逻辑关系不明显,不易排错
03 public class IndentingCode{
04 public static void main(String args[]){
05 int x ; for(x=1;x<=3;x++){
06 System.out.print("x = "+x+", ");
07 System.out.println("x * x = "+(x*x));}}}

【范例分析】

这个案例很简短,而且也没有语法错误,但是因为编写风格(Programming Style)的关系,阅读起来肯定没有前面一个案例容易读懂,所以建议读者尽量使用缩进,养成良好的编程习惯。良好的代码编写风格,是优秀程序员需要达到的境界,在满足程序基本功能和性能目标的前提下,还要满足代码的“雅致”之美。

2.5 高手点拨

注意Java源代码中的字符半角和全角之分

Java继承了C和C++的很多语法,其中一个语法就是每个语句(Statement)后加一个分号“;”作为本语句的结束。这本是一个很简单的语法要求,但是对于初学者来说,却是一个极容易犯错的问题。其主要原因在于混淆了半角的“;”和全角的“;”的区别。那么什么是字符的半角和全角呢?

传统上,在西欧语系使用的计算机系统中,每一个字母或符号使用1个字节的空间,而1个字节由8比特(bit)组成,因此共有28=256个编码空间,这对西欧语系的字符足够用了;但是对于汉语、日语及韩语文字,由于其数量远远超过256个,故常使用两字节来存储1个字符,为了使字体看起来齐整,英文字母、数字及其他符号,也由原来只占1个字空间,改为用2个字的空间来显示,并用2个字节来存储。所以,汉语、日语、韩语等文字没有半角之说,统一为全角字符。相比起来,英文字母、数字及其他西欧符号用1个字节表示就是半角,用2个字节表示就是全角,如下图所示。

Java的初学者在使用中文输入法输入英文字符时,很容易在中文输入模式下输入全角的分号(;)、左右大括号(“{”“}”)、左右括号(“(”“)”)及逗号(,),而Java的编译器在语法识别上仅仅识别这些字符对应的半角。因此建议初学者在输入Java语句(不包括注释和字符串的内容)时,在中文输入模式下,要么按“Ctrl+Shift”组合键切换至英文模式,要么将中文输入法转变为半角模式,如下图所示,中文输入法中的“太阳”标记为全角模式,单击该图标可以切换为“月亮”标记——半角模式。

2.6 实战练习

1.分析下面程序代码的运行结果,运行程序并查看实际结果,分析产生结果的原因。

01 public class Exercise2-1
02 {
03   public static void main (String args[])
04   {
05     int x = 10;
06     int y = 3;
07     System.out.println( x / y);
08   }
09 }

2. 用float型定义变量:float f = 3.14; 是否正确? (Java面试题)

解析:不正确。赋值运算符(=)左右两边的精度类型不匹配。在默认情况下,包含小数点的实数,如本题中的3.14,被存储为double类型(即双精度),而float类型定义的变量,如本题中的f是单精度的。如果想让上面的语句编译正确,应该对赋值运算符(=)右边的值做强制类型转换,即把常量3.14强制转换为单精度(即float类型),如下所示。

float f = (float)3.14; //正确

或者,一开始就把3.14存储为单精度类型,在3.14后加上小写字母“f”或大写字母“F”,如下所示。

float f = 3.14f; //正确
float f = 3.14F; //正确


相关图书

Effective Java中文版(原书第3版)
Effective Java中文版(原书第3版)
Java编程动手学
Java编程动手学
Java研发自测入门与进阶
Java研发自测入门与进阶
Java开发坑点解析:从根因分析到最佳实践
Java开发坑点解析:从根因分析到最佳实践
Java EE企业级应用开发实战(Spring Boot+Vue+Element)
Java EE企业级应用开发实战(Spring Boot+Vue+Element)
Effective Java (第3版 英文版)
Effective Java (第3版 英文版)

相关文章

相关课程