带你读《Java程序设计与计算思维》之一:计算思维与Java设计初步体验-阿里云开发者社区

开发者社区> 华章出版社> 正文

带你读《Java程序设计与计算思维》之一:计算思维与Java设计初步体验

简介: 程序设计的过程就是一种计算思维的表现,《Java程序设计与计算思维》结合Java程序设计语言的教学特点,遵循计算思维的方式,图解重要概念,通过大量的范例程序讲解和上机编程实践来指导读者活用Java程序语法,兼顾培养计算思维和学习面向对象程序设计的双目标。

点击查看第二章
点击查看第三章
Java程序设计与计算思维

image.png

赵军 吴灿铭 等编著

第1章 计算思维与Java设计初步体验

计算机(Computer)堪称是20世纪以来人类最伟大的发明之一,对于人类的影响更甚于工业革命所带来的冲击。计算机是一种具备数据处理与计算功能的电子设备。在1946年,美国宾州大学教授埃克特与莫西利合作完成了人类第一台真空电子管计算机ENIAC。而在1945年,冯?诺依曼教授首先提出了计算机存储程序的运行方式与二进制的概念,认为数据与程序可以存储在计算机的存储器再投入运行,于是拉开了程序设计语言与程序设计蓬勃发展的序幕。自从人类发明计算机,计算机就渗透到人类生活的各个领域。如图1-1所示的是计算机运用于工厂生产线与大楼自动化安保管理的例子。

image.png

从程序设计语言的发展史来看,其种类还真是不少,如果包括实验、教学或科学研究中使用的程序设计语言,那么可能有上百种之多,不过每种程序设计语言都有其发展的背景及目的。例如FORTRAN语言是世界上第一个开发成功的高级程序设计语言,另一个早期非常流行的高级程序设计语言是BASIC语言,它不但易学易懂,而且非常适合初学者了解程序设计语言的运行过程,笔者算是最早一批“计算机普及要从娃娃抓起”的受益者,在上初中的时候第一次接触计算机,学习的程序设计语言就是BASIC,它的早期版本不是结构化的程序设计语言。早期的另一种语言PASCAL的主要目标是教导程序设计的原则,笔者进入大学计算机系学习的第一种程序设计语言就是PASCAL语言,它基本上是早期用于大学教授学生结构化程序设计思想的首选语言。后来陆续推出了商业用途的COBOL语言、人工智能专用的PROLOG语言等,有些语言出现之后一直流行至今,如C、C++、Java、Visual Basic语言,其中的Java语言是具有代表性的面向对象程序设计语言之一。
时至今日,面向对象程序设计的概念已经倡导多年。20世纪70年代出现的Smalltalk语言是真正的第一个面向对象的程序设计语言,后来C++和Java也加入了面向对象程序设计语言的阵营,Java语言是一种完全面向对象的程序设计语言。本章将从程序设计最重要的计算思维概念开始讲述,然后概略性地介绍程序设计语言的分类、程序设计的步骤及Java语言,涉及的内容包括Java的起源、语言的特性和应用范围。同时,也会谈到最新的开发工具Java SE 11的新增功能,示范如何正确地编译与执行Java程序。完成本章的学习后,我们可以开始编写第一个Java程序,就会清楚Java简易的程序结构。
本章的学习目标

  • 认识计算思维
  • 程序设计语言的分类
  • 程序设计的流程
  • 程序设计的原则
  • 结构化与面向对象的程序设计
  • Java语言的起源
  • Java语言的特性
  • Java的开发工具
  • JDK的安装与运行环境的设置
  • Java程序的编译与执行
  • Java的程序结构解析
  • Java SE11新增功能的简介

1.1 认识计算思维

对于一个有志于投身信息技术领域的人员来说,程序设计是一门和计算机硬件与软件息息相关的学科,是计算机诞生以来一直蓬勃发展的新兴科学。从长远的发展来看,程序设计能力已经被看成是国力的象征,不少省市已经将程序设计列入高中学生的选修课程,有些省份的高考甚至加入程序设计的考核,例如浙江省从2017年高考开始,除了语文、数学、英语三科必考外,其他七选三的选考科目中就有“技术”科目,考核的内容包括通用技术和信息技术。程序设计能力不再是计算机、通信、信息等相关理工科专业的学子必备的能力,而是新一代人才都必须具备的基本能力。程序设计的本质是数学,或者更直接地说是数学的应用。过去,程序设计非常看重计算能力。随着信息与网络科技的高速发展,计算能力不再是唯一的目标,在程序设计课程中着重加强学生计算思维(Computational Thinking,CT)的培养和训练。
在日常生活中,无论是大事还是小事,都是在解决问题,任何只要牵涉到“解决问题”的议题,都可以运用计算思维来解决。读书与学习就是为了培养我们在生活中解决问题的能力,计算思维是一种利用计算机的逻辑来解决问题的思维,就是一种能够将问题“抽象化”与“具体化”的能力,也是新一代人才都应该具备的素质。
我们可以这样说:“学习程序设计不等于学习计算思维,程序设计的过程就是一种计算思维的表现,而要学好计算思维,通过程序设计来学绝对是最佳的途径”。程序设计语言本身就只是工具,没有最好的程序设计语言,只有是否适合的程序设计语言。学习程序设计的目标绝对不是要把每位学习者都培养成为专业的程序设计人员,而是要帮助每个人建立系统化的逻辑思维模式。

1.1.1 计算思维的内容

2006年,美国卡内基·梅隆大学的Jeannette M. Wing教授首次提出了“计算思维”的概念,她提出计算思维是现代人的一种基本技能,所有人都应该积极学习,随后谷歌(Google)公司也为教育者开发了一套计算思维课程(Computational Thinking for Educators),这套课程提出了培养计算思维的4部分,分别是分解(Decomposition)、模式识别(Pattern Recognition)、模式概括与抽象(Pattern Generalization and Abstraction)以及算法(Algorithm)。虽然这并不是建立计算思维唯一的方法,不过通过这4部分我们可以更有效地进行思维能力的训练,不断使用计算方法与工具解决问题,进而逐渐养成我们的计算思维习惯。虽然这并不是建立计算思维的唯一方法,不过通过这4部分我们能更有效率地拓展思维,提高使用计算方法与工具解决问题的能力,最终建立计算思维。也就是要将这4部分进行系统的学习与组合,并使用计算机来协助问题的解决(参考图1-2)。在后面的章节我们来详细说明。

image.png

1.1.2 分解

许多人在编写程序或解决问题时,对于问题的分解(Decomposition)不知道从何处着手,将问题想得太庞大,如果对一个问题不能进行有效分解,就会很难处理。将一个复杂的问题分割成许多小问题,把这些小问题各个击破,小问题全部解决之后,原本的大问题也就解决了。
下面我们以一个实际的例子来说明。如果有8幅非常难画的图,我们可以把它们分成2组各4幅图来完成,如果还是觉得太复杂,继续再分成4组,每组各两幅图来完成,采用相同模式反复分割问题(如图1-3所示),这就是最简单的分治法(Divide and Conquer)的核心思想。

image.png

例如我们有一台计算机的部件出现故障了,如果将整台计算机逐步分解成较小的部分,对每个部分的各个硬件部件进行检查,就容易找出有问题的部件。再例如一位警察在思考如何破案时,需要将复杂的问题细分成许多小问题。经常编写程序的人在遇到问题时会考虑所有的可能性,把问题逐步分解,久而久之,这种逻辑思维的习惯就成了这些人的思考模式了,如图1-4所示。

image.png

1.1.3 模式识别

在把一个复杂的问题分解之后,我们常常可以发现小问题中有共同的属性以及相似之处,在计算思维中,这些属性被称为“模式”(Pattern)。模式识别是指在一组数据中找出特征(Feature)或规则(Rule),用于对数据进行识别与分类,以作为决策判断的依据。在解决问题的过程中找到模式是非常重要的,模式可以让问题的解决更为简化。当问题具有相同的特征时,它们能够被更简单地解决,因为存在共同模式时,我们可以用相同的方法解决此类问题。
举例来说,在知道怎么描述一只狗之后,我们可以按照这种模式轻松地描述其他狗,例如狗都有眼睛、尾巴与4只脚,不一样的地方是每只狗或多或少地有其独特之处(如图1-5所示),识别出这种模式之后,便可用这种解决办法来应对不同的问题。因为我们知道所有的狗都有这类属性,当想要画狗的时候便可将这些共同的属性加入,这样就可以很快地画出很多只狗。

image.png

1.1.4 模式概括与抽象

模式概括与抽象在于过滤以及忽略不必要的特征,让我们可以集中在重要的特征上,这样有助于将问题抽象化,通常这个过程开始会收集许多数据和资料,通过模式概括与抽象把无助于解决问题的特性和模式去掉,留下相关的以及重要的共同属性,直到我们确定一个通用的问题以及建立如何解决这个问题的规则。
“抽象”没有固定的模式,它会随着需要或实际情况而有所不同。例如,把一辆汽车抽象化,每个人都有其各自的分解方式,像是车行的业务员与修车技师对汽车抽象化的结果就可能会有差异(如图1-6所示)。
车行业务员:轮子、引擎、方向盘、刹车、底盘。
修车技师:引擎系统、底盘系统、传动系统、刹车系统、悬吊系统。

image.png

1.1.5 算法

算法是计算思维4个基石中的最后一个,不但是人类使用计算机解决问题的技巧之一,也是程序设计中的精髓,算法常出现在规划和设计程序的第一步,因为算法本身就是一种计划,每一条指令与每一个步骤都是经过规划的,在这个规划中包含解决问题的每一个步骤和每一条指令。
在日常生活中有许多工作可以使用算法来描述,例如员工的工作报告、宠物的饲养过程、厨师准备美食的食谱、学生的课程表等。如今我们几乎每天都要使用的各种搜索引擎都必须借助不断更新的算法来运行,如图1-7所示。

image.png

在韦氏辞典中,算法定义为:“在有限的步骤内解决数学问题的程序。”如果运用在计算机领域中,我们也可以把算法定义成:“为了解决某项工作或某个问题,所需要有限数量的机械性或重复性的指令与计算步骤。”
在计算机中,算法更是不可或缺的重要一环。下面讨论的内容包括计算机程序常涉及算法的概念和定义。在认识算法的定义之后,我们再来看看算法所必须符合的5个条件(参考图1-8和表1-1)。

image.png

在认识算法的定义与条件后,我们接着来思考:该用什么方法来表达算法最为适当呢?其实算法的主要目的在于让人们了解所执行的工作的流程与步骤,换句话说,算法是描述如何解决问题的办法,因而只要能清楚地体现算法的5个条件,即可清晰地表达算法。
常用的算法一般可以用中文、英文、数字等文字来描述,也就是使用文字或语言语句来说明算法的具体步骤,有些算法则是使用可读性高的高级程序设计语言(如Python、C、C++、Java等)或者伪语言(Pseudo-Language)来描述或说明的。

image.png

流程图(Flow Diagram)是一种相当通用的算法表达方式,就是使用某些特定图形符号来表示算法的执行过程。为了让流程图具有更好的可读性和一致性,目前较为通用的是ANSI(美国国家标准协会)制定的统一图形符号。假如我们要设计一个程序,让用户输入一个整数,而这个程序可以帮助用户判断输入的这个整数是奇数还是偶数,那么这个程序的流程图大致如图1-9所示。

image.png

1.2 进入程序设计的奇幻世界

程序设计语言其实是一种人类用来和计算机进行沟通的语言,也是用来指挥计算机进行运算或执行任务的指令集合。许多不懂计算机的人可能会把程序想象成十分深奥难懂的技术文件,其实程序只是由一系列合乎程序设计语言语法规则的指令所组成的,程序设计就是编写程序指令或程序代码来指挥计算机辅助我们人类完成各项工作。

1.2.1 程序设计语言的分类

随着程序设计语言不断地发展和演进,成就了今日计算机上各种各样软件的蓬勃发展。我们可以把程序设计语言分为主要的三大类:机器语言(Machine Language)、汇编语言(Assembly Language)和高级语言(High-Level Language)。每一代的程序设计语言都有其特色,并且朝着易于使用、调试与维护功能更强的目标不断发展和提升。另外,每一种语言都有其专有的语法、特性、优点以及相关的应用领域。就以机器语言为例,它是最低级的程序设计语言,是以0与1二进制数的方式直接将指令(机器代码)输入计算机,因此在指令级的数据处理上非常高效,但是编程效率最低。
汇编语言则是把以二进制数表示的数字指令用有意义的英文字母、字符表示的指令集来替代,方便人类的记忆与使用。不过,汇编语言编写的程序必须通过汇编器(Assembler)将汇编语言的指令转换成计算机可以识别的机器语言。汇编语言和机器语言相对于高级语言,统称为低级语言(Low-Level Language)。
由于汇编语言与机器语言不易于阅读,因此又产生了一些以英语单词为关键字的程序设计语言,它们被称为高级语言,例如BASIC、FORTRAN、COBOL、PASCAL、Java、C、C++等。高级语言比较符合人类自然语言的形式,也更加容易理解,并提供了程序的控制结构、输入输出指令。当使用高级语言编写完程序之后,在执行前必须先用编译器(Compiler,或称为编译程序)或解释器(Interpreter,或称为解释程序)把高级语言程序转换成汇编语言或机器语言。因此,相对于汇编语言,高级语言在执行效率上要低一些。不过,高级语言的可移植性比汇编语言高,可以在不同架构或硬件平台的计算机上执行。程序设计语言按照“翻译”方式可分为两种,分别说明如下:

  • 编译型语言

所谓编译型语言,就是使用编译器(Compiler)将程序代码翻译为目标程序。编译器可将源程序分成几个阶段转换为机器可读的可执行文件(目标程序),不过编译器必须先把源程序读入主存储器后才可以开始编译。每当源程序被修改一次,就必须重新经过编译器的编译过程,才能保持其可执行文件为最新的。经过编译后所产生的可执行文件,在执行中不必再“翻译”,因此执行效率较高。例如C、C++、PASCAL、FORTRAN等语言都是编译型语言。如图1-10所示为编译型语言编译与执行过程的示意图。


image.png

  • 解释型语言

所谓解释型语言,是指使用解释器对高级语言的源代码逐行进行“翻译”(解释),每解释完一行程序语句后,才会解释下一行程序语句,如图1-11所示。如果在解释的过程中发现了错误,解释动作就会立刻停止。由于使用解释器解释的程序每次执行时都必须再解释一次,因此执行速度较慢。BASIC、LISP、PROLOG等高级语言都是解释型语言。

image.png

1.2.2 程序设计的流程

有些人往往认为程序设计的主要目的就是通过“运行”得出结果,而忽略了程序运行的效率与程序日后维护的成本。学习程序开发的最终目的是学会如何组织众多程序设计人员共同参与来设计一套大型且符合用户需求的复杂系统。一个程序的产生过程可分为五大设计步骤,如表1-2所示。

image.png

1.2.3 程序编写的原则

至于在程序设计中要使用何种程序设计语言,通常可根据主客观环境的需要进行选择,并无特别的规定。一般从4个方面来评判程序设计语言的优劣。

  • 可读性(Readability)高:阅读与理解都相当容易。
  • 平均成本低:成本考虑不局限于编码的成本,还包括执行、编译、维护、学习、调试与日后更新等的成本。
  • 可靠性高:所编写出来的程序代码稳定性高,不容易产生副作用(Side Effect)。
  • 可编写性高:针对需求所编写的程序相对容易。

以下是我们在编写程序时应该注意的三项基本原则:
1. 适当的缩排
缩排用来区分程序的层级,使程序代码易于阅读,像是在主程序中包含子程序区块,或者子程序区块中又包含其他的子程序区块时,都可以通过缩排来区分程序代码的层级,如图1-12所示。

image.png

2. 明确的注释
对于程序设计人员而言,在适当的位置加入足够的注释往往可以作为评断程序设计优劣的重要依据之一。尤其当程序结构复杂而且程序语句较多时,适时在程序中加入注释不仅可提高程序的可读性,而且可以让其他程序设计人员能更清楚地理解这段程序代码的作用。如下这段程序就带有非常清楚的注释:

01    import java.util.*;
02    public class ch2_02 {
03        public static void main(String[] args) {
04            //声明变量
05            int intCreate=1000000;//产生随机数的次数
06            int intRand;          //产生的随机数
07            int[][] intArray=new int[2][42];//存放随机数的数组
08            //将产生的随机数存放到数组中
09            while(intCreate-->0) {
10                intRand=(int)(Math.random()*42);
11                intArray[0][intRand]++;
12                intArray[1][intRand]++;
13            }
14            //对intArray[0]数组进行排序
15            Arrays.sort(intArray[0]);
16            //找出出现次数最多的前6个数
17            for(int i=41;i>(41-6);i--) {
18            //逐一检查次数相同者
19                for(int j=41;j>=0;j--) {
20                //当次数符合时打印输出
21                if(intArray[0][i]==intArray[1][j]) {
22                    System.out.println("随机数号码"+(j+1)+"出现"+
intArray[0][i]+"次");
23                    intArray[1][j]=0; //将找到的数值对应的次数归零
24                    break;         //中断内循环,继续外循环
25                }
26             }
27          }
28       }
29    }

3. 有意义的命名
除了使用明确的注释来辅助程序的阅读外,还要在程序中大量使用有意义的标识符(包括变量、常数、函数、结构等)命名原则。如果使用不恰当的名称,在程序编译时就可能会无法顺利地进行编译,或者造成程序在运行时出现错误。

1.3 程序设计逻辑的简介

每位程序设计人员就像一位艺术家一样,会有不同的设计逻辑,不过由于计算机是很严谨的高科技工具,不能像人脑一样天马行空,对于一个好的程序设计人员而言,还是必须遵循某些规范,符合程序设计的逻辑概念,这样才能让程序代码具备可读性与日后的可维护性。就像早期的结构化设计,时至今日已将传统程序设计的逻辑转化成面向对象的设计逻辑,这都是程序设计人员在编写程序时要遵循的大方向。

1.3.1 结构化程序设计

在传统程序设计的方法中,主要有“自上而下法”与“自下而上法”两种。所谓“自下而上法”,是指程序设计人员先编写整个程序需求中最容易的部分,再逐步展开来完成整个程序。“自上而下法”则是将整个程序需求从上到下、从大到小逐步分解成较小的单元(或称为模块(Module)),这样使得程序设计人员可针对各个模块分别开发,不但减轻了设计人员的负担,而且程序的可读性更高,对于日后维护也容易许多。
结构化程序设计的核心思想是“自上而下的设计”与“模块化的设计”。例如,在PASCAL语言中,这些模块被称为过程(Procedure),在C语言中被称为函数(Function)。通常“结构化程序设计”具备三种控制流程,而对于一个结构化程序,无论其结构如何复杂,都可使用这三种基本的控制流程来编写,如表1-3所示。

image.png
image.png

1.3.2 面向对象程序设计

面向对象程序设计(Object-Oriented Programming,OOP)的主要设计思想是将存在于日常生活中随处可见的对象(Object)概念应用在软件开发模式(Software Development Model)中。面向对象程序设计让我们在程序设计中能以一种更生活化、可读性更高的设计思路来进行程序的开发和设计,并且所开发出来的程序更容易扩充、修改和维护。
在现实生活中充满了形形色色的物体,每个物体都可视为一种对象。我们可以通过对象的外部行为(Behavior)和内部状态(State)来进行详细的描述。外部行为代表此对象对外所显示出来的运行方式,内部状态则代表对象内部各种特征的当前状况,如图1-13所示。

image.png

例如,我们今天想要自己组装一台计算机,而目前我们人在外地,因为配件不足,找遍了当地所有的计算机配件公司仍找不到所需要的配件,假如我们必须到北京的中关村来寻找所需要的配件。也就是说,一切的工作必须一步一步按照自己的计划分别到不同的公司寻找我们所需的配件。试想,即使节省了不少购买配件的成本,但是时间成本的代价却相当大。
如果换一个角度,假使我们不必理会配件货源如何获得,完全交给计算机公司全权负责,那么事情便会简单许多。我们只需填好一份配置的清单,该计算机公司便会收集好所有的配件,然后寄往我们所指定的地方,至于该计算机公司如何找到货源,便不是我们所要关心的事了。我们要强调的概念便在于此,只要确立每一个配件公司是一个独立的个体,该独立个体有其特定的功能,而各项工作的完成仅需在各个独立的个体之间进行消息(Message)交换即可。
面向对象程序设计的概念就是认定每一个对象是一个独立的个体,而每个独立的个体有其特定的功能,对我们而言,无须理解这些特定功能如何实现这个目标的具体过程,只需要将需求告诉这个独立个体,如果该个体能独立完成,便直接将此任务交给它即可。面向对象程序设计的重点是强调程序的可读性(Readability)、可重复使用性(Reusability)与扩展性(Extension)。
面向对象语言本身还具备三种特性(如图1-14所示),下面逐一介绍。

image.png

  • 封装

封装(Encapsulation)就是利用“类”来实现“抽象数据类型”(ADT)。类是一种用来具体描述对象状态与行为的数据类型,也可以看成一个模型或蓝图,按照这个模型或蓝图所产生或创建的实例(Instance)就称为对象。类和对象的关系如图1-15所示。

image.png

所谓“抽象”,就是将代表事物特征的数据隐藏起来,并定义一些方法(Method)来作为操作这些数据的接口,让用户只能接触到这些方法,而无法直接使用数据,也符合信息隐藏(Information Hiding)的要求,而这种自定义的数据类型就称为“抽象数据类型”。而传统程序设计的概念则必须掌握所有的来龙去脉,就程序开发的时效性而言,传统程序设计便要大打折扣。

  • 继承

继承(Inheritance)是面向对象程序设计语言中最强大的功能之一,因为它允许程序代码的重复使用(Code Reusability),同时可以表达树结构中父代与子代的遗传现象。继承类似于现实生活中的遗传,允许我们定义一个新的类来继承现有的类(Class),进而使用或修改继承而来的方法(Method),并可在子类(SubClass)中加入新的成员数据与成员方法。在继承关系中,可以把它单纯视为一种复制(Copy)的操作。换句话说,当程序开发人员以继承机制声明新增的类时,它会先将所引用的父类中的所有成员完整地写入新增的类中。类继承关系的示意图如图1-16所示。

image.png

  • 多态

多态(Polymorphism)是面向对象程序设计的重要特性,也被称为“同名异式”。多态的功能可让软件在开发和维护时实现充分的扩展性。多态,按照英文单词字面的解释就是一样东西同时具有多种不同的形态。在面向对象程序设计语言中,多态的定义简单来说是利用类的继承关系先创建一个基类对象。用户通过对象的继承声明将此对象向下继承为派生类对象,进而控制所有派生类的“同名异式”成员方法。
简单地说,多态最直接的定义就是让具有继承关系的不同对象可以调用相同名称的成员方法,并产生不同的运行或计算结果。

1.3.3 在面向对象程序设计中的其他关键术语

  • 对象

对象(Object)可以是抽象的概念或一个具体的东西,包括数据(Data)及其相应的操作或运算(Operation),或称为方法(Method)。对象具有状态(State)、行为(Behavior)与标识(Identity)。
每一个对象均有其相应的属性(Attribute)及属性值(Attribute Value)。例如,有一个对象称为学生,“开学”是一条消息,可传送给这个对象。而学生有学号、姓名、出生年月日、住址、电话等属性,当前的属性值便是其状态。学生对象的操作或运算行为则有注册、选修、转系、毕业等,学号则是学生对象的唯一识别编号(对象标识,OID)。

类(Class)是具有相同结构和行为的对象集合,是许多对象共同特征的描述或对象的抽象化。例如,小明与小华都属于人这个类,他们都有出生年月日、血型、身高、体重等类的属性。类中的一个对象有时就称为该类的一个实例(Instance)。

  • 属性

属性(Attribute)用来描述对象的基本特征及其所属的性质,例如一个人的属性可能会包括姓名、住址、年龄、出生年月日等。

  • 方法

方法(Method)是对象的动作与行为,我们在此以人为例,不同的职业,其工作内容就会有所不同,例如学生的主要工作为学习,而老师的主要工作则为教书。

1.4 Java语言的特性

Java语言源于1991年Sun Microsystem(太阳计算机系统,简称Sun公司)公司内部一项名为Green的开发计划,是为了编写控制消费类电子产品软件所开发出来的小型程序设计语言系统,不过这项计划并未获得市场的肯定,因而沉寂了一段时间。但是,不久之后,由于因特网的蓬勃发展,谁也没有想到当初只是为了在不同平台系统下执行相同软件而开发的语言工具,却意外地引发了一股技术发展的潮流。于是,Sun公司对Green计划重新进行了评估并做了修正,在1995年正式向外界发表名为“Java”的程序设计语言系统。
Java之所以会成为令人瞩目的程序设计语言,主要原因之一就是因为Java具有“支持Web”的功能,可以在Web平台上设计和编写出“互动性高”与“跨平台”的程序。再加上Java语言面向对象、支持泛型程序设计的特性,因而如今Java语言已经深入日常生活中的各个领域,例如IC卡(通用智能卡)、金融卡(如银行智能卡)、身份识别证等应用。另外,还有智能设备、无线通信等应用,以及开发大规模的商业应用等各个方面,我们都可以看到无所不在的Java应用。
Java是一种面向对象的高级程序设计语言,Java语言的应用范围涵盖因特网、网络通信及智能通信设备,并成为企业构建数据库的较佳开发工具。Java语言的风格十分接近C++语言,在保有C++语言面向对象技术核心的同时,还舍弃了C++语言中容易引起错误的指针,并以引用功能取而代之,经过多次的修正、更新,Java逐渐成为一种功能完备的、面向对象的程序设计语言。Sun公司就曾提到Java语言的几项特点:简单性、面向对象、解释性、严谨性、跨平台性、高性能、多线程。

1.4.1 简单性

Java语法源于C++语言,因此它的指令和语法十分简单,我们只要能了解简单英文单词与语法的概念,就能进行程序设计并完成运算处理的工作。Java具有以下两点简单特性:
(1)简化了语法:Java简化了C++中的一些用法,并舍弃了不常用的语法,如容易造成内存存取问题的指针(Pointer)和多重继承的部分。
(2)垃圾回收机制(Garbage Collection):Java使用了垃圾回收机制,当程序中有不再使用的资源时,系统会自动释放其占用的内存空间,从而减少程序设计者自行管理内存资源不足的困扰。

1.4.2 跨平台性

“跨平台性”表示Java的程序不依赖于任何一个特定的硬件平台,Java程序的特点是“一次编译、到处执行”,也就是说,Java程序在编译后可以不用再经过任何更改就可以在任何支持Java的硬件设备或平台上顺利执行。基本上,无论是哪一种操作系统(Windows、UNIX/Linux或Solaris)、哪一种硬件平台(PC、个人数字设备、Java Phone或智能家电等),只要它们搭载有JVM(Java Virtual Machine,Java虚拟机)执行环境,即可顺利执行已事先编译的Java Bytecode(字节码),如图1-17所示。也就是说,执行Java应用程序必须先安装Java Runtime Environment(JRE),JRE内部包含JVM以及一些标准的Java类库。通过JVM才能在系统中执行Java应用程序(Java Application)。
当程序设计人员设计和编写好的Java源程序通过不同操作系统平台上的编译器(例如Intel的编译器、Mac OS的编译器、Solaris的编译器或者UNIX/Linux的编译器)进行编译后,产生相同的Java虚拟机字节码(Byte Code),然后这些Java虚拟机字节码再通过不同操作系统平台的解释器,翻译成该系统平台的机器码。因此,Java是建立在软件平台上的程序设计语言,而让Java实现跨平台运行的主要因素就是JVM(Java虚拟机)和Java API。

image.png

1.4.3 解释型

Java源程序(Java Source)必须通过内建的实用程序javac.exe来进行编译,把Java程序的源代码编译成目标执行环境中可识别的字节码(Bytecode),字节码是一种虚拟的机器语言,而在目标环境中的执行是通过实用程序java.exe对字节码以解释方式按序执行的,这个过程如图1-18所示。

image.png

1.4.4 严谨性

Java程序是由类与对象所组成的,编程人员可将程序分割为多个独立的代码段,并将相关的变量与函数写入其中,相当严谨地分开处理程序的各种不同执行功能。

1.4.5 例外处理

例外(Exception)是一种运行时的错误,在传统的计算机程序设计语言中,当程序发生错误时,程序设计人员必须自行编写一部分程序代码来进行错误的处理。不同于其他高级程序设计语言,Java语言会在运行期间发生错误的时候自动抛出例外对象以便进行相关的处理工作。我们可使用try、catch与final三个例外处理程序区块,以“专区专责”的方式解决程序运行期间可能遇到的错误。

1.4.6 多线程

Java内建了Thread类,其中包含各种与线程处理相关的方法(Method),真正实现同一时间执行多个程序运算。多线程是在每一个进程(Process)中包含多个线程(Thread),将程序分割成一些独立的工作,如果运用得当,多线程可以大幅度提升系统运行的性能。

1.4.7 自动垃圾回收

相对于大多数C++编译器不支持垃圾回收机制,Java语言有自动垃圾回收(Garbage Collection)机制,这个特点受到许多从使用C++语言转到使用Java语言的程序设计人员的欢迎。这是因为许多C++程序设计人员在进行程序初始化操作时,必须在主机内存堆栈中分配一块内存空间,当程序运行结束后,必须通过指令的下达来释放被分配的内存空间。不过,一旦程序设计人员忘记回收这块内存空间,就会造成内存泄漏(Memory Leak)而浪费内存空间。因为Java语言有自动垃圾回收机制,所以当一个对象没有被引用时,就会自动释放这个对象所占用的内存空间,从而避免内存泄漏的现象。

1.4.8 泛型程序设计

泛型程序设计(Generic Programming)是程序设计语言的一种风格。泛型在C++中其实就是模板(Template),只是Swift、Java和C#采用了泛型(Generic)这个更广泛的概念。泛型可以让程序设计人员根据不同数据类型的需求编写出适用于任何数据类型的函数和类。我们或许可以这么说:泛型是一种类型参数化的概念,主要是为了简化程序代码,降低日后程序的维护成本。泛型语法让我们在编写Java程序时可以指定类或方法来支持泛型,而且在语法上更为简洁。Java 语言中引入泛型的功能后,这项重大改变使得语言、类型系统和编译器有了许多不同以往的变化,其中许多重要的类(例如集合框架)已经成为泛型化的类了,它带来了很多好处,还提高了Java程序的类型安全。

1.5 Java的开发环境版本与架构

在Java SE 11之前的几个版本的改版时间间隔都较短,例如2017年9月21日,Oracle公司发布了Java SE 9,接着大概过了半年时间,Oracle公司于2018年3月21日发布了Java SE 10,又差不多过了半年时间,Oracle官方于2018年9月25日正式发布了Java SE 11(Java SE Development Kit 11)。

1.5.1 程序开发工具介绍

Java的开发工具分成JDK和IDE两种:
(1)Java开发工具(Java Development Kit,JDK)是一种“简易”的程序开发工具,仅提供编译(Compile)、执行(Run)及调试(Debug)功能。
(2)集成开发环境(Integrated Development Environment,IDE)集成了编辑、编译、执行、测试及调试功能,例如常见的Borland Jbuilder、NetBeans IDE、Eclipse、Jcreator、Java Editor等。

1.5.2 JDK的下载与安装

由于Java支持各种操作系统,因此可根据自己使用的操作系统版本来下载对应的安装程序。目前大部分的开发环境都必须另行安装JDK,不过也有部分集成开发环境在安装时会同时安装JDK。下面我们将以Windows 10/Windows 7平台来示范JDK 11的安装过程。首先到Java的官方网站(http://www.oracle.com/technetwork/java/index.html )下载最新版的JDK,如图1-19所示。

image.png

在图1-19所示的Java官方网站中,单击网页右侧的“Java SE 11.0.1”链接,接着会显示出如图1-20所示的网页。

image.png

在图1-20所示的网页中单击“Java SE Downloads”下方的“DOWNLOAD”按钮(框中的按钮),随后会显示出如图1-21所示的网页,读者可以根据网页中的提示下载JDK。要开始下载,可选中如图1-21所示的网页中的Accept License Agreement单选按钮。

image.png

笔者根据自己的操作系统下载的是Windows版本的JDK,文件名为“jdk-11.0.1_windows-x64_ bin.exe”,如图1-22所示。

image.png

下载完安装文件后,单击“运行”按钮,即可执行该安装程序,如图1-23所示。

image.png

JDK 11的安装向导界面如图1-24所示。

image.png

image.png直接在如图1-24所示的安装向导界面中单击“下一步”按钮,随即显示出如图1-25所示的安装界面,接着选择JDK安装组件及安装路径,默认的安装路径是“C:Program FilesJavajdk-11.0.1”。建议使用这个默认设置,接下来单击“下一步”按钮,开始安装。

image.png

image.png接着就会开始进行文件的安装、复制,这个部分可能需要几分钟,请耐心等候。当安装完成并完成相应的设置后,就会出现安装完成的界面,如图1-26所示,单击“关闭”按钮,即可完成JDK的安装。

image.png

1.5.3 设置JDK搜索路径的环境变量

安装工作完成后,为了在“命令提示符”窗口使用JDK的各项工具程序,例如编译器javac.exe、执行程序java.exe,就需要修改或设置系统内相关路径的环境变量。我们必须在PATH环境变量中添加设置值“C:Program FilesJavajdk-11.0.1”(注意具体的版本不同,这个设置的最后部分稍有不同)。
单击Windows 10任务栏的“搜索”按钮,在搜索框中输入“控制面板”,并单击搜索结果中的“控制面板”以启动“控制面板”程序,如图1-27所示。

image.png

在启动的“控制面板”窗口单击“系统和安全”选项,如图1-28所示。

image.png

出现如图1-29所示的窗口后,再单击“系统”选项。

image.png

出现如图1-30所示的窗口后,单击“高级系统设置”选项。

image.png

随后就会看到如图1-31所示的“系统属性”窗口,在“高级”页签中单击“环境变量”按钮(注意:Windows 7的用户可从“控制面板”中的“系统”的“高级系统设置”进入类似于图1-31所示的“系统属性”窗口)。

image.png

在如图1-32所示的“环境变量”对话框下方的“系统变量”框中选择“Path”系统变量,并单击“编辑”按钮。

image.png

显示出如图1-33所示的界面后,再单击“新建”按钮,并在最后输入“C:Program FilesJavajdk-11.0.1bin”路径。

image.png

如果是Windows 7的用户,那么先找到系统变量的Path部分,单击“编辑”按钮,在“变量值”输入字段的末尾加上“;”,然后加上“C:Program FilesJavajdk-11.0.1bin”,随后依次单击三次“确定”按钮,就可以设置好JDK搜索路径对应的环境变量。
如果我们要验证Path环境变量是否设置成功,可以右击Windows 10操作系统左下角的Windows窗口图标,随后会出现如图1-34所示的菜单。

image.png

单击菜单中的“Windows PowerShell”或者“命令提示符”,就会启动“Windows PowerShell”窗口或“命令提示符”窗口,在其中输入“javac -version”命令,该命令可以显示出当前系统中javac的版本信息,如图1-35所示。

image.png

如果可以看到如图1-35所示的版本信息,就表示环境变量Path设置成功,因为当前笔者计算机的工作文件夹是“C:UsersJun”,所以在这个路径(或称为文件夹)并没有javac.exe工具程序,当操作系统在这个路径找不到javac.exe时,它就会自动根据环境变量Path所指定的路径搜索javac.exe。而我们刚才已在环境变量Path中新建了一个“C:Program FilesJavajdk-11.0.1bin”的路径,操作系统可以在这个路径下找到javac.exe工具程序,因此可以顺利执行“javac -version”命令,从而列出如图1-35所示的“javac 11”版本信息。
如果我们在设置环境变量的过程中不小心输入了错误的路径名称,当执行上述“javac -version”命令时,就会显示出如“'javac'不是内部或外部命令,也不是可运行的程序或批处理文件”的错误提示信息,这时我们就要仔细检查在设置过程中有哪个步骤设置错了,或者输入了不正确的路径名称。

image.png

1.5.4 Java程序结构的解析

接着我们将分别使用Windows内建的记事本(Notepad)应用程序来编辑一个简单的Java程序,并说明Java程序的基本结构。

01    /*文件:CH01_01*/
02    //程序公有类
03    public class CH01_01{
04    //主要执行区块
05        public static void main(String[ ] args){
06            //程序语句
07            System.out.println("我的第一个Java程序");
08        }
09    }

【程序的执行结果】
首先进入“命令提示符”窗口,假设笔者的Java范例程序存放的文件夹在D驱动器中,完成的操作指令说明如下:

D: (接着按【Enter】键, 表示切换到D驱动器)
cd Java (接着按【Enter】键, 表示切换到Java文件夹,cd命令的功能就是改变目录或文件夹)
cd ch01 (接着按【Enter】键,表示切换到ch01文件夹,cd命令的功能是改变目录或文件夹)
javac CH01_01.java (接着按【Enter】键, 表示将CH01_01.java源程序编译成类文件)
java CH01_01(接着按【Enter】键,表示执行CH01_01类文件,并将执行结果输出)

如图1-36所示为完整的操作步骤。

image.png

【程序的解析】
第01、02行:程序的注释说明文字。其中“//”是Java的单行注释符号,此符号后的同行语句在编译和运行时会被略过,只被视为注释文字而已;而“/”与“/”属于多行注释标签,在注释起始处使用“/”,结尾处使用“/”,其中所包含的文字同样会被视为注释而被编译器略过。
第03行:定义程序的公有(public)类。每一个Java程序内最多只能拥有一个公有类,并且此类的名称必须与程序文件名一致才能被正确地编译。
第03~09行:程序中任何类或方法的执行语句都必须使用“{”与“}”符号包括起来,否则会引发程序的编译错误。
不过,Java SE 11增强了Java编译和解释器的功能,使之能够执行单个文件的Java源代码程序,应用程序可以直接从源代码开始运行。单个文件的程序常见于小型工具或由Java入门学习者编写。而且,单个源程序文件有可能会编译成多个类文件(.class),这会增加给程序打包的额外成本,基于这些原因,在执行Java程序之前进行编译,这个步骤就显得不必要了。
因此,在前面介绍的把程序编译成Java类的编译操作的这个步骤,在新版的JDK 11已可以省去。也就是说,即使没有编译成类文件(.class),在JDK 11的开发环境下,通过Java SE 11所增强的java解释器也可以直接解释执行单个文件的Java源代码程序。其命令格式如下:

java 程序名称.java

前面的范例程序,即使没有事先将Java源代码程序编译成类文件,也可以通过增强的java解释器直接解释执行CH01_01.java源代码程序。命令如下:

java CH01_01.java(接着按【Enter】键,直接执行CH01_01.java的源代码程序)

如图1-37所示为完整的操作步骤。

image.png

在此特别说明一下,为了兼顾学习Java 10、Java 9、Java 8或Java更早版本的读者也能选用本书学习Java语言,在本书的后续章节中,我们将保留通用的范例程序执行过程,即先通过javac编译器将Java源代码程序编译成类文件(.class),再通过java解释器执行这些编译生成的字节码。
在了解了Java程序的执行操作之后,下面开始学习“如何编写程序”。要编写出良好的程序,第一步是了解“程序的基本结构”。
【Java程序的基本结构】

01    /*文件:CH01_01*/
02    //程序公有类
03    public class CH01_01{
04    //主要执行区块
05        public static void main(String[ ] args){
06            //程序语句
07            System.out.println("我的第一个Java程序");
08        }
09    }

第03行:程序文件名必须与程序中公有类(public class)的名字相同,意思是说上述范例程序在存盘时,文件名必须命名为“CH01_01.java”。只有如此,在Windows操作系统的“命令提示符”窗口中或者其他Java集成开发环境中进行编译时,才不会发生编译错误。另外,一个标准的Java程序基本上至少包含一个类。如果将其中一个类声明成public,那么它的文件名必须与该程序名称相同。也就是说,在一个.java文件内,如果有一个以上的类,只能有一个public类。但是,如果在.java文件中,没有一个类是public,那么该Java程序的命名可以不必和类名称相同。
第05行:main()是Java程序的“入口点”,是程序执行的起点,要执行的程序语句区块必须编写在此函数或方法的大括号内“{ }”。程序语句区块执行的顺序是“按序”执行,直到出现右大括号。
【main( )的语法】

public static void main (String args[ ] ) {
程序语句区块;
}

其中,main( )声明成public、static、void,这些修饰词代表的意思分别是“公有”“静态”“无返回值”,意思是说“main( )是一个公有、静态的函数或方法,而且没有返回值”,关于这些修饰词的意义,我们在后续章节会进一步说明。
第07行:这个部分有两点要说明:第一点是“println( )”输出显示的部分;第二点是“;”分号的重要性。输出显示的部分:“System.out.println( )”是Java语言的标准输出,使用的是System类中的子类out,其中子类的println( )是在屏幕显示输出的方式。输出的内容是括号“( )”中所指定的字符串(string),字符串的内容以一对“"”符号包括起来的。out类中的输出方式除了println( )外,还有print( ),二者的差别在于println( )具有换行显示的功能,print( )则不具有换行显示的功能。
【标准输出语句】

System.out.println ("Welcome to Java World"); // println()具有换行显示功能
System.out.print ("Welcome to Java World");   // print()不具有换行显示功能

“//”程序注释:程序注释对于程序的编写是很重要的,注释能够使编写程序的作者或其他人清楚地了解这段程序以及整个程序的设计目的,对后续的维护有很大的帮助。其中“//”适用于单行或简短的程序注释;“/”和“/”则适用于多行或需要详细解释的注释。
“;”分号:在Java程序设计中,每一行程序代码编写完毕后,在程序语句的末尾都必须加上“;”分号,以明确说明这条程序语句到此已经结束了。假如没有加上分号,在编译时就会发生错误,这是初学者经常疏忽的地方。
至于程序代码编写格式的问题,Java语言其实没有一定的规范,因为Java语言属于自由格式(Free-format)的编写方式,只要程序代码容易阅读,程序语法和逻辑无误,就可以正确执行。不过,适当地将程序代码“缩排”或“换行”可以让程序结构清楚且容易理解。
【用记事本(Notepad)应用程序编辑Java程序】
程序代码可参考图1-38。

image.png

当使用记事本应用程序保存文件时,请在“保存类型”选项列表中选择“所有文件”,并将它命名为和程序中的公有类(声明为public的类)相同的名称。在此范例程序中的公有类名称为“CH01_01”,所以要将文件命名为CH01_01.java。注意,如果“保存类型”设置成“文本文件(*.txt)”,就会使实际的文件名变成CH01_01.java.txt,而这样命名的文件不是一个合法的Java程序文件,因而将无法被正常编译。

1.6 认识Java SE 11新增的功能

Java SE 11是一个长期支持版本(Long-Term Support,LTS)。LTS是软件产品生命周期的一种政策,特别是用于开源软件(Open Source Software,OSS,或称为开放源代码软件)的一种政策。开源软件是指源代码可以自由使用的一种计算机软件,这种软件的版权持有人在软件协议合约条文中保留一部分权利,并允许用户用于学习目的以及为持续提高软件质量而进行的修改和改进。
正因为Java SE 11是一种长期支持版本(LTS),它不仅延长了软件维护的周期,同时提升了所开发软件的可靠性,所以许多Java程序设计人员更加关注Java SE 11版本。
其实,对一位Java程序开发人员来说,JDK的更新工作相当重要,因为JDK更新不仅可以获取最新的安全更新版本,修复了程序“臭虫”(Bug),还可以通过JDK的更新得到开发软件所应有的性能优化。最新的 Java SE 11新增的功能包括Nest-Based Access Control(基于嵌套的访问控制)、Dynamic Class-File Constants(动态类文件常数)、HTTP Client(HTTP客户端)、ZGC:A Scalable Low-Latency Garbage Collector(可伸缩低延迟垃圾收集器)等重要特性。下面我们就几项特别的功能为大家摘要说明。

  • 从Java SE平台和JDK中删除Java EE和CORBA模块,并删除了JavaFX。其实,Java EE和CORBA模块从Java SE 9版本就归类为不推荐使用(deprecated)。Java EE平台提供了整套的Web服务技术,多年来,Java EE版本在不断“进化”,并加入了许多与Java SE无关的技术,这使得Oracle公司同时维护两个Java版本的困难度越来越大;再者,由于独立的Java EE版本由第三方网站提供,因此Java SE或JDK中就没有必要再提供Java EE了。另外,CORBA始于20世纪90年代,当前已经很少有人用CORBA开发Java应用程序,Oracle公司认为维护CORBA的成本已远远超过了保留它带来的好处,因此在JDK 11中一并删除了CORBA模块。
  • 升级现有平台的API以支持Unicode标准版10.0。注释:Unicode码是指“统一码、万国码”,以两个字节来表示,共有65536种组合,是ISO-10646 UCS(Universal Character Set,通用字符集)的子集。
  • HTTP客户端(标准)功能在JDK 9版本时引入并在JDK 10中得到了更新,现在java.net.http程序包提供了标准化的API。
  • Lambda表达式中隐式类型的形式参数允许使用保留类型名称var,例如:
(var x, var y) -> x.process(y)

等同于下面的表达式:

(x, y) -> x.process(y)

有关Lambda表达式的进一步说明,请大家参阅16.6节中有关Lambda表达式的介绍。

以下列出的是目前在JDK 11版本中的JDK 增强提案(JDK Enhancement Proposals,JEP)。
181: Nest-Based Access Control
309: Dynamic Class-File Constants
315: Improve Aarch64 Intrinsics
318: Epsilon: A No-Op Garbage Collector
320: Remove the Java EE and CORBA Modules
321: HTTP Client (Standard)
323: Local-Variable Syntax for Lambda Parameters
324: Key Agreement with Curve25519 and Curve448
327: Unicode 10
328: Flight Recorder
329: ChaCha20 and Poly1305 Cryptographic Algorithms
330: Launch Single-File Source-Code Programs
331: Low-Overhead Heap Profiling
333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)
336: Deprecate the Pack200 Tools and API
如果大家想要进一步了解上述“JDK增强提案”中新增功能的细节说明,建议查询这个网站,网址为https://jaxenter.com/jdk-11-jep-145675.html ,如图1-39所示。

image.png

课后习题

一、填空题
1.Java程序经编译器编译时会直接生成     ,然后通过各种平台上的Java虚拟机转换成机器码,才可以在各种平台的操作系统中执行。
2.     是计算机与人类沟通的最低级语言,是以0与1的二进制值方式直接将机器码指令或数值输入计算机。
3.Java的开发工具分为          两种。
4.所谓     ,表示Java语言的执行环境不偏向任何一个硬件平台。
5.     的主要用途是用来区分程序的层级,使得程序代码易于阅读。
6.结构化程序设计的核心思想就是          的设计。
7.继承可分为          
8.     是面向对象设计的重要特性,它展现了动态绑定的功能,也称为“同名异式”。
9.Java具备了     ,用户不需要在程序执行结束时来释放程序所占用的系统资源,Java执行系统会自动完成这项工作。
10.Java程序代码通过实用程序     来编译生成字节码。
11.Java内建了     类,这个类包含各种与线程处理相关的管理方法。
12.Java所谓的     的设计概念使得Java没有任何平台的限制。
13.如果main( )的类名称是Hello,那么该Java程序文件的名称为Hello.java。在“命令提示符”下编译这个程序的命令是     ;如果编译无误,那么在“命令提示符”下的执行命令是     。在JDK 11中,如果要略过编译成类文件的这个中间步骤,那么下达直接解释执行这个Java程序的命令为     
14.在执行Java程序时,对象可以分散在不同计算机中,通过网络来存取远程的对象,这种特性称为     
二、问答与实践题
1.请说明Java为什么不受任何机器硬件平台或任何操作系统的限制,而实现了跨平台执行的目的。
2.说明创建Java应用程序的整个流程图。
3.下列程序代码是否有误?如果有,请说明有错误的地方,并加以修正:

image.png

4.请简述程序设计语言的基本分类。
5.评断程序设计语言好坏的要素有哪些?
6.程序编写的三项基本原则是什么?
7.试简述Java语言的特性(至少三种)。
8.Java的开发工具可分成哪两种?
9.简述Java程序语言的起源。
10.试简述面向对象程序设计的三种重要特征。
11.请比较编译器的编译与解释器的解释两者之间的差异性。
12.试编写一个简单的Java程序,让它输出的结果为“今日事,今日毕”,如图1-40所示。

image.png

13.试编写一个简单的Java程序,它的输出结果如图1-41所示。

image.png

14.试编写一个简单的Java程序,它的输出结果如图1-42所示。

image.png

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:

华章出版社

官方博客
官网链接