Java语言入门基础教程详解(必看两万字)

Java编程基础教程

前言

在最受欢迎的程序设计语言排行榜上,Java语言已经连续数年位列榜首。“Write once, Run anywhere,(一次编写,到处可行)”,这是一种很有效率的编程方式。跨平台、完全面向对象、既适于单机编程也适合于Internet编程等特点,给Java语言注入了强大的生命力。而Java语言也取得了举世瞩目、全球公认的地位。

如今的时代,电子设备嵌入Java技术,Java智能卡海量发行,PC中广泛应用Java技术,电信运营商支持Java技术,Java开发人员数量也日增月长。另外,Java开发者锐意创新,将Java技术应用到各种领域,使得Java技术已经成为世界上最卓越的企业应用和移动应用开发平台之一。历史上从没有过像Java平台这样能够如此广泛地应用,许多公司和软件人员大量使用Java技术。

亲爱的读者,如果你是在校生,正在上Java程序设计这门课程,请你珍惜校园的时光,珍惜学习的机会,发挥你的聪明才智吧,Java已经是无处不在,你的努力也不会徒然。

目录

 Java语言入门篇
第一讲 Java语言快速入门 2
一、Java的起源和发展历程 2
二、Java语言的工作原理及特点 3
三、Java开发环境的建立 5
四、第一个Java程序的编译和运行 6
第二讲 Java中的数据类型和运算 11
一、Java输入/输出的初步运用 11
二、Java的标识符和保留字 12
三、Java的基本数据类型 13
四、Java基本数据类型转换 16
五、Java中的运算 18
第三讲 Java结构化编程 24
一、分支结构 24
二、循环结构 28
三、循环控制和循环嵌套 30
四、Java结构化编程综合 33

 

第一篇 Java语言入门篇

该篇既为无语言基础的读者准备,也为有语言基础的读者准备。对于前者,该篇需要精读和尽量充足的编程实练;对于后者,可作整理思路之用,并特别要分辨Java语言与其他编程语言某些方面的差异,以避免在以后的编程中犯低级错误。

在该篇中,安排了Java语言快速入门、Java中的数据和运算、Java结构化编程三讲。

“Java语言快速入门”简单介绍了Java的发展历程、Java语言的工作原理及特点、Java开发环境的建立等内容,并以实例说明了编译和运行Java程序的过程。

“Java中的数据和运算”,首先介绍了用Scanner扫描器从标准输入设备进行数据输入、System.out.println实现数据输出的方法,之后介绍了Java的标识符和保留字、Java的基本数据类型、基本数据类型转换、Java中的运算等。

“Java结构化编程”的核心是程序的流程控制,具体介绍了构成分支结构的语句(if、switch)、构成循环结构的语句(while、do-while和for)、循环嵌套和循环控制(break、continue),并给出适量的示例,以对Java语言建立初步的认识。

第一讲 Java语言快速入门

本讲意在快速入门。本讲主要内容:

Java的起源和发展历程

Java语言的工作原理及特点

Java开发环境的建立

第一个程序的编译和运行

一、Java的起源和发展历程

作为一名Java语言的学习者,对Java的起源和发展有个概略认识应是必要的。

1. Java的起源

Java起源于20世纪90年代初Sun公司的一个叫Green的项目,该项目的目标是开发嵌入家用电器的分布式软件系统,使电器更加智能化。项目小组成员皆为C++的高手,便采用C++进行系统开发,但在开发过程中发现了很多问题,如C++语言过于复杂、安全性差等。于是项目小组只好另辟蹊径,在“简单的、可靠的、紧凑的并易于移植的”的框架内开发了一个小型的计算机语言,用于编写消费者的电子产品中的程序,当时这款语言命名为Oak,橡树的意思。至于这Oak怎么变成了Java,且看下面的Java发展历程。

2. Java发展历程

表1-1以年份、关键句列表的方式,简述了Java语言的发展历程。

表1-1   Java语言的发展

3. Java的标准划分

Java 的版本演进到Java 2,根据不同层面的应用进行了细化,Java 2平台被分为三种版本,版本及其说明见表1-2。

表1-2   Java的三个版本

文章以J2SE展开,讨论Java语言程序设计。J2SDK 1.6的标准版又名Java SE 6。

二、Java语言的工作原理及特点

1. Java是一门怎样的语言

Sun公司出品了Java,它对Java语言有专门的描述:

“Java is a simple, object-oriented, distributed, interpreted, robust, secure, architecture neutral, portable, high-performance, multithreaded, and dynamic language.”

它告诉你Java是简单的、面向对象的、分布式的、解释的、健壮的、安全的、结构中立的、轻便的、高性能的、多线程的动态语言。所有这些形容词恰恰指明了Java语言的特点和工作原理。

2. 跨平台特性

关于Java程序,有一句口号式的经典描述—“Write once, Run anywhere”,其中文意思是“一次编写,到处运行”。这指的正是Java语言跨平台的特性。

Java源代码被编译成一种结构中立的中间文件格式,在机器上能直接执行这种中间代码,不管机器是什么型号的,操作系统是哪种。但有一个必要的前提:那台运行Java程序的机器上需要预先安装Java运行系统。Java运行系统又称为Java虚拟机(简称JVM),它可以从java.sun.com网站免费下载,不同的操作系统需要安装对应的JVM版本。而Java的跨平台特性即通过JVM实现。

图1-1演示了Java程序的跨平台特性。

图1-1   “一次编写,到处运行”

3. 完全面向对象

Java语言是一门面向对象的语言,它比C++等语言新,一张白纸上可以画最美好的图画,20世纪90年代初它就是这样一张白纸,以James Gosling为首的Green项目团队给它画的那幅画是完全面向对象,一切皆为对象。

什么是对象呢?对象是可存储数据的变量和可提供操作的方法的集合。对象的核心就是两项:变量和方法。每个对象在内存中都占据独立的空间,每个对象都拥有类型,对象从类型创建而来。

在本书中,面向对象程序设计从第二篇开始细述。

4. 多线程

Java中提供了专门的类,可方便地用于多线程编程。

多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立。

多线程的程序可同时执行多个任务,多线程程序具有更好的交互性、实时性。

5. 内存垃圾自动回收

在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其他对象;而在Java中,JVM的一个系统级线程可以监督对象,它可以发现对象何时不再被使用,原先分配给该对象的内存即成为了垃圾,JVM系统线程会释放该内存块,对象即被销毁,内存垃圾就被自动回收。

事实上,除了释放没用的对象,Java垃圾收集也可以清除内存碎片。JVM将经过碎片整理后的内存分配给新的对象。

6. 简洁有效

Java语言的语法大多基于C++,但Java更加严谨、简洁。这体现在如下方面:

Java去除了C++中一些难以理解、容易混淆的因素,如头文件、指针、结构体等;避免了赋值语句与逻辑运算语句的混淆;避免了隐藏变量带来的困惑,如“if(a = 3)…;”,在C++中是没问题的,而在Java中是错误的;取消了多重继承这一复杂的继承机制。

Java提供了对内存的自动管理:内存分配、内存释放。

Java提供了丰富的类库,有利于软件开发的高效和标准化。

7. 健壮且安全

一个Java程序从编写到运行出结果的全过程如图1-2所示。

图1-2   Java程序从编写到运行全过程

Java程序首先要通过编译的环节,而Java有着最严格的“编译器”,可在编译阶段尽早发现错误,只有纠错完毕才能编译成功,生成字节码文件。这是健壮性的一个保证。

字节码文件通过JVM解释执行,类装入器负责装入运行一个程序需要的所有类,确定整个可执行程序的内存布局。字节码校验器对装入的代码进行检查。校验器可发现操作数栈溢出、非法数据类型转换等多种错误。解释执行的机制是又一个健壮保证。

另外解释器的沙盒运行模式,Java网络程序被限制访问本地资源,这些保障了系统的安全性。

三、Java开发环境的建立

一台计算机上安装了JVM,该台机器就可运行Java程序;而要开发Java程序,计算机上仅仅有JVM还是不够的,需要建立Java开发环境才行。

选择什么样的版本,是J2SE还是J2EE,或者是J2ME?这要看从事哪方面的Java开发应用。本书使用J2SE来讨论Java程序设计,因此需要下载和安装JavaSE开发包。

1. JavaSE的组成

JavaSE是一个包含Java开发环境和运行环境的套件,该套件由如下三项集成:

Java Development kit(JDK),Java程序开发环境。

Java Runtime Environment(JRE),Java 应用程序运行环境。

Java Plug-in,使Java Applet可在网页中运行的插件。

2. 建立JavaSE开发环境

有关Java平台方面的软件都是免费开放的,可直接从Sun公司的Java技术支持网站(http://java.sun.com)上下载,网站上提供了众多不同标准和版本的Java语言平台。下载JavaSE开发包,直接输入地址Java Downloads | Oracle亦可。

安装过程是简捷的,双击下载文件,选择安装目录(如C:\java\jdk1.6.0_04),按步操作即可。

3. 设置环境变量

安装完毕需要设置path和classpath两个环境变量,这对于以后程序能否编译,编译成功的程序能否运行都是很关键的一个环节。

要设置环境变量,先要弹出如图1-3所示的属性窗口。这在Windows XP下可通过右击桌面中的“我的电脑”,在弹出的快捷菜单中选择“属性”命令即可;在Windows Vista下可通过“开始”菜单,右击“计算机”,在弹出的快捷菜单中选择“属性”命令,再单击左栏任务下的最后一项“高级系统设置”即弹出属性窗口。然后在属性窗口的“高级”选项卡下,单击“环境变量”按钮就会弹出“环境变量”设置窗口。

path 用于设置Java编译、解释等工具的路径,这些工具文件在Java安装目录下的bin目录中。path的设置如图1-3所示。

classpath用于设置应用程序类路径和扩展的应用程序类路径,通常需要指定两项Java安装目录下的lib目录和当前运行的class所在目录(用“·”指定)。classpath的设置如图1-4所示。

图1-3 环境变量path的设置

图1-4 环境变量classpath的设置

3. bin目录下几个Java实用工具

在bin目录下有若干Java的工具软件,常用的几个工具软件见表1-3。

表1-3   几个Java实用工具

四、第一个Java程序的编译和运行

Java程序有两种常用的应用形式:

应用程序(Application)

嵌入在HTML文件中的小程序(Applet)

本书大部分篇幅讨论的是Java应用程序的设计,Java应用程序是可以独立运行的程序,而Java Applet则不可独立运行,需要嵌入到网页文件中运行,Applet可使网页产生生动活泼的画面,使网页由静态转变为动态。

1. 第一个Java程序

下面就给出第一个Java程序,我们可以在记事本等编辑软件中编辑Java程序,编辑完毕保存成文本文件,但扩展名不能是记事本默认的“.txt”,而应是“.java”。如果给这个程序起名为Hello,那这个程序的全名则是Hello.java。

Hello.java的内容在记事本中的显示如图1-5所示。

图1-5   第一个Java程序

2. 编译和运行

如图1-2所示,一个Java程序编写完后先要编译才能解释运行。编译无错将生成结构中立的字节码文件。由表1-3得知javac.exe即为Java编译器,所以可以用命令javac Hello.java对以上的Hello.java文件进行编译,编译后生成字节码文件名为程序首行class后的类名,扩展名为“.class”,本例生成的字节码文件为HelloWorld.class。

之后用Java解释器java.exe对字节码文件解释即得结果。编译和运行过程如图1-6所示。

图1-6 Java程序的编译和运行

4. Java程序的基本结构

下面给出第二个Java程序。

  1. [HelloDate.java]  
  2.           import java.util.*;  
  3.           public class HelloDate{  
  4.               public static void main(String[] args){  
  5.               System.out.print("Hello, It is");  
  6.               System.out.println(new Date());  
  7.           }  
  8.        } 

程序的运行结果是:

  1. Hello,It is Tue May 05 20:05:35 CST 2009 

通过阅读以上两个程序,我们对Java程序建立了初步的认识。这个程序命名为HelloDate.java是随意的吗?否!那第一个程序怎么没命名成HelloWorld.java呢?原因就在“public”上。请记住“public class……”这样定义的类,必须将class后的那个类名作为文件名。

Java程序的基本组成有如下两部分:

导入包

  1. import 包名; 

类定义

  1. class 类名{  
  2.    类体  

下面作进一步的说明:

1)可执行的Java程序,必有一个类中含main方法。

2)main方法有固定格式,如public static void main(String[] args),其中只有参数名args是可自定的。main前的每个修饰词都不可缺,顺序亦不可错。

3)方法和类都需用成对的花括号界定。

4)Java程序块中语法类同C++,每条语句用分号结束。

5)Java程序对大小写敏感,class后的类名由大写字母开头,变量名、对象名由小写字母开头,常用修饰词与方法名以小写字母开头。

本讲扼要介绍了Java语言的发展历程和Java程序工作原理。Java是20世纪90年代由Sun公司开发的面向对象的程序设计语言,Write once, Run anywhere的特点和JVM的工作模式是相契合的,它们给Java注入了强大的生命力。通过两个程序从编辑到运行的过程,揭示了Java程序编译和解释的运行机制,并对Java程序的基本结构建立了初步的认识。

本讲只是一个Java语言基础的导引,要编写出自己的Java程序,必须学习Java中的数据类型和运算,学习程序的流程控制。

五、思考与练习

1. Write once, Run anywhere描述的是Java语言的什么特性?

2. 任何计算机都可以直接运行Java程序吗?

3. Java程序可以直接编译成适用于本地计算机的机器码吗?

4. 不同的操作系统上可下载同样的Java VM版本安装吗?

5. 从哪里下载J2SE?

6. 安装好J2SE后,安装目录为D:\JDK1.6,请问如何设置环境变量?

7. classpath的设置意义是什么?

8. Java程序文件和Java字节码文件的扩展名分别是什么?

9. JCreator与JavaSE是一种怎样的关系?

10. 在JCreator中如何编译和运行Java 程序?

11. Java程序中的类名通常由大写还是小写字母开头?

12. Java中的常用修饰词和变量通常由大写还是小写字母开头?

13. 编写一个Java程序,显示输出你的邮箱和电话号码。

第二讲   Java中的数据类型和运算

任何语言都需要操纵和处理数据,数据是有类型的,不同的数据类型有不同的运算方式。本讲主要讨论Java语言的数据和运算,主要内容有:

Java输入/输出的初步运用

Java的标识符和保留字

Java的基本数据类型

Java基本数据类型转换

Java中的运算

一、Java输入/输出的初步运用

大多数程序都要输出数据,有一部分程序需要在运行时输入数据。如这样一个问题:读取一个整数,输出该数的平方。

这应该是一个很简单的问题吧?它需要用户先输入一个数,程序输出该数平方的结果。本节专门针对上面这个问题。一通百通,由此及彼。把它解决了,我们就了解了Java的输入/输出方法,然后能着手写出实用的程序。

1. 问题解析

问题复述:读取一个整数,输出该数的平方。

Java可将该问题分解成如下几个步骤:

创建一个来自标准输入设备的扫描器(①);

从扫描器上读取一个整数(②);

做求平方运算,自乘一次即可;

将运算结果向标准输出设备输出(③)。

其中,①②③皆是存疑的标识,通过下面的程序对照来步步解惑。

2. 程序解决

按如上步骤,对问题编程解决。

  1. [Square.java]  
  2.           import java.util.Scanner;  
  3.           public  class Square {  
  4.               public static void main(String[] args){  
  5.                   Scanner sc = new Scanner(System.in);  //  
  6.                   int n = sc.nextInt();         //  
  7.                   int s =  n * n;   
  8.                   System.out.println(s);            //  
  9.               }  
  10.           } 

程序的输出结果是:

  1. 12(用户交互输入)  
  2. 144(显示输出) 

从main方法开始读起,语句后标示的数字符号注释即是对问题解析中存疑的解答。

解①:扫描器的类型是Scanner,来自标准输入设备(默认键盘)的扫描器可由new Scanner(System.in)创建。

解②:可通过扫描器的规定方法获取数据,如用nextInt方法取得整数,用nextDouble方法取得双精度实数,类似的方法有很多,可取得各种不同类型的数据。

解③:输出数据的方法是System.out.println(......),其中括号中的省略号为输出内容,输出内容可由字符串与数值数据多项组成,项与项之间直接用“+”连接即成。

依照上一讲的说明,该程序的第二行中,class前加了public一词,所以程序文件必须命名为Square.java。

3. 程序解析扩展

在前面对程序作了基本的解析,但这些解析还不能令你透彻地理解程序。要透彻地理解,还需要掌握一些面向对象的基本知识,这里只作蜻蜓点水式的说明:

1)Scanner是一个类,它在java.util包中,所以本程序的首行为“import java.util. Scanner;”,意为载入此类;

2)要创建一个扫描器,需要给Scanner指出扫描源,如new Scanner(System.in);

3)Scanner扫描器拥有很多扫描输入数据的方法,如nextInt()即是其中之一;

4)System为系统类,它在java.lang包中,该包在程序编译时自动载入,故不用在程序开头加对应的载入语句;

5)System.out为数据标准输出流,该流拥有print和println方法,print方法的意义是不换行输出,println是换行输出。

二、Java的标识符和保留字

1. 标识符

Java程序中的类、属性、方法、对象、变量等元素都应有自己的名称,各元素的名称通称为标识符。

Java标识符定义规则:由字母、数字、_和$组成;开头字符必须是字母、下画线或$。标识符定义采用三原则:见名知义、规范大小写、不可用Java保留字。

例如,从以下字符串中挑出合法的Java标识符。

  1. 2tow    Mary5   else    Hello world  
  2. bob do  cheese_eat  Hello! 

合法的标识符:Mary5、bob、cheese_eat。

非法标识符:2tow(开头字符不可为数字)、Hello world(标识符中不可有空格)、Hello!(!不可作为标识符的组成字符)、else和do(皆为Java保留字)。

合法的标识符是符合定义规则的字符串,不符合定义规则的字符串则是非法标识符。另外,标识符对字母大小写敏感,如myname与Myname是两个不同的标识符。

2. 保留字

保留字(reserved word),是指Java语言规定了特定含义的标识符。对于保留字,用户只能按照系统规定的方式使用,不能自行定义。

数据类型相关的保留字:boolean、int、long、short、byte、float、double、char、class和interface。

流程控制相关的保留字:if、else、do、while、for、switch、case、default、break、continue、return、try、catch和finally。

修饰符相关的保留字:public、protected、private、final、void、static、strictfp、abstract、transient、synchronized、volatile和native。

动作相关的保留字:package、import、throw、throws、extends、implements、this、super、instanceof和new。

其他保留字:true、false、null、goto和const。

需注意,保留字一律用小写字母表示。

三、Java的基本数据类型(1)

在Java中,每个存放数据的变量都是有类型的,如:

  1. char ch  
  2. float x  
  3. int a,b,c 

ch是字符型的,就会分配到2个字节内存。不同类型的变量在内存中分配的字节数不同,同时存储方式也是不同的。所以给变量赋值前需要先确定变量的类型,确定了变量的类型,即确定了数据需分配内存空间的大小,数据在内存的存储方式。

1. Java中的数据类型

Java中的数据类型有基本数据类型和引用数据类型两大类,图2-1呈现了Java中数据类型的概貌。

图2-1   Java中的数据类型概貌

本讲就基本数据类型进行讨论,引用数据类型将在下一篇中论述。

以下讨论每一种数据类型时,对常量和变量作分别说明。所谓常量,就是直接的值;而变量则是放置常量的容器,除了放置常量之外,也可以给变量一个运算式,变量中的值是可变的。

2. 布尔型—boolean

布尔型又名逻辑型,它是最简单的数据类型,在流程控制时常会用到。有C++编程经验的学习者,要特别看清,Java中的布尔型数据不对应于任何整数值。

布尔型常量:true和false。需要注意的是,布尔常量的组成字母一律都是小写的。

布尔型变量:以boolean定义的变量,如:

  1. boolean b = true;       //定义变量bboolean,且值为true 

3. 字符类型—char

(1)字符常量

字符常量指用单引号括起来的单个字符,如‘a’,‘A’。

请特别注意,字符的定界符是单引号,而非双引号。除了以上所述形式的字符常量值之外,Java还允许使用一种特殊形式的字符常量值,这通常用于表示难以用一般字符来表示的字符,这种特殊形式的字符是以一个“\”开头的字符序列,称为转义字符。Java中的常用转义字符见表2-1。

表2-1   Java中的转义字符

(2)字符变量

以char定义的变量,如char c='a';

要特别加以说明的是,Java的文本编码采用Unicode集,Java字符16位无符号型数据,一个字符变量在内存中占2个字节。

例1:编程测试十六进制数41、51对应的字符,并相隔一个tab位输出。

分析:已知十六进制数,求字符。根据表2-1,可用'\uxxxx'的转义字符形式来表示所求字符,然后直接输出即可。

  1. [HDTest.java]  
  2.           class HDTest{  
  3.              public static void main(String[] args){  
  4.                  char a='\u0041';  
  5.                  char b='\u0051';  
  6.                  System.out.println(a+"     "+b);   
    //
    字符之间以若干空格相间  
  7.              }  
  8.           } 

程序运行结果:A      Q

三、Java的基本数据类型(2)

4. 定点类型(整型)

定点类型包括了字节型、整型、短整型和长整型,它们在内存中虽然占据的字节数互不相同,但它们的存储方式是同样的,所以这里把这些类型归并在一起讨论。

“定点”的意思是把小数点定在末尾,小数点后没有数字的数据,Java中通常把它们称为整数。

(1)定点常量

定点常量是整型常数,它可用十进制、八进制、十六种进制三种方式来表示。

十进制定点常量:如123、-456、0。

八进制定点常量:以0前导,形式为0dd...d。如0123表示十进制数83,-011表示十进制数-9。

十六进制定点常量:以0x或0X开头,如0x123表示十进制数291,-0X12表示十进制数-18。

(2)定点变量

定点变量即整型变量,可细分成字节型变量、整型变量、短整型变量和长整型变量四种。表2-2对各种定点变量的开销内存字节数和数值范围作简要说明。

表2-2   关于整型变量的说明

需要注意的是,如果要将一定点常量赋值给一个定点变量,需要查验常量是否在该变量的表达范围内,如超出范围程序会编译出错。

如:

  1. byte b = 200;       //JCreator编译时错误信息是可能损失精度” 

例2:阅读程序,分析其运行结果。

  1. [OHTest.java]  
  2.            class OHTest{  
  3.                  public static void main(String[] args){  
  4.                       int x = 010;  
  5.                       System.out.println("x = "+ x);  
  6.                       int y = 0x10;  
  7.                       System.out.println("y = " + y);     
  8.                  }  
  9.            } 

程序运行结果略,请思考并调试验证。

5. 浮点型(实型)

(1)浮点常量

即带小数点的实型数值,可以由直接带小数点的数值和科学计数法两种形式来表示:

带小数点的数值形式:由数字和小数点组成,如0.123、.123、123.、123.0。

科学计数法表示形式:由一般实数和e±n(E±n)组成,如12.3e3、5E-3,它们分别表示12.3×103和5×10-3。需要注意的是,e或E之前必须有数字,且e或E后面的指数必须为整数。

(2)浮点变量

浮点变量有单精度变量和双精度变量之分,不同的精度开销的内存字节数和表达的数值范围均有区别。两种浮点变量占内存字节数和数值范围见表2-3。

表2-3   单精度变量和双精度变量简要说明

浮点常量也有单精度和双精度之分,前面列出的常量均是双精度常量,如果要特别说明为单精度常量,可以数据末尾加上f或F作为后缀,如12.34f。如果要特别指明一个浮点常量是双精度常量,数据末尾不需要添加后缀,或者在数据末尾加上d或D作为后缀,如12.34d。

例3:输入一个圆的半径,求圆面积。

分析:圆半径在编写程序时是不确定的,其值在程序运行时输入,这样程序就比较通用,可以处理不同半径的求面积和周长问题。这就涉及数据输入的问题,参照本讲第一节,输入数据通过Scanner扫描器解决。

  1. [CircleArea.java]  
  2.           import java.util.Scanner;  
  3.           class CircleArea{  
  4.               public static void main(String[] args){  
  5.                   Scanner sc = new Scanner(System.in);  
  6.                   double r = sc.nextDouble();  
  7.                   double area = Math.PI * r * r;   
  8.                   System.out.println(area);  
  9.               }  
  10.           } 

四、Java基本数据类型转换

除了布尔型数据外,其他定点类型的数据和浮点类型的数据可以混合在一起进行运算,不同类型数据运算的结果是何种类型的呢?数据可由一种类型转换成另一种类型吗?在这一讲里这些疑问都将得到解决。

1. 自动类型转换

定点和浮点类型都可看作是数值型数据,当不同的数值型数据运算时,有一个内在的规则:先统一为同一类型,再进行运算。结果就为运算前统一的类型。这里的“统一”就是自动类型转换。

自动类型数据转换总是从低级到高级进行,byte、char、short的级别最低,double的级别最高,具体如图2-2所示。

图2-2   数值型自动转换方向

byte、char、short型数据只要参与运算,就首先将类型转为int后进行运算,所以即使short型数据之间的运算,运算结果也是int型。如果int型数据与float型数据运算,int型数据会自动转换成float型,运算结果也为float型。

例4:如有以下变量定义,请回答算式:x + y、 x + y + z、 a + b、 a - x - y、x + c的结果分别是何种类型。

  1. int x;  
  2. byte y;  
  3. long z;  
  4. float a;  
  5. double b;  
  6. char c; 

分析:x + y的结果应为int型,x + y + z的结果为long型,a + b的结果为double型,a - x - y的结果为float型,x + c的结果为int型。

2. 强制类型转换

不同类型数据之间的运算和赋值时,低级别类型的数据可以自动转换成高级别类型的数据。欲让高级数据转换成低级数据,需用到强制类型转换,其形式是:

(类型)数据

数据为需要类型转换的常量、变量或表达式。括号中的类型为数据要转换成的类型。

如:int x = 3.5;         //编译出错,高级别的数据不能给低级别的变量赋值

int x = (int)3.5;   //3.5强制转换成int型数据,后给同级别的变量x赋值

5:阅读程序Char_Int1.javaChar_Int2.javaFloat_Int.java,分析它们的运行情况。

  1. [Char_Int1.java]  
  2.            class Char_Int1{  
  3.                public static void main(String[] args){  
  4.                    char y = 'a';  
  5.                    System.out.println( y );  
  6.                }  
  7.            } 

分析:程序输出结果为a,本程序无数据运算。

  1. [Char_Int2.java]  
  2.            class Char_Int2{  
  3.                public static void main(String[] args){  
  4.                    int x = 2;  
  5.                    char y = 'a';  
  6.                    System.out.println(y + x);  
  7.                }  
  8.            } 

分析:程序中有x + y的运算,如图2-2所示,char型首先转换成int型,即字符对应的ASCII码值。而字符a对应的ASCII码为97,故程序结果为99。

思考:如何修改程序使之输出结果为字符c? 

  1. [Float_Int.java]  
  2.        class Float_Int{  
  3.          public static void main(String[] args){  
  4.              int x=(int)5.2f;  
  5.              float y = x;  
  6.              System.out.println(x + "   " + y);  
  7.          }  
  8.        } 

程序运行结果:5    5.0

五、Java中的运算(1)

数据的运算通过运算符实现,Java语言提供了丰富的运算符,在本讲中将讨论算术运算、赋值运算、条件运算、关系运算和逻辑运算,以及各种运算符的优先级别。

1. 算术运算

算术运算由算术运算符完成,可以实现最基本的数值运算。算术运算符可分为双目和单目两类,双目运算符需要两个操作数参与,有加、减、乘、除、取余五种,见表2-4。

表2-4   双目运算符

表2-4中的op1与op2是两个操作数,它们可以是任意数值型的数据。特别要说明的是Java中的“%”运算与C++有别,它可对浮点数进行,符号同第一个操作数。如52.3%10的结果是2.3,-12%-5的结果是2。

此外,Java对符号“+”运算进行了扩展,它不仅可以对数值型数据进行加法运算,还可以进行字符串之间、数字与字符串之间的拼接。如System.out.println(“s= “ + 4*5);语句将输出s = 20的结果,括号中项与项之间的“+”就起了拼接的作用。

相对双目运算符,还有单目运算符,见表2-5,它们只对一个操作数进行运算。

表2-5   单目运算符

表2-5中的op是一个操作数,对于“前缀+”和“前缀-”,op可以是任意数值型的常量、变量和表达式。如果是常量应是无符号的,如-3,如果带符号则该常量应带上小括号,如-(-3),结果负负得正,为3。

表2-5中的op对于前后缀的“++”和“--”,就不能是常量和表达式了,只能是变量。5++与++(a+b)均是错误用法。前后缀的“++”和“--”通常也称为自加、自减。在使用时另外还要注意如下几点:

++与--运算时结合方向自右向左,-i++相当于-(i++);

两个+号(或-号)之间不能有空格;

应避免使用复杂的表达式。

算术表达式即是用算术运算符与括号将运算对象连接起来的、符合Java规则的式子。就算术运算符之间,运算级别以“先*、/、%,后+、-,左结合”的原则进行,如n*-2、-n/-2。

例6:阅读程序,分析程序运行结果。

  1. [TestMod.java]  
  2.          class TestMod{  
  3.             public static void main(String[] args){  
  4.                 int x = 3y = 10;    
  5.                 System.out.println(y-- % ++x);  
  6.                 System.out.println(-y % -x);  
  7.             }  
  8.          } 

分析:x和y值的变化如程序右侧表2-6所示,第一行输出时,y取用10进行模运算,x先自加为4,结果为2;y接着自减到9,进行第二行输出,结果为-1。

2. 赋值运算

将数据保存到变量中,这个过程就是“赋值”,所以赋值运算也是最基本的运算,赋值运算符号即为通常的等于符号“=”。Java中的赋值运算可分为基本赋值与复合赋值两种。

(1)基本赋值

基本赋值运算形式:

  1. <变量>  <表达式> 

其作用是将“=”右边表达式的值赋给左边的变量。表达式也可以是直接的常量或变量。该式加上分号即为赋值语句。

特别要说明的一点是,“=”右边的表达式的级别不能高于变量所定义类型的级别(数值型的级别如图2-2所示),否则要有强制转换的说明。而如果表达式类型与变量类型是不可互转的,这样的赋值运算在编译时将出错。

例7:阅读程序,理解赋值运算。

  1. [AssignTest.java]  
  2.             class AssignTest{  
  3.                public static void main(String[] args){  
  4.                    int a,b;  
  5.                    int c = (a = 5) + ( b = 13);  
  6.                    System.out.println(a + " " + b + "  " + c);  
  7.                }  
  8.             } 

程序运行结果为:5  13  18

五、Java中的运算(2)

(2)复合赋值

复合赋值意味着的是运算且赋值,其形式:

  1. <变量><简单运算符>  <表达式> 

表2-7通过示例对复合赋值进行了简要说明。

表2-7   复合赋值示例说明

复合赋值化解成基本赋值式为: <变量> = <变量><简单运算符>(<表达式>),表达式加上括号意指优先运算。

3. 关系运算

关系运算亦即比较运算。既然是比较就需要两个操作数参与。Java提供的关系运算符及其示例说明见表2-8。

表2-8   关系运算符及其说明

由表2-8知关系运算式的通常形式是:
 

  1. op1 <关系运算符> op2 

表中的op1与op2是两个可以比较的操作数,它们可以是基本数据类型的,也可以是复合类型的。目前暂只讨论前者。下面有几点说明在编程时需要注意:

“==”不要写成“=”;

任何类型的两个数据都可以通过“==”或“!=”来比较是否相等;

浮点数的比较小心慎用;

关系运算的结果是true和false,而非1或0;

关系运算符优先级低于算术运算符优先级,高于赋值运算符优先级。

4. 逻辑运算

逻辑运算可以表达复合的条件,逻辑运算可以对结果是布尔型的数据进行复合或否定。逻辑运算符只有三个,关于它们的说明见表2-9。

表2-9   逻辑运算符及其说明

表2-9中的op1、op2、op皆是布尔型数据。与其他表达式不同的一点是,逻辑运算表达式中,不是每一个逻辑运算符都一定进行运算。在“&&”与运算时,只要前一个操作数的结果是false,结果就已确定为false,后面的运算就被忽略;在“||”或运算时,只要前一个操作数的结果是true,结果也就确定为true,后面的运算同样被忽略,这称为逻辑运算的截断性。

例8:阅读程序,理解逻辑运算的截断性。

[CutOffTest.java]

  1. class CutOffTest {  
  2.    public static void main(String[] args){  
  3.        int f = 0;  
  4.        if (f!=0 && 3/f>5)  
  5.            System.out.println("true");  
  6.        else   
  7.            System.out.println("false");  
  8.    }  

分析:if语句中的3/f>5的运算会发生除0溢出错误,因为f!=0的结果是false,后面所遇又是“&&”,根据逻辑运算的截断性,其后的表达式被忽略,所以程序可正常运行得到结果,结果为false。

加入逻辑运算符后,优先级别排序是:非运算(!)、算术运算、关系运算、逻辑与(&&)、逻辑或(||)、赋值(=)。

5. 条件运算

条件运算可根据条件取值,运算符号由间隔的双字符组成“? :”。条件运算式形式是:

  1. e1 ? e2 : e3 

式中的e1为条件,应是布尔型数据,e2和e3可以是任意类型、但必须类型一致的数据。若条件e1为真,则条件运算结果为e2的值;若条件e1为假,则条件运算结果为e3的值。下面语句可以求a和b中的较大数,并赋值给变量max:

  1. max = a > b ? a : b; 

6. Java运算符的优先级

当运算趋于复杂时,表达式中可能会出现多种运算符,只有理解了Java运算符的优先级,才能运用得当,所得即所想。

Java运算符的优先级见表2-10

2-10   Java运算符的优先级

本讲属于Java程序设计基础的部分,介绍了Java语言标准设备的数据输入/输出方法、Java中的数据和运算。继续学习下一讲的程序流程控制,你就将初步具备程序设计的能力。

六、思考与练习

1. 如何在程序运行时交互输入数据?

2. 一个数字组成的字符串如何转化成整数?

3. Java程序如何向字符窗口输出数据?

4. 在Java中一个字符数据开销字节数是多少?

5. 在Java中怎样给出一个八进制整常数?

6. 在Java中怎样给出一个十六进制整常数?

7. 在Java中如何输出数据?

8. Java表达整型的数据类型与C相比异同点是什么?

9. 如何给出一个单精度常数?

10. 字符常量和字符串的定界符分别是什么?

11. 在Java中一个整型数据占字节数是多少?

12. 在Java中用什么类型的变量存储一个逻辑值?

13. 阅读程序,分析程序运行情况。

(1)

  1. class Test1{  
  2.   public static void main(String[] args){  
  3.       char a = '\u0041';  
  4.       int b = a;  
  5.       float c = b;  
  6.       double d = c;  
  7.       System.out.println(a + "\t" + b + "\t" + c + "\t" + d);  
  8.   }  

(2)

  1. class Test2{  
  2.   public static void main(String[] args){  
  3.       double e = 65.5;  
  4.       float f = e;  
  5.       int g = f;  
  6.       char h = g;  
  7.       System.out.println(e+ "\t"+ f+ "\t"+ g+ "\t"+ h);  
  8.   }  

(3)

  1. class Test3{  
  2.   public static void main(String[] args){  
  3.       System.out.println(10 % 3);  
  4.       System.out.println(10 % -3);  
  5.       System.out.println(-10 % 3);  
  6.       System.out.println(-10 % -3);  
  7.   }  

(4)

  1. class Test4{  
  2.   public static void main(String[] args){  
  3.       char x = '4';  
  4.       int y = 4;  
  5.       if (x==y)System.out.println(y);  
  6.       else System.out.println((char)y);  
  7.       }  
  8.    } 

14. 输入两个整数,求平均数。

第三讲   Java结构化编程

只有少数问题,诸如上一讲的“读取整数求平方”,可以通过若干语句的顺序执行得到结果。大多数任务需要运用到分支和循环才得以解决。本讲主要讨论Java程序的结构化编程和流程控制,主要内容有:

分支结构(if, switch)

循环结构(while, do-while, for)

循环嵌套和循环控制(break, continue)

Java结构化编程综合

一、分支结构(1)

如果有这样一个问题“交互输入一个整数,若为正数求平方,若为负数求立方”,顺序执行的语句就无法解决了,此时要通过分支结构的程序来求解。

Java像C++一样,可以通过if语句和switch语句来建立分支结构的程序。相对来说,if语句更常用一些,因为if可表达所有的条件分支情况,而switch语句也有着特别的妙处,在某些情况下,可以令程序更加简练清晰。

1. if语句

if语句是最基本的分支语句。它通过条件的直接判断,转向不同的程序流程,以此实现流程控制。

(1)if语句的最简形式

  1. if ( 条件 )  
  2.      语句块 

条件为boolean数据,语句块指一组语句,若语句块中的语句多于一条,则在头尾需要用成对的大括号标识。图3-1解析了该语句的执行流程。当条件为true时,执行语句块,条件为false时,则跳过语句块。

图3-1 最简if语句流程解析

  1. 如:max = a ;  
  2.         if( max < b ) max = b ; 

这两条语句,保证max变量总是取得a和b中的较大数。

(2)if语句的基本形式

  1. if ( 条件 )  
  2.     语句块1  
  3. else  
  4.     语句块

图3-2解析了if-else语句的执行流程。当条件为true时,执行语句块1,条件为false时,执行语句块2。只要执行到此if语句,总有一个语句块被执行。

图3-2   基本if语句流程解析

这是一个兼有输入和输出的问题,输入同样用Scanner扫描器解决,通过nextDouble()方法取得扫描到的double型数据。然后通过分支求y值。注意程序中所涉变量必须在使用之前定义类型。

例2:闰年计算规律为:“四年一闰,百年不闰,四百年再闰”。输入一个年份,判断该年份是否为闰年。

分析:能被4整除的年份通常是闰年,而如果该年份还能被100整除,则存疑了。需要继续考察该年份能否被400整除,若能则是,否则非闰年。这样闰年就有两种情况:直接能被400整除的年份、被4整除而不能被100整除的年份。

[TestIf2.java]

  1. import java.util.Scanner;  
  2. class TestIf2{  
  3.     public static void main(String[] args){  
  4.          Scanner sc = new Scanner(System.in);  
  5.          System.out.print("Year? ");          
  6.          int year = sc.nextInt();  
  7.          if( year % 400 == 0 || year % 4 == 0 && year % 100 != 0)  
  8.              System.out.println(year+" is a leap year.");  
  9.          else  
  10.              System.out.println(year+" is't a leap year.");  
  11.     }  

一、分支结构(2)

如果遇到比以上示例复杂的问题,如y是一个三分支的函数,对x的取值范围需要考虑三种或更多的情况,此时if-else语句仍可以解决,那就是在语句块中继续嵌套if-else语句,形式如:

  1. if ( 条件1 )  
  2.     if ( 条件2 )  
  3.         语句块1  
  4.     else  
  5.         语句块2  
  6. else  
  7.    语句块

这样的嵌套理论可行,但程序的清晰性减弱,特别是嵌套层数在两层以上,就很容易出错。Java提供了if-else的扩展形式,可以自如应对多分支的问题。

(3)if语句的扩展形式

  1. if ( 条件1 )  
  2.         语句块1   
  3. else if ( 条件2 )  
  4.         语句块2  
  5. ...  
  6. else if ( 条件n )  
  7.         语句块n   
  8. [else  
  9.    else语句块

其中,末尾中括号的else部分是可选的。如果无可选的else部分,而前面的各条件又都为false时,程序流程流经这条if语句,什么也不执行;否则,不管前面的条件怎样苛刻,总有一个、当然也只有一个语句块执行。流程解读如图3-3所示。

图3-3 完整if语句流程解析

例3:某企业工龄工资调整,工龄不到二年者不参与调整,其余员工中,工龄少于五年者按每年50元计算,工龄达五年少于十年者每年按65元计算,工龄达十年者每年按80元计算,工龄达十五年者每年按100元计算。此外,对达十二年以上者,额外增加200元。

分析:本问题是一个五分支的处理,五种情况分别是:不到二年、过二年不到五年、达五年不到十年、达十年不到十五年、达十五年。“此外”部分放在最后考虑。

[TestIf3.java]

  1. import java.util.Scanner;  
  2. class TestIf3{  
  3.     public static void main(String[] args){  
  4.         Scanner sc = new Scanner(System.in);   
  5.         System.out.print("工龄? ");         
  6.         int year = sc.nextInt();  
  7.         int num;  
  8.         if( year<2 )  num = 0;   
  9.         else if( year<5 )  num = year * 50;    
  10.         else if( year<10 )  num = year * 65;  
  11.         else if( year<15 )  num = year * 80;  
  12.         else  num = year * 80;  
  13.         if( year>=12 ) num += 200;  
  14.         System.out.println(year + "\t" + num);  
  15.     }  

2. switch语句

switch是用基于整型数据的多分支判断。

switch语句形式:

  1. switch ( 表达式 ) {  
  2.     case 1: 语句组1;  
  3.     case 2: 语句组2;  
  4.     ...  
  5.     case n: 语句组n;  
  6.    [default: default语句组;]  

语句组指一组语句,与语句块不同的是头尾不需要用大括号括出。

switch中的表达式结果必须是一个整型值,该值用来与后续的值1、值2、……、值n比较,如果值是相同的,则执行case后的语句组。之后不再判断,连续地执行下去,直到遇到break语句或switch运行完毕。switch表达式值与值1匹配的极端情况,将使所有的语句组都顺序执行。具体流程如图3-4所示。

图3-4 switch语句流程解析

所以break语句对于switch语句是相当重要的,switch如好脾气的、不知拒绝的主人,而break就是当机立断的管家,流程至break就终止switch语句的执行,转到switch后的语句。

例4 : 输入一百分制成绩, 输出对应的等级。90~100分的等级为‘A’,80~89分的等级为‘B’,70~79分的等级为‘C’,60~69分的等级为‘D’,60分以下的等级为‘E’。

  1. [TestSwitch.java]  
  2.           import java.util.Scanner;  
  3.           class TestSwitch{  
  4.               public static void main(String[] args){  
  5.                   Scanner sc = new Scanner(System.in);  
  6.                   System.out.print("Score ? ");    
  7.                   int scscore = sc.nextInt();  
  8.                   char grade;  
  9.                   switch(score/10){  
  10.                       case 9: case 10: grade = 'A'; break;   
  11.                       case 8: grade = 'B'; break;  
  12.                       case 7: grade = 'C'; break;  
  13.                       case 6: grade = 'D'; break;  
  14.                       default:grade = 'E';  
  15.                   }  
  16.                   System.out.println(score+"\t"+grade);  
  17.               }  
  18.           } 

请思考一下,如果程序中无break语句,运行结果会是怎样?

二、循环结构

程序经常需要重复一些操作,如生成一个有规律可循的数列、自然数累加等问题。循环结构正好用来解决这样的问题。在Java中,有while、do-while、for三条语句可用来设计循环结构的程序。

1. while语句

while语句是条件循环语句,根据条件是否成立,确定循环是否进行。

  1. while循环语句形式:  
  2.  
  3. while ( 条件 )  
  4.     语句块 

在循环体执行前先判断条件,只要条件成立,循环就继续。语句块即是重复的部分,称为循环体。语句块执行完毕再回到条件判断,直到条件不成立,流程转到下一语句。流程解析如图3-5所示。

图3-5 while语句流程解析

例5:求前100个自然数的和。

分析:本题即求1+2+…+100,要设一个累加变量sum放置结果,在累加前需给sum设置初值,以后需不断在sum中加入递增的数,将此加数变量设为num,num的初值应为1,变化规则是每次递增1,当num超过100时,sum中的值即为所求结果。

[TestWhile.java]

  1. class TestWhile{  
  2.    public static void main(String[] args){  
  3.        int sum = 0num = 1;  
  4.        while(num<=100){  
  5.            sum += num;  
  6.            num ++;  
  7.        }  
  8.        System.out.println("sum: " + sum);  
  9.    }  

由此及彼,许多累加的问题都可仿照完成。

设计一个循环时,要考虑到循环的终点,而循环体中应该可以不断地修正循环条件,让循环条件由开始的成立向不成立转化,此时循环便结束。不设置终点的循环会永无穷尽,即陷入死循环。

2. do-while语句

do-while循环与while循环很相近,区别只在于先判断还是先执行。

do-while循环语句形式:

  1. do  
  2.     语句块  
  3. while ( 条件 ); 

do-while语句流程解析如图3-6所示。大多数情况下while循环与do-while循环会得到一致的结果。惟一可能产生差异的是循环条件特别苛刻,第一次就不成立,此时while循环什么都不做,而do-while循环的循环体却会执行一次。

图3-6 do-while语句流程解析

例6:用do-while语句求前100个自然数的和。

  1. [TestDoWhile.java]  
  2.         class TestDoWhile{  
  3.             public static void main(String[] args){  
  4.                 int sum=0,num=1;  
  5.                 do{  
  6.                     sum += num;  
  7.                     num ++;  
  8.                 }while(num<=100);              //while后的分号不可缺  
  9.                 System.out.println("sum: " + sum);  
  10.             }  
  11.         } 

3. for语句

for循环是一种计数循环,可以设置循环变量,用来遍历某个范围的值。

for循环语句形式:

  1. for ( 语句块1; 条件语句块2)  
  2.     语句块

for语句流程解析如图3-7所示。for中有三项,它们分别用分号相间,其中语句块1只在循环起始执行了一次,而没参加具体的循环。语句块3是循环体,而语句块2是每次循环完毕执行的部分。for语句同while一样也是先判断后循环的语句,可用while来改写如下:

  1. 语句块1;  
  2. while ( 条件 ) {  
  3.     语句块3;  
  4.     语句块2;  

图3-7   for语句流程解析

当然这样的改写只是帮助对for语句的理解,相对来说,for语句还是更简明和更有效率的。

例7:用for语句求前100个自然数的和。

  1. [TestFor.java]  
  2.            class TestFor{  
  3.               public static void main(String[] args){  
  4.                    int sum,num;  
  5.                    for(sum=0num=1; num<=100; num++)  
  6.                       sum += num;  
  7.               System.out.println("sum: "+sum);  
  8.            }  
  9.          } 

语句块1可用来初始化一个或多个变量,如果是多个变量取不同的初值,可在赋值表达式间以逗号相间。语句块1、条件、语句块2三项是可选的,最简的for语句形式是for(;;),这就相当于while(true),它们设定了一个永真循环,很有死循环的嫌疑。下一节的学习将澄清迷雾,我们会认识到除了循环条件外,在循环体内也可以设置中途退出的机制。

三、循环控制和循环嵌套

循环控制是除了循环条件之外,控制循环是否进行的一个机制,这给处理循环问题带来了灵活性。循环体内的语句块可以是顺序执行的语句,可以是分支结构的语句,也可以是循环语句,循环中含循环,就是循环嵌套。

1. 循环控制

循环控制由break语句和continue语句实现。

(1)break语句

break语句很利落简单,语句形式:

break;

break语句除了适用于switch外,也适用于for、while以及do-while三种循环语句,其作用是结束循环,程序流程至这些语句后的第一句。通常break语句配合条件语句一起使用。

例8:求1+2+3 +…+ N < 1000的N的最大数。

分析:这是一个自然数累加计算加判断的问题,加多少项是预先不知的,或者正是所求的,所以不管是用哪个循环语句来处理,条件的地方均无法明确给出。这就需要在循环体中边加边判断,如果结果有了,中途退出循环。

[TestBreak.java]

  1. class TestBreak{  
  2.     public static void main(String[] args){  
  3.         int sum = 0num = 1;  
  4.         while( true ){  
  5.             sum += num;  
  6.             if( sum>1000 ) break;  
  7.             num ++ ;  
  8.         }  
  9.         System.out.println("N: " + (num-1));  
  10.     }  

(2)Continue语句

continue语句形式:

continue;

continue语句,也称短路语句。它适用于for、while以及do-while语句中,其作用是忽略其后的语句,中止当前循环,流程转至循环起始处,开始下一次循环。

例9:阅读程序,分析程序运行结果。

  1. [TestContinue.java]  
  2.  
  3.            class TestContinue{  
  4.                public static void main(String[] args){  
  5.                    for(int m = 1; m <= 10; m ++){  
  6.                        if( m%2 == 0 ) continue;   
  7.                        System.out.print(m + "\t");  
  8.                    }  
  9.                }  
  10.            } 

2. 循环嵌套

在解决复杂一些的问题时,需要在循环里继续设置循环语句,这就是循环的嵌套。外层的循环称为外循环,内层的循环称为内循环。如输出二维矩阵的问题,用循环嵌套就很容易解决。

例10:阅读程序,分析程序运行流程。

  1. [Matrix.java]  
  2.  
  3.            class Matrix {  
  4.                public static void main( String[] args ){  
  5.                   for( int i=1; i<=3; i++ ) {  
  6.                        for ( int j=1; j<=5; j++)  
  7.                              System.out.print(i*j + "\t");      //内循环体  
  8.                        System.out.println();                //换行  
  9.                   }  
  10.                }  
  11.            } 

程序分析:i是外循环变量,当i取得一个值,循环体(斜体部分的代码)执行一次。其中有两条语句,一条是for循环语句(内循环),另一条是换行语句。当循环体执行时,即内循环变量j从初值到终值遍历一次,进行输出。i增值换下一个时,先换行。

本程序的输出结果是:

  1. 1       2       3       4       5  
  2. 2       4       6       8       10  
  3. 3       6       9       12      15 

例11:输出一个三角形形式的九九乘法表。

  1. 11=1  
  2. 1=2   2×2=4 
  3. 1=3   3×2=6   3×3=9 
  4. 1=4   4×2=8   4×3=12  4×4=16 
  5. 1=5   5×2=10  5×3=15  5×4=20  5×5=25 
  6. 1=6   6×2=12  6×3=18  6×4=24  6×5=30  6×6=36 
  7. 1=7   7×2=14  7×3=21  7×4=28  7×5=35  7×6=42  7×7=49 
  8. 1=8   8×2=16  8×3=24  8×4=32  8×5=40  8×6=48  8×7=56  8×8=64 
  9. 1=9   9×2=18  9×3=27  9×4=36  9×5=45  9×6=54   9×7=63  9×8=72  9×9=81 

分析:这与前面矩阵输出的问题有些相像,同样也是输出多行的问题。乘法表有九行,可用循环变量i来记录行数(1~9行),第1行,有1个乘法算式;第2行,有2个乘法算式;第i行便有i个乘法算式。对于确定的第i行,如何来输出这i个算式呢?这又是一个重复处理的问题,可用内循环来解决。内循环变量设为j,j的变化从1到i。

[MutiTable.java]

  1.    class MutiTable{  
  2.        public static void main( String[] args ){  
  3.            for( int i=1; i<=9; i++ ) {  
  4.                 for ( int j=1; j<=i; j++)  
  5.                       System.out.print( i + "*" +j+ "=" + i*j + "\t");   
  6.            System.out.println();  
  7.        }  
  8.    }  

以上程序巧妙的是,循环变量i和j正巧是每个乘法算式的被乘数和乘数。

四、Java结构化编程综合

本节通过程序设计实例,来进一步掌握Java结构化编程方法。

例12:输入一月份,求该月的天数。

分析:不同的月份有不同的天数,这需要判断后才能确定。把月份归为三类,30天的月份有4、6、9、11月份,28或29天(由年份再确定)的月份是2月份,其余皆为31天。这是一个多分支判断的问题,可用if或switch语句解决,根据月份判断天数部分用switch语句代码更简捷。

[Monthdays.java]

  1. import java.util.Scanner;  
  2. class Monthdays{  
  3.    public static void main(String[] args){  
  4.        int month,days;  
  5.        Scanner sc = new Scanner(System.in);  
  6.        System.out.print("Month? ");  
  7.        month = sc.nextInt();  
  8.        if(month<1 || month>12){     //若输入数据非月份数  
  9.            System.out.println("error data");  
  10.            System.exit(0);                  //退出运行  
  11.        }  
  12.        switch(month){  
  13.            case 4: case 6: case 9: case 11: days = 30;break;  
  14.            case 2:                 //2月份需要输入年份进一步判断  
  15.               System.out.print("Year? ");  
  16.               int year = sc.nextInt();  
  17.               if(year%400==0 || year%4==0 && year%100!=0)  
  18.                  days = 29;  
  19.               else days = 28;  
  20.               break;  
  21.            default: days = 31;                  
  22.        }  
  23.        System.out.println("days: "+days);  
  24.    }  

程序运行中途要强制退出,可以用“System.exit(0);”语句。本例中若输入的年份数据是不合理的数据,程序输出error data后,便退出结束运行。

例13:输入一个自然数,判断该数是否为素数。

分析:先确认什么样的数为素数。根据数学定义知,一个自然数除了1和本身之外没有其他的因子,该数便为素数。2专门规定为素数,且是最小的素数。对于自然数n,我们只要用2到n-1去测试,如果它们中没有一个是n的因子,n就为素数,否则n不是素数。

[PrimeTest.java]

  1. import java.util.Scanner;  
  2. class PrimeTest{  
  3.    public static void main(String[] args){  
  4.        Scanner sc = new Scanner(System.in);  
  5.        System.out.print("number? ");  
  6.        int n = sc.nextInt();        //n为被测数  
  7.        int i;               //i1和本身外可能的因子  
  8.        for(i=2;i<n;i++)  
  9.            if(n%i == 0)break;       //in的因子,n非素数  
  10.        if(i == n)               //所有可能的因子全非n的因子  
  11.           System.out.println( n + " is a prime number." );  
  12.        else  
  13.           System.out.println(n + " is not a prime number");  
  14.    }  

例14:求所有三位素数。

分析:本题是上题的拓展。不是判断某一个数,而是判断所有三位数。这就需要用一个循环变量遍历三位数,因为所有的三位偶数都非素数,所以可直接遍历三位奇数。对于确定的三位数判断其是否为素数的方法同上。

[PrimeNumbers.java]

  1. class PrimeNumbers{  
  2.    public static void main(String[] args){  
  3.        int i,n;  
  4.        for( n = 101; n<1000; n+=2 ){         //n遍历所有三位奇数  
  5.             for( i=2; i<n; i++)  
  6.                 if( n%i == 0 )break;  
  7.             if( i==n )System.out.print( n + "\t");  
  8.        }  
  9.    }  

程序运行结果:

  1. 101     103     107     109     113     127     131   137     139     149  
  2. 151     157     163     167     173     179     181  191     193     197  
  3. …  
  4. 983     991     997  

例15:输出如下菲波那契数列的前20项,并求其和。

  1. 11235813…… 

分析:菲波那契数列的前两项均为1,以后的每一项都是前两项之和。这是一个重复求和处理的问题,可用循环解决。循环次数是所要求的项数18。对所有项求和的问题可以设置一个累加器变量sum,初值为前两项之和,后在循环中每求得一新项,即将该项加进sum。

[Fei.java]

  1. class Fei{  
  2.    public static void main(String[] args){  
  3.        int a,b,c,sum;  
  4.        a = b = 1;               //a,b为前两项,均为1  
  5.        sum = a + b;             //累加器变量,设初值  
  6.        System.out.print( a + "\t" + b );  
  7.        for( int i=1; i<=18; i++ ){  
  8.           c=a+b;                //生成的新项置放在变量c  
  9.           System.out.print("\t" + c);  
  10.           sum += c;   
  11.           a = b;                //前两项后移一个数  
  12.           b = c;          
  13.        }  
  14.        System.out.println("\tsum=" + sum);  
  15.    }  

程序运行结果:

  1. 1       1       2       3       5       8       13      21      34      55  
  2. 89      144     233     377     610     987     1597    2584    4181    6765  
  3. sum=17710 

本讲介绍了Java语言的结构化编程,在main方法中的代码段总是由三种基本结构组成:顺序结构、分支结构和循环结构。分支结构通常用if或switch语句实现,循环结构常用while、do-while或for语句实现。在循环结构中可以继承包含循环,这即是循环嵌套,也称为多重循环,我们可用多重循环解决比较复杂的问题。break语句可以安排在switch和三种循环语句中,它总是会终止当前的语句。continue语句可以放在循环语句中,它只是结束当前循环,而并不会终止循环。

至此,我们已初入Java之门,可以解决一些基本的数据处理问题了。

五、思考与练习

1. 求150内的奇数之和。

2. 输入一个自然数,求N!。

3. 用循环嵌套的方法输出如下图案:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洋240

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值