当前位置:文档之家› J2EE从入门到精通1-5

J2EE从入门到精通1-5

1. 基本Console(操纵、控制台)互动

1.1 第一个Java程序

对新手解释清楚什么是Java程序并不是一件简单的事情,因为一个最简单的Java程序就可能涉及文档管理、类(Class)、主程序、命令列、索引等许多概念。所以我们只能从实例出发,逐步深入地加以介绍。

在文本编辑器中书写一个名为“HelloWorld.java”文本文件:

HelloWorld.java

public class HelloWorld{

public static void main(String[] args){

System.out.println("Hello!World!");

}

}

文件后缀= “ java”. 就构成一个最简单的Java程序,其中"class"是Java类定义的关键字,类的名称是HelloWorld,类名应该与程序的主档名(HelloWorld.java)相同,在编写Java程序时,一个文档中可撰写数个类,但是只能有一个类是"public"的,而且文档主档名必须与这个"public"类的名称相同。

接下来看看main()方法(Method),它是Java程序的“进入点”(Entrypoint),程序的执行是由进入点开始的,它一定是个"public"方法(函数)成员(Member),只有这样它才可以被调用;由于它不需要产生对象就能被执行,所以它必须是个"static"成员。

"void"表示这个方法执行结束后不返回任何值,Java程序的main()方法不需返回任何值,所以一律使用void;其中"String[] args"是命令行参数(Command line argument),可以在执行程序时取得使用者指定的相关参数,目前虽然您不使用,但仍要撰写它,这是规定。

显示输出语句:System.out.println("Hello!World");

在这个程序中使用了https://www.doczj.com/doc/e011681476.html,ng包中的System类成员out对象的println()方法,这是一个PrintStream对象,将一个确定的字符串(String)"Hello!World!"输出至Console(即操纵、控制台)上。

注意在Java中字符串要使用双引号""括起来,println()表示输出字符串后自动断行,如果使用print()的话,则输出字符串后程序并不会自动断行。注意java语句要用分号";"结束。

一个最基本的Java程序完成后,接下来是在dos提示符下使用javac程序对应用程序,对HelloWorld.java加以编译:

c:\>javacHelloWorld.java

生成同一个目录下的字节码(或class)文档HelloWorld.class,再用java程序:

c:\>javaHelloWorld

运行该字节码文档,就会得到以下输出结果:

Hello!World!

1.2 给C使用者的第一个Java程序

C语言的打印输出函数为printf()。J2SE5.0版本后,Java增加了一个printf()的功能,如果您是学过C的使用者,下面这第一个Java程序一定会让您感到亲切或高兴:

// HelloWorldForC.java

public class HelloWorldForC {

1

public static void main(String[] args) {

System.out.printf("%s! Welcome to Java!\n", "caterpillar");

}

}

这次使用的是out对象的printf()方法,%s对应于第一个字符串"caterpillar",程序的输出:caterpillar! Welcome to Java!

记号“'\n”是换行字符,当然,也可以使用在之后使用println()进行换行:

System.out.printf("%s!WelcometoJava!","caterpillar")

要指定数字的话,可以使用%d,例如:

System.out.printf("%s!Welcometo%dstJava!\n","caterpillar",1);

字符串"caterpillar"对应于%s,而数字1对应于%d,执行结果会显示如下:

caterpillar!Welcometo1stJava!

1.3 取得用户输入

当在文字模式下要输入资料至程序中时,可以使用标准输入流对象System.in,然而我们很少直接使用它,因为System.in对象所提供的read()方法,是从输入流取得一个位元组的资料,并传回该位元组的整数值。

在文字模式下的输入是以字符的方式传送给程序,所以直接使用read()方法取得的是字符的ASCII编码整数,通常要取得的使用者输入会是一个字符串,或是一组数字,所以System.in对象的read()方法一次只读入一个位元组资料的方式并不适用。

在J2SE5.0中,您可以使用java.util.Scanner取得使用者的输入。

java.util指的是组件(package)层级,java.util.Scanner表示Scanner这个类是位于java/util这样的阶层之下,可以将这个阶层想像为类似文档管理的目录(资料夹)阶层。

直接先来看如何取得使用者的输入字符串:

// UserInput.java

import java.util.Scanner;

public class UserInput{

public static void main(String[] args){

Scanner scanner = new Scanner(System.in);

System.out.print("Please input your name :");

System.out.printf("Hello!%s!",scanner.next());

}

}

执行结果:

Please input your name:caterpillar

Hello!caterpillar!

java.util组件是J2SE5.0的标准组件,编译器知道到哪去找这个组件,语句

"import java.util.Scanner;"

告诉编译器,程序将使用java.util下的Scanner类。

"new "表示新增一个Scanner对象,使用它的System.in对象,因为实际上是System.in在取得使用者的输入,您可以将Scanner看作是System.in对象的支援者,System.in取得使用者输入之后,交给Scanner作一些处理(实际上,这是Decorator模式的一个应用)。

简单的说,“Scanner scanner = new Scanner(System.in);”告诉执行环境新增一个Scanner对象,然后使用它的next()方法来取得使用者的输入字符串,如果要取得数字呢?您可以使用Scanner对象的nInextt()方法,例如:

import java.util.Scanner;

2

public class UserInput {

public static void main(String[] args) {

Scanner scanner = new Scanner(System.in);

System.out.print("Please input your name: ");

System.out.printf("Hello! %s!", scanner.next());

}

}

nextInt()会将试着取得的字符串转换为int整数,看看执行结果:

Please input a number:100

Oh!Iget100!!

同样的,您还可以使用Scanner的nextFloat()、nextBoolean()等方法来取得使用者的输入,并转换为正确的资料型态。

要注意的是,Scanner取得输入的依据是空白字符,举凡按下空白键、tab键或是enter键,Scanner 就会传回下一个输入,如果您想要取得包括空白字符的输入,比较简单的方法是使用BufferedReader 类取得输入。

1.4 使用BufferedReader取得输入

使用Scanner来取得使用者的输入很方便,但是它以空格来隔离每个输入字符串,在某些时候并不适用,因为使用者可能输入一个字符串,中间会包括空白字符,而您希望取得完整的字符串。

您可以使用BufferedReader类,它是java.io组件中所提供的一个类,所以使用这个类时必须先import java.io组件;使用BufferedReader对象的readLine()方法必须处理IOException例外(exception),例外处理机制是Java提供给程序设计人员捕捉程序中可能发生的错误所提供的机制,现阶段您处理IOException的方法是在main()方法后,加上throwsIOException,这在以后会再详细讨论为何要这么作。

BufferedReader在构建时接受一个Reader对象,在读取标准输入流时,会使用InputStreamReader,它继承了Reader类,您使用以下的方法来为标准输入流建立缓冲区对象:

BufferedReaderbuf = new BufferedReader(new InputStreamReader(System.in));

"new "关键字表示您要构建一个对象为您所用,BufferedReaderbuf表示宣告一个型态为BufferedReader的对象变数,而new BufferedReader()表示以BufferedReader类构建一个对象,new InputStreamReader(System.in)表示接受一个System.in对象来构建一个InputStreamReader对象。

您可以在学过面向对象观念之后再来看这段,现阶段若您比较难理解,就记得上面的缓冲区读取对象建立方式,通常要使用BufferedReader来取得使用者的输入都是这么写的。

下面这个程序可以在文字模式下取得使用者输入(可包括空白字符输入),并重新显示在主控台中:

import java.io.*;

public class GetInput {

public static void main(String[] args) throws IOException {

BufferedReader buf = new BufferedReader(

new InputStreamReader(System.in));

System.out.print("请输入一列文字: ");

String text = buf.readLine();

System.out.println("您输入的文字: " + text);

}

}

readLine()方法会传回使用者在按下Enter键之前的所有字符输入,程序的执行范例如下所示:

3

请输入一列文字:This is a test !

您输入的文字: This is a test !

1.5 标准输入输出流

在以往的HelloWorld程序中,您使用了System类中的静态对象out,它提供标准输出流(Stream),会在程序开始执行之后自动开启并准备接受指定的资料,它通常对应至显示输出(Console(即操纵、控制台)、终端机输出)或其它的输出目的地,它可以被重新导向至一个文档,您可以在执行程序时使用'>>'将输出结果导向至指定的文档,例如:

javaHelloWorld>>output.txt

上面的执行会将结果导向至output.txt,而不会在荧幕上显示"Hello!World!",output.txt中将会有输出结果"Hello!World"!。

除了标准输出流out之外,Java程序在执行之后,还会开启标准输入流in与标准错误输出流err,下面先说明标准输入流in。

标准输入流in也是用System类所提供的静态对象,在程序开始之后它会自动开启,对应至键盘或其它的输入来源,准备接受使用者或其它来源的输入,您可以使用read()方法来读取输入,不过通常很少直接使用它,而会使用一个Scanner对象为输入流作后处理,方法在取得使用者输入标准错误输出流err也是在程序执行后自动开启,它会将指定的字符串输出至显示装置或其它指定的装置,与标准输出流out不同的是,它会立即显示指定的(错误)讯息给使用者知道,例如即使您指定程序将结果重新导向至文档,err输出流的讯息并不会被重新导向,而仍会显示在指定的显示装置上,下面这个例子给您一个简单的测试方式:简介过了。

HelloWorld.java

public class HelloWorld{

public static void main(String[] args){

System.out.println("Hello!World!");

System.err.println("ErrorMessageTest");

}

}

在编译程序之后,请如下执行程序,您会发现输出结果如下:

javaHelloWorld>>output.txt

ErrorMessageTest

开启output.txt之后,您会发现当中只有"Hello!World!"讯息,而ErrorMessageTest讯息并没有被导向至文档中,而是直接显示在Console(即操纵、控制台)(或终端机)中。

要重新导向标准输出是用'>',标准输入则是'<',而'>>'除了重导标准输出之外,还有附加的功能,也就是会把输出附加到被导向的目标文档后头,如果目标文档本来不存在,那么效果就和'>'一样。

1.6 Console(即操纵、控制台)输出格式控制

标准输出通常是文字模式为主的主控台(终端机),这边介绍几个格式控制技巧,在主控台显示时可以协助输出的显示格式。

首先介绍格式字符控制,先表列一些常用的控制字符:

4

System.out.println("\u0048\u0065\u006C\u006C\u006F");

在输出数值时,预设都会以十进位的方式来显示数值,下面这几段程序可以让您分别以不同进位制来显示数值:

intx = 19;

//转成二进位10011

System.out.println(Integer.toBinaryString(x));

//转成十六进位13

System.out.println(Integer.toHexString(x));

//转成八进位23

System.out.println(Integer.toOctalString(x));

在J2SE5.0中,您可以使用System.out.printf()作简单的输出格式设定,例如:

//输出19的十进位表示

System.out.printf("%d%n",19);

//输出19的八进位表示

System.out.printf("%o%n",19);

//输出19的十六进位表示

System.out.printf("%x%n",19);

'%d'表示将指定的数值以十进位表示,'%o'是八进位表示,而'%x'是十六进位表示,'%n'是指输出平台特定的换行字符,如果是在Windows下实际上会置换为'/r/n',如果是Linux下则会置换为'/n'。

下表简单列出了一些常用的转换符号:

5

System.out.printf("example:%.2f%n",19.234);

执行结果会输出:

example:19.23

您也可以指定输出时,至少要预留的字符宽度,例如:

System.out.printf("example:%6.2f%n",19.234);

由于预留了6个字符宽度,不足的部份要由空白字符补上,所以执行结果会输出如下(19.23只占五个字符,所以补上一个空白在前端):

example:19.23

以上只是简短的列出一些常用的输出转换符号,事实上,这些功能都是由java.util.Formatter 所提供的,如果您需要更多关于输出格式的控制,您可以看看线上API文件以查询相关设定。

1.7 Console(即操纵、控制台)(控制台)对象-JDK6

在JDK6中新增了java.io.Console(即操纵、控制台)类,可以让您取得字符为基础的主控台装置,例如,您可以藉由System新增的Console(即操纵、控制台)()方法取得标准输入输出装置的Console(即操纵、控制台)对象,并利用它来执行一些简单的主控台文字输入输出,例如:Console(即操纵、控制台)Demo.java

import java.io.Console(即操纵、控制台);

public class Console(即操纵、控制台)Demo{

public static void main(String[] args){

System.out.print("请输入名称:");

Console(即操纵、控制台)Console(即操纵、控制台)= System.Console(即操纵、控制台)();

Stringname = Console(即操纵、控制台).readLine();

System.out.println("您输入的名称…"+name);

}

}

执行结果:

请输入名称:Justin

您输入的名称…Justin

对于主控台下的密码输入,Console(即操纵、控制台)类还提供有一个简单readPassword()方法,在读取使用者于主控台下输入的密码时,不会显示使用者输入的字符(这在过去要用其它麻烦的方式来达到),例如:

Console(即操纵、控制台)Demo.java

import java.io.Console(即操纵、控制台);

public class Console(即操纵、控制台)Demo{

6

public static void main(String[] args){

System.out.print("请输入名称:");

Console(即操纵、控制台)Console(即操纵、控制台)= System.Console(即操纵、控制台)();

Stringname = Console(即操纵、控制台).readLine();

char[]password = Console(即操纵、控制台).readPassword("请输入密码:");

System.out.println("您输入的名称…"+name);

System.out.println("您输入的密码…"+new String(password));

}

}

执行结果:

请输入名称:Justin

请输入密码:

您输入的名称…Justin

您输入的密码 (123456)

Console(即操纵、控制台)类也提供有reader()与writer()方法,可以传回Reader、Writer对象,以便进行其它的IO处理,例如结合Scanner一同使用:

Scanner scanner = new Scanner(System.Console(即操纵、控制台)().reader());

要注意的是,以javaw所执行的应用程序,没有主控台(Console(即操纵、控制台)),也就取不到Console(即操纵、控制台)对象(例如在Eclipse中)。

2.基础入门

2.1资料型态

程序在执行的过程中,需要运算许多的信息,也需要储存许多的信息,这些信息可能是由使用者输入、从文档中取得,甚至是由网路上得到,在程序运行的过程中,这些信息透过“变数”(V ariable)加以储存,以便程序随时取用。

一个变数用来指向一个内存空间,资料就是储存在这个空间中,使用变数名称来取得资料相信会比使用内存位置来得方便;然而由于资料在储存时所需要的容量不一,不同的资料必须要配给不同的空间大小来储存,在Java中对不同的资料区分有几种不同的“资料型态”(Datatype)。

在Java中基本的资料型态主要区分为“整数”(Integer)、“位元”(Byte)、“浮点数”(Float)、“字符”(Character)与布林数(Boolean)几种,而这几种还可以细分,如下所示:

整数

只储存整数数值,可细分为“短整数”(short)(占2个位元组)、整数(int)(占4个位元组)与长整数(long)(占8个位元组),长整数所占的内存比整数来得多,可表示的数值范围也就较大,同样的整数可表示的整数数值范围也比短整数来得大。

位元

Java提供有byte资料型态,专门储存位元资料,例如影像位元资料,一个byte资料型态占一个位元组,而必要的话,byte资料型态也可以用于储存整数数值。

浮点数

主要用来储存小数数值,也可以用来储存范围更大的整数,可分为浮点数(float)(占4个位元组)与倍精度浮点数(double)(占8个位元组),倍精度浮点数所使用的内存空间比浮点数来得多,可表示的数值范围与精确度也比较大。

字符

用来储存字符,Java的字符采Unicode编码,其中前128个字符编码与ASCII编码相容;每个字符资料型态占两个位元组,可储存的字符范围由\u0000到\uFFFF,由于Java的字符采用Unicode

7

编码,一个中文字与一个英文字母在Java中同样都是用一个字符来表示。

布林数

占内存2个位元组,可储存true与false两个数值,分别表示逻辑的“真”与“假”。

因为每种资料型态所占有的内存大小不同,因而可以储存的数值范围也就不同,例如整数int 的内存空间是4个位元组,所以它可以储存的整数范围为-2147483648至2147483647,如果储存值超出这个范围的话称之为“溢值”(Overflow),会造成程序不可预期的结果,您可以使用下面这个程序获得数值的储存范围:

DataTypeMaxMin.java

public class DataTypeMaxMin{

public static void main(String[] args){

System.out.printf("shortrange:%d~%d\n",

Short.MAX_VALUE,

Short.MIN_VALUE);

System.out.printf("intrange:%d~%d\n",

Integer.MAX_V ALUE,

Integer.MIN_V ALUE);

System.out.printf("longrange:%d~%d\n",

Long.MAX_V ALUE,

Long.MIN_VALUE);

System.out.printf("byterange:%d~%d\n",

Byte.MAX_V ALUE,

Byte.MIN_V ALUE);

System.out.printf("floatrange:%e~%e\n",

Float.MAX_V ALUE,

Float.MIN_V ALUE);

System.out.printf("doublerange:%e~%e\n",

Double.MAX_VALUE,

Double.MIN_V ALUE);

}

}

其中Byte、Integer、Long、Float、Double都是https://www.doczj.com/doc/e011681476.html,ng组件下的类名称,而MAX_V ALUE与MIN_V ALUE则是各类中所定义的静态常数成员,分别表示该资料型态可储存的数值最大与最小范围,%e表示用科学记号显示,执行结果如下所示:

shortrange:32767~-32768

intrange:2147483647~-2147483648

longrange:9223372036854775807~-9223372036854775808

byterange:127~-128

floatrange:3.402823e+38~1.401298e-45

doublerange:1.797693e+308~4.900000e-324

其中浮点数所取得是正数的最大与最小范围,加上负号即为负数的最大与最小范围。

2.2变数、常数

资料是储存在内存中的一块空间中,为了取得资料,您必须知道这块内存空间的位置,然而若使用内存位址编号的话相当的不方便,所以使用一个明确的名称代表储存在内存中的资料,变数(Variable)是一个指向资料储存空间的参考,您将资料指定给变数,就是将资料储存至对应的内存空间,调用变数,就是调用对应的内存空间的资料供您使用。

在Java中要使用变数,必须先宣告变数名称与资料型态,例如:

8

intintNum;//宣告一个整数变数

doubledblNum;//宣告一个倍精度浮点数变数

就如上面所举的例子,我们使用int、float、double、char等关键字(Keyword)来宣告变数名称并指定其资料型态,变数在命名时有一些规则,它不可以使用数字作为开头,也不可以使用一些特殊字符,像是*&^%之类的字符,而变数名称不可以与Java内定的关键字同名,例如int、float、class 等等。

变数的命名有几个风格,主要以清楚易懂为主,初学者为了方便,当使用一些简单的字母来作为变数名称,这会造成日后程序维护的困难,命名变数时发生同名的情况也会增加。

在过去曾流行过匈牙利命名法,也就是在变数名称前加上变数的资料型态名称缩写,例如intNum 用来表示这个变数是int整数资料型态,fltNum表示一个float资料型态,然而随着现在程序的发展规模越来越大,这种命名方式已经不被鼓励。

过去的程序在撰写时,变数名称的长度会有所限制,但现在已无这种困扰,因而现在比较鼓励用清楚的名称来表明变数作用,通常会以小写字母作为开始,并在每个单字开始时第一个字母使用大写,例如:

intageForStudent;

intageForTeacher;

像这样的名称可以让人一眼就看出这个变数的作用,这样的命名方式,在Java程序设计领域中是最常看到的一种。

变数名称可以使用底线作为开始,通常使用底线作为开始的变数名称,表示它是私用的(Private),只在程序的某个范围使用,外界并不需要知道有这个变数的存在,通常这样的变数名称常用于面向对象程序设计中类的私有成员(Privatemember),这样的命名方式在Java中偶而也会看到(比较常见于C++的程序撰写中),一个宣告的例子如下:

double_window_center_x;

double_window_center_y;

当您在Java中宣告一个变数,就会配置一块内存空间给它,这块空间中原先可能就有资料,也因此变数在宣告后的值是不可预期的,Java对于安全性的要求极高,您不可以宣告变数后,而在未指定任何值给它之前就使用它,编译器在编译时会回报这个错误,例如若宣告变数var却没有指定值给它,则会显示以下讯息:

variablevarmightnothavebeeninitialized

可以的话,尽量在变数宣告后初始其值,您可以使用“指定运算子”(Assignmentoperator)= 来指定变数的值,例如:

intageForStudent = 0;

doublescoreForStudent = 0.0;

charlevelForStudent = 'A';

上面这段程序在宣告变数的时候,同时指定变数的储存值,而您也看到如何指定字符给字符变数,字符在指定时需使用引号''来包括;在指定浮点数时,会习惯使用小数的方式来指定,如0.0,在Java中写下0.0这么一个常数的话,其预设为double资料型态。

在宣告变数之后,您可以直接调用变数名称来取得其所储存的值,下面这个程序是个简单的示范:

UseVariable.java

public class UseVariable{

public static void main(String[] args){

intageForStudent = 5;

doublescoreForStudent = 80.0;

charlevelForStudent = 'B';

System.out.println("年级\t得分\t等级");

9

System.out.printf("%4d\t%4.1f\t%4c",

ageForStudent,

scoreForStudent,

levelForStudent);

}

}

执行结果:

年级得分等级

580.0B

在Java中写下一个数值,称之为字面常量(Literalconstant),它会存在内存的某个位置,您无法改变它的值;而在使用变数的时候,也会使用一种叫“常数”的变数,严格来说它并不是常数,只不过指定数值给这个变数之后,就不可再改变其值,有人为了区分其与常数的差别,还给了它一个奇怪的名称:“常数变数”。

先不要管“常数变数”这个怪怪的名称,其实它终究是个变数而已,只是在宣告变数名称的同时,加上"final"来限定,只不过这个变数一但指定了值,就不可以再改变它的值,如果程序中有其它程序码试图改变这个变数,编译器会先检查出这个错误,例如:

finalintmaxNum = 10;

maxNum = 20;

这一段程序码中的maxNum变数使用final来限定,所以它在指定为10之后,就不可以再指定值给它,所以第二次指定会被编译器指出错误:

cannotassignavaluetofinalvariablemaxNum

使用final来限定的变数,目的通常就是不希望其它的程序码来变动它的值,例如用于循环计数次数的指定(循环之后就会学到),或是像圆周率PI的指定。

2.3算术运算

程序的目的简单的说就是运算、运算还是运算,加减乘除这类的动作是少不得的,在Java中提供运算功能的就是运算子(Operator),例如与算术相关的加(+)、减(-)、乘(*)、除(/)这类的运算子,另外还有一个也很常用的余除运算子(%),这类以数学运算为主的运算子,称之为“算术运算子”(Arithmeticoperator)。

这类运算子的使用基本上与我们学过的加减乘除一样,也是先乘除后加减,必要时加上括号表示运算的先后顺序,例如这个程序码会在主控台显示7:

System.out.println(1+2*3);

编译器在读取程序码时,是由左往右读取的,而初学者往往会犯一个错误,例如(1+2+3)/4,由于一般习惯将分子写在上面,而分母写在下面的方式,使得初学者往往将之写成了:System.out.println(1+2+3/4);

这个程序事实上会是这样运算的:1+2+(3/4);为了避免这样的错误,在必要的时候为运算式加上括号才是最保险的,例如:

System.out.println((double)(1+2+3)/4);

注意在上面的程序码中使用了double限定型态转换,如果不加上这个限定字的话,程序的输出会是1而不是1.5,这是因为在这个Java程序中,1、2、3、4这四个数值都是整数,当程序运算后,会自动去除小数点之后的数字再进行输出,而加上double限定,表示要运算后的值转换为double资料型态,如此小数点之后的数字才不会被去除。

同样的,看看这段程序会印出什么结果?

inttestNumber = 10;

System.out.println(testNumber/3);

答案不是3.3333,而是3,小数点之后的部份被自动消去了,这是因为estNumber是整数,而除10

数3也是整数,运算出来的程序被自动转换为整数了,为了解决这个问题,您可以使用下面的方法:inttestNumber = 10;

System.out.println(testNumber/3.0);

System.out.println((double)testNumber/3);

上面这个程序片段示范了两种解决方式:如果运算式中有一个浮点数,则程序就会先转换使用浮点数来运算,这是第一段程序所使用的方式;第二个方式称之为“限定型态转换”,您使用double 告诉程序先将testNumber的值转换为double,然后再进行除法运算,所以结果会是正确的3.3333;型态转换的限定关键字就是宣告变数时所使用的int、float等关键字。

当您将精确度小的资料型态(例如int)指定给精确度大的资料型态(例如double),这样的指定在精确度并不会失去,所以这样的指定是可行的。

Java对于程序的安全性要求极高,型态转换在某些情况一定要明确指定,就是在使用指定运算子时,将精确度大的指定给精确度小的变数时,由于在精确度上会有遗失的现象,编译器会认定这是一个错误,例如:

inttestInteger = 0;

doubletestDouble = 3.14;

testInteger = testDouble;

System.out.println(testInteger);

这段程序在编译时会出现以下的错误讯息:

possiblelossofprecision

found:double

required:int

testInteger = testDouble

^

1error

如果您确定这是您要的结果,您必须明确加上转换的限定字:

testInteger = (int)testDouble;

%运算子是余除运算子,它计算除法后的余数,一个使用的例子是数字循环,假设有一个立方体要进行360度旋转,每次在角度上加1,而360度后必须复归为0,然后重新计数,这时您可以这么撰写:

count = (count+1)%360;

2.4比较、条件运算

数学上有比较的运算,像是大于、等于、小于等等,Java中也提供了这些运算子,这些运算子称之为“比较运算子”(Comparisonoperator),它们有大于(>)、不小于(> = )、小于(<)、不大于(< = )、等于(= = )以及不等于(! = )。

在Java中,比较的条件成立时以true表示,比较的条件不成立时以false表示,请您看看下面这几行会显示哪些数值:

System.out.println("10>5->"+(10>5));

System.out.println("10> = 5->"+(10> = 5));

System.out.println("10<5->"+(10<5));

System.out.println("10< = 5->"+(10< = 5));

System.out.println("10 = = 5->"+(10 = = 5));

System.out.println("10! = 5->"+(10! = 5));

程序的执行如下所示:

10>5->true

10> = 5->true

10<5->false

11

10< = 5->false

10 = = 5->false

10! = 5->true

比较运算在使用时有个即使是程序设计老手也可能犯的错误,且不容易发现,也就是等于运算子(= = ),注意它是两个连续的等号(= )所组成,而不是一个等号,一个等号是指定运算子,这点必须相当注意,例如若有两个变数x与y要比较是否相等,是写成x = = y,而不是x = y,后者的作用是将y的值指定给x,而不是比较运算。

另一个使用= = 运算时要注意的是,对于对象来说,两个对象参考之间使用= = 作比较时,是比较其名称是否参考至同一对象,而不是比较其内容,您可以参考不可变的(immutable)字符串了解一下这段话的意义。

即然谈到了条件式的问题,来介绍Java中的“条件运算子”(Conditionaloperator),它的使用方式如下:

条件式?成立传回值:失败传回值

条件运算子的传回值依条件式的结果而定,如果条件式的结果为true,则传回冒号前的值,若为false,则传回冒号后的值,下面这个程序可以作个简单的示范:

ConditionalOperator.java

import java.util.Scanner;

public class ConditionalOperator{

public static void main(String[] args){

Scanner scanner = new Scanner(System.in);

System.out.print("请输入学生分数:");

intscoreOfStudent = scanner.nextInt();

System.out.println("该生是否及格?"+

(scoreOfStudent> = 60?'是':'否'));

}

}

执行结果:

请输入学生分数:77

该生是否及格?是

这个程序会依您所输入的分数来判断学生成绩是否不小于60分,以决定其是否及格,如果是则传回字符'是',否则传回字符'否'。

条件运算子(?:)相当的好用,使用得当的话可以省去不少的程序码,例如下面这个程序可以判断使用者输入是否为奇数。

ConditionalOperator.java

import java.util.Scanner;

public class ConditionalOperator{

public static void main(String[] args){

Scanner scanner = new Scanner(System.in);

System.out.print("请输入数字:");

intinputedNumber = scanner.nextInt();

System.out.println("是否为奇数?"+

(inputedNumber%2! = 0?'是':'否'));

}

}

当输入的数为奇数时,就不能被2整除,所以余数一定不是0,在条件式中判断为true,因而传回字符'是',若数值为偶数,则2整除,所以余数为0,在条件式中判断为false,所以传回字符'否'。

12

2.5逻辑、位元运算

大于、小于的运算会了,但如果想要同时进行两个以上的条件判断呢?例如分数大于80但小于90的判断,在逻辑上有所谓的“且”、“或”与“反”,在Java中也提供这几个基本逻辑运算所需的“逻辑运算子”(Logicaloperator),分别为“且”(&&)、“或”(||)及“反相”(!)三个运算子。

来看看下面这个程序会输出什么?

intnumber = 75;

System.out.println((number>70&&number<80));

System.out.println((number>80||number<75));

System.out.println(!(number>80||number<75));

三段程序分别会输出true、false与true三种状况。

接下来看看“位元运算子”(Bitwiseoperator),在数位设计上有AND、OR、NOT、XOR与补数等运算,在Java中提供这些运算的就是位元运算子,它们的对应分别是AND(&)、OR(|)、XOR (^)与补数(~)。

如果您不会基本的位元运算,以下可以提供一个程序来显示各个运算的结果:

BitWiseOperator.java

public class BitwiseOperator{

public static void main(String[] args){

System.out.println("AND运算:");

System.out.println("0AND0\t\t"+(0&0));

System.out.println("0AND1\t\t"+(0&1));

System.out.println("1AND0\t\t"+(1&0));

System.out.println("1AND1\t\t"+(1&1));

System.out.println("\nOR运算:");

System.out.println("0OR0\t\t"+(0|0));

System.out.println("0OR1\t\t"+(0|1));

System.out.println("1OR0\t\t"+(1|0));

System.out.println("1OR1\t\t"+(1|1));

System.out.println("\nXOR运算:");

System.out.println("0XOR0\t\t"+(0^0));

System.out.println("0XOR1\t\t"+(0^1));

System.out.println("1XOR0\t\t"+(1^0));

System.out.println("1XOR1\t\t"+(1^1));

}

}

执行结果:

AND运算:

0AND00

0AND10

1AND00

1AND11

OR运算:

0OR00

0OR11

1OR01

1OR11

XOR运算:

0XOR00

13

0XOR11

1XOR01

1XOR10

Java中的位元运算是逐位元运算的,例如10010001与01000001作AND运算,是一个一个位元对应运算,答案就是00000001;而补数运算是将所有的位元0变1,1变0,例如00000001经补数运算就会变为11111110,例如下面这个程序所示:

bytenumber = 0;

System.out.println((int)(~number));

这个程序会在主控台显示-1,因为byte占内存一个位元组,它储存的0在内存中是00000000,经补数运算就变成11111111,这在电脑中用整数表示则是-1。

要注意的是,逻辑运算子与位元运算子也是很常被混淆的,像是&&与&,||与|,初学时可得多注意。

位元运算对初学者来说的确较不常用,但如果用的恰当的话,可以增进不少程序效率,例如下面这个程序可以判断使用者的输入是否为奇数:

BitWiseOperator.java

import java.util.Scanner;

public class BitwiseOperator{

public static void main(String[] args){

Scanner scanner = new Scanner(System.in);

System.out.print("请输入数字:");

intinputedNumber = scanner.nextInt();

System.out.println("是否为奇数?"+

((inputedNumber&1)! = 0?'是':'否'));

}

}

执行结果:

请输入数字:8

是否为奇数?否

这个程序得以运算的原理是,奇数的数值若以二进位来表示,其最右边的位元必为1,而偶数最右边的位元必为0,所以我们使用1来与输入的值作AND运算,由于1除了最右边的位元为1之外,其它位元都会是0,与输入数值AND运算的结果,只会留下最右边位元为0或为的结果,其它部份都被0AND运算遮掉了,这就是所谓“位元遮罩”,例如:

00000100->4

00000001->1

----------

00000000->判断为偶数

00000011->3

00000001->1

----------

00000001->判断为奇数

XOR的运算较不常见,这边举个简单的XOR字符加密例子,先看看程序:

XorCode.java

public class XorCode{

public static void main(String[] args){

charch = 'A';

System.out.println("beforeencoding:"+ch);

ch = (char)(ch^0x7);

14

System.out.println("afterencoding:"+ch);

ch = (char)(ch^0x7);

System.out.println("decoding:"+ch);

}

}

执行结果:

beforeencoding:A

afterencoding:F

decoding:A

0x7是Java中整数的16进位写法,其实就是10进位的7,将位元与1作XOR的作用其实就是位元反转,0x7的最右边三个位元为1,所以其实就是反转ch的最后两个位元,如下所示:01000001->65->对应ASCII中的'A'

00000111->0x7

----------

01000110->70->对应ASCII中的'F'

同样的,这个简单的XOR字符加密,要解密也只要再进行相同的位元反转就可以了。

要注意的是,虽然在说明时都只取8个位元来说明,但实际的位元在运算时,需依资料型态所占的内存长度而定,例如在使用int型态的0作运算时,要考虑的是32个位元,而不是只有8个位元,因为int占有4个位元组。

在位元运算上,Java还有左移(<<)与右移(>>)两个运算子,左移运算子会将所有的位元往左移指定的位数,左边被挤出去的位元会被丢弃,而右边会补上0;右移运算则是相反,会将所有的位元往右移指定的位数,右边被挤出去的位元会被丢弃,至于左边位元补0或补1则视最左边原来的位元而定,如果原来是0就补0,是1就补1,您还可以使用>>>运算子,这个运算子在右移后一行在最左边补上0。

可以使用左移运算来作简单的2次方运算示范,如下所示:

ShiftOperator.java

public class ShiftOperator{

public static void main(String[] args){

intnumber = 1;

System.out.println("2的0次:"+number);

number = number<<1;

System.out.println("2的1次:"+number);

number = number<<1;

System.out.println("2的2次:"+number);

number = number<<1;

System.out.println("2的3次:"+number);

}

}

执行结果:

2的0次:1

2的1次:2

2的2次:4

2的3次:8

实际来左移看看就知道为何可以如此运算了:

00000001->1

00000010->2

15

00000100->4

00001000->8

2.6递增、递减运算

递增、递减与指定运算子,老实说常成为初学者的一个恶梦,因为有些程序中若写得精简,这几个运算子容易让初学者搞不清楚程序的真正运算结果是什么;事实上,使用这几种运算子的目的除了使让程序看来比较简洁之外,还可以稍微增加一些程序执行的效率。

在程序中对变数递增1或递减1是很常见的运算,例如:

inti = 0;

i = i+1;

System.out.println(i);

i = i-1;

System.out.println(i);

这段程序会分别显示出1与0两个数,您可以这么写这个程序:

inti = 0;

System.out.println(++i);

System.out.println(--i);

其中写在变数i之前的++与--就是“递增运算子”(Incrementoperator)与“递减运算子”(Decrementoperator),当它们撰写在变数之前时,其作用就相当于将变数递增1与递减1:++i;//i = i+1;

--i;//i = i-1;

您可以将递增或递减运算子撰写在变数之前或变数之后,但其实两者是有差别的,将递增(递减)运算子撰写在变数前时,表示先将变数的值加(减)1,然后再传回变数的值,将递增(递减)运算子撰写在变数之后,表示先传回变数值,然后再对变数加(减)1,例如:

inti = 0;

intnumber = 0;

number = ++i;//相当于i = i+1;number = i;

System.out.println(number);

number = --i;//相当于i = i-1;number = i;

System.out.println(number);

在这段程序中,number的值会前后分别显示为1与0,再看看下面这段:

inti = 0;

intnumber = 0;

number = i++;//相当于number = i;i = i+1;

System.out.println(number);

number = i--;//相当于number = i;i = i-1;

System.out.println(number);

在这段程序中,number的值会显示前后分别为0与1。

接下来看“指定运算子”(Assignmentoperator),到目前为止只看过一个指定运算子,也就是(= )这个运算子,事实上指定运算子还有以下的几个:

16

有时可能会楞一下,因为不常用的话,这些语法并不是那么的直觉。

使用++、--或指定运算子,由于程序可以直接在变数的内存空间中运算,而不用取出变数值、运算再将数值存回变数的内存空间,所以可以增加运算的效率,但以现在电脑的运算速度来看,这一点的效率可能有些微不足道,除非您这类的运算相当的频繁,否则是看不出这点效率所带来的改善,就现在程序撰写的规模来看,程序的易懂易读有时反而是重点,可以的话尽量将程序写的详细一些会比较好,千万不要为了卖弄语法而滥用这些运算子。

2.7if条件式

为了应付程序所可能遇到的各种状况,Java提供了绦件判断-if,它的语法如下:

if(条件式)

陈述句一;

else

陈述句二;

这个语法的意思,白话来说,就是当条件式成立时(true),则执行陈述句一,要不然就执行陈述句二;如果条件式不成立时并不想作任何事,则else可以省略。

在if后如果有两个以上陈述句,称之为“复合陈述句”(Compoundstatement),此时必须使用{}将复合陈述句包括起来,例如:

if(条件式){

陈述句一;

陈述句二;

}

else{

陈述句三;

陈述句四;

}

下面来写个简单的程序,判断使用者的输入是奇数还是偶数:

ConditionIf.java

import java.util.Scanner;

public class ConditionIf{

public static void main(String[] args){

Scanner scanner = new Scanner(System.in);

System.out.print("请输入数字:");

intinput = scanner.nextInt();

intremain = input%2;

17

if(remain = = 1)

System.out.println(input+"为奇数");

else

System.out.println(input+"为偶数");

}

}

在if中也可以再设定执行的条件,例如:

if(条件式一){

陈述句一;

if(条件式二)

陈述句二;

陈述句三;

}

这只个简单的例子,其中陈述句二要执行,必须同时满足条件式一与二才行;再来看个例子:if(条件式一){

陈述句一;

//其它陈述句

}

else

if(条件式二)

陈述句二;

如果条件式一不满足,就会执行else中的陈述,而我们在这边进行条件式二的测试,如果满足就执行陈述句二,由于Java是个自由格式语言,您可以适当的排列这个程序,这会比较好懂一些:if(条件式一){

陈述句一;

//其它陈述句

}

elseif(条件式二)

陈述句二;

基于这个方式,您可以如下设定多个条件,且易读易懂:

if(条件式一)

陈述一;

elseif(条件式二)

陈述句二;

elseif(条件式三)

陈述句三;

else

陈述句四;

陈述句四会在条件式一、二、三都不成立时执行;下面这个程序是个简单的例子,处理学生的成绩等级问题:

ConditionIf.java

import java.util.Scanner;

public class ConditionIf{

public static void main(String[] args){

Scanner scanner = new Scanner(System.in);

System.out.print("输入分数:");

18

intscore = scanner.nextInt();

if(score> = 90)

System.out.println("得A");

elseif(score> = 80&&score<90)

System.out.println("得B");

elseif(score> = 70&&score<80)

System.out.println("得C");

elseif(score> = 60&&score<70)

System.out.println("得D");

else

System.out.println("得E(不及格)");

}

}

在这边要注意的是,if与else的配对,例如下面这个程序依缩排来看,您觉得有无问题存在?

if(条件式一)

if(条件式二)

陈述句一;

else

陈述句二;

很多人都会以为条件式二的if会与else配对,但事实上是条件式一的if与else配对,加上括号就不会有问题了:

if(条件式一){

if(条件式二)

陈述句一;

else

陈述句二;

}

如果想避免这种错误,在程序中多使用括号是必要的,多写一些总是比少写一些来得保险一点。

2.8switch条件式

switch是Java提供的另一个条件判断陈述式,它只能比较数值或字符,使用适当的话,比if判断式来得更为有效;switch的语法架构如下:

switch(变数名称或运算式){

case符合数字或字符:

陈述句一;

break;

case符合数字或字符:

陈述句二;

break;

default:

陈述三;

}

首先看看switch的括号,当中置放您想要取出数值的变数,取出数值之后,程序会开始与case 中所设定的数字或字符作比对,如果符合就执行以下的陈述句,直到遇到break后离开switch块,如果没有符合的数值或字符,则会执行default后的陈述句,default不一定需要,您可以省去这个部份。

19

来看看上一个范例的成绩等级比对如何使用switch来改写:

ConditionSwitch.java

import java.util.Scanner;

public class ConditionSwitch{

public static void main(String[] args){

Scanner scanner = new Scanner(System.in);

System.out.print("请输入分数:");

intscore = scanner.nextInt();

intlevel = (int)score/10;

switch(level){

case10:

case9:

System.out.println("得A");

break;

case8:

System.out.println("得B");

break;

case7:

System.out.println("得C");

break;

case6:

System.out.println("得D");

break;

default:

System.out.println("得E(不及格)");

}

}

}

在这个程序中,您使用除法并取得运算后的商数,如果大于90的话,除以10的商数一定是9或10(100分时),在case10中没有任何的陈述,也没有使用break,所以会继续往下执行,直到遇到break离开switch为止,所以学生成绩100分的话,也会显示A的成绩等级;如果比对的条件不在10到6这些值的话,会执行default下的陈述,这表示商数小于6,所以学生的成绩等级就显示为E了。

注意在case后的等号是冒号而不是分号,这是个很常键错的符号;如果您比对的是字符,则记得加上单引号(''),例如:

case'A':

这个程序与使用if来判断成绩等级的程序有何不同?如果纯綷比对数字或字符的话,建议使用switch,因为它只会在一开始的switch括号中取出变数值一次,然后将这个值与下面所设定的case 比对,但如果您使用if的话,每次遇到条件式时,都要取出变数值,效率的差异就在这,例如:if(a = = 1)

//....

elseif(a = = 2)

//....

elseif(a = = 3)

//....

这个程序片段中在最差的状况下,也就是a = 3时,共需三次比对,而每次比对都必须取出变数a的值一次,如果换成switch的话:

20

相关主题
文本预览
相关文档 最新文档