从本章开始,就要正式学习Java语言的程序设计,除了认识程序的架构外,本章还介绍了修饰符、关键字、一些基本的数据类型、变量、常量、运算符、表达式和流程控制语句。通过简单的范例,让大家能够对Java的语法以及编程代码规范有一定的了解。
2.1 java源文件组成元素
Java源文件可包含三个“顶级”要素:
(1)一个包(package)声明(可选)
2)任意数量的导入(import)语句
3)类(class)声明
包的声明:
多数软件系统是庞大的。为了方便管理,通常要将类组织成包。在包中可以存放类,也可以存放子包,从而形成具有层次结构的包。包可以根据需要任意组织,通常,要按照类的用途、含义来组织包。
技术提供了包的机制,以此来组织相关的类。声明包的句法如下:
package <top_pkg_name> [.<sub_pkg_name>];
package命令指明源文件中的类属于某个特定的包。例如:
package com.itjob.java;
com.itjob.java,则最终生成的*.class文件应该在$path\com\itjob\java目录中。
包的引入:
import命令告诉编译器类在哪里。import命令的语法:
import 包名称.子包名称.类名称; //手工导入所需要的类
import 包名称.子包名称.*;à //由 JVM自动加载所需要的类
例如:
import com.itJob.*;
import java.util.List;
import java.io.*;
包的静态引入:
静态导入为Java的新特性,在JDK1.5之后提供了静态导入功能。如果一个类中的方法全部是使用static声明的静态方法,则在导入的时候就可以直接使用“import static”的方式导入,导入的格式如下:import static包.类.*;
如果按照非静态的import导入的话,则调用的时候肯定使用的是:类.方法()。而使用了静态导入“import static包.类.*;”的语句,则在主方法中直接使用该类中的方法即可。
例如TestJava2_1:
//Operate.java
package com.itjob.java;
public class Operate
{ // 里面的方法全部都是 static类型
public static int add(int i, int j)
{ // 加法操作
return i + j;
}
public static int sub(int i, int j)
{ // 减法操作
return i - j;
}
public static int mul(int i, int j)
{ // 乘法操作
return i * j;
}
public static int div(int i, int j)
{ // 除法操作
return i / j;
}
}
//MathApp.java
package com.itjob.test;
import static com.itjob.java.Operate.*;
import static com.qiyu.util.Arith.add;
public class MathApp
{
public static void main(String[] args)
{
System.out.println(add(23, 34));
}
}
编译JAVA带包名的源代码编译:
javac -d Operate.java
javac -d MathApp.java
执行带包名的JAVA应用程序:
java com.itjob.test.MathApp 或:java -classpath com.itjob.test.MathApp
类声明:
需要注意的是,如果将一个类声明成public,则也要将文件名称取成和这个类一样的名称。也就是说,在一个Java文件里,最多只能有一个public类,否则java的文件便无法命名,但是可以有多个非public类。
Jar包:
如果在工作过程中,不想让用户看到我们自己实现的类的具体内容,类似于C和C++中的库文件一样,我们可以利用jar命令来进行封装。JAR是一种与平台无关的文档格式,全称为Java Archive,翻译成中文叫Java归档,它相当于一种压缩格式,可以把众多的文件(Java Applet及Application的类文件、图像或声音等格式)合成一个文件,就像ZIP和RAR。
JAR文件好处:
安全:能够对JAR文件进行数字签名,只让能够识别数字签名的用户使用里面的东西。
压缩:加快读取速度。文件变小,JAR的压缩机制跟ZIP完全相同
包封装:能够让JAR包里面的文件依赖于同一版本的类文件
可移植性:JAR包作为内嵌在java平台内部处理的标准,能够在各种平台上直接使用。
jdk提供了jar的工具,就在java安装目录的bin目录下有一个jar.exe的应用程序,可以使用此工具打包。
用法:jar {ctxu}[vfm0M] [jar-文件] [manifest-文件] [-C 目录] 文件名 ...
-c创建新的归档
-t列出归档内容的列表
-x展开归档中的命名的(或所有的〕文件
-u更新已存在的归档
-v生成详细输出到标准输出上
-f指定归档文件名
-m包含来自指定的清单(manifest〕文件的清单(manifest〕信息
-0只存储方式;未用ZIP压缩格式
-M不产生所有项的清单(manifest〕文件
-I为指定的jar文件产生索引信息
-C更改为指定的目录并包含其中的文件
实例:
1:将两个class文件归档到一个名为classes.jar的归档文件中
jar cvf classes.jar one.class two.class
2:把test目录生成test.jar文件
jar cvf test.jar test
3:将当前目录下的所有的*.class与*.gif文件打包到一个JAR文件中
jar cf classes.jar *.class *.gif
4:显示出jar文件中包的所有目录和文件名列表
jar tvf test.jar
5:解压jar文件
jar xvf test.jar
6:将某个文件加入到某个*.jar文件中
jar uvf classes.jar otherFile.class
除了可以利用jar命令来产生jar包以外,还可以利用MyEclipse的相关工具,使用说明如下:在左边的Package属性页右键包名或*.java,然后选择“Export…”,在弹出的Export对话框中选择Java子目录下的“JAR file”,然后点击“Next”,在弹出的Jar Export对话框中点击“Browse…”,选择你要保存的路径和jar包名称即可。
引入jar包:
有了jar包之后,该如何引入呢?
对于命令行而言,假设生成的jar包在C盘:
编译:javac -classpath .;c:\myfunc.jar TestJar.java
//或javac -classpath c:\myfunc.jar TestJar.java
运行:java -classpath .;c:\myfunc.jar TestJar
//对于运行时利用-classpath指明路径的时候,当前的.不能少
利用MyEclipse,在左侧的Package属性页上右键项目工程文件,选择“Properties”或按快捷键“Alt+Enter”,在弹出的“Properties for …”对话框中选择“Java Build Path”,然后在右边选择“Libraries”属性页,点击“Add External JARs…”,在弹出的对话框中选择你的jar包即可。引入jar包之后,使用jar包里面的类和使用普通的类似。
Java类库和包:
类库是描述提供某种功能的模块的一般术语。类库被组织成许多包,每个包都包含若干个类。 Java类库中几个重要的包:java.lang、java.awt、java.applet、java.net、java.io、java.util。
Java中常见的包说明如图2-1所示:
图2-1 Java常见包
2.2 Java 基本语法
本节将仔细探讨Java语言的一些基本规则及用法。
2.2.1 类(class)
Java程序是由类(class)所组成,至于类的概念在以后会有详细讲解,现在只要先记住所有的Java程序都是由类组成的就可以了。下面的程序片段即为定义类的典型范例:
public class Test // 定义public类Test
{
//…
}
上面的程序定义了一个新的public类Test,这个类的原始程序的文件名称应取名为Test.java。类Test的范围由一对大括号所包含。public是Java的关键字,指的是对于类的访问方式为公有。
需要注意的是,由于Java程序是由类所组成,因此在完整的Java程序里,至少需要有一个类。此外,本书曾在前面提到过在Java程序中,其原始程序的文件名不能随意命名,必须和public类名称一样,因此在一个独立的原始程序里,最多只能有一个public类,却可以有许多non-public类。当然,没有public类也是可以的。
2.2.2 大括号、段及主体
将类名称定出之后,就可以开始编写类的内容。左大括号“{”为类的主体开始标记,而整个类的主体至右大括号“}”结束。每个命令语句结束时,必须以分号“;”做结尾。当某个命令的语句不只一行时,必须以一对大括号“{}”将这些语句包括起来,形成一个程序段(segment)或是块(block)。
再以一个简单的程序为例来说明什么是段与主体。若是暂时看不懂TestJava2_2 这个程序,也不用担心,慢慢的都会讲到该程序中所用到的语句。在下面的程序中,可以看到main() method的主体以左右大括号包围起来;for循环中的语句不只一行,所以使用左右大括号将属于for循环的段内容包围起来;整个程序语句的内容又被第3与第13行的左右大括号包围,这个块属于public类TestJava2_2所有。此外,应该注意到每个语句结束时,都是以分号作为结尾。
范例:TestJava2_2.java
2.2.3 程序运行的起始点 —— main() method
Java程序是由一个或多个类组合而成,程序起始的主体也是被包含在类之中。这个起始的地方称为main(),用左右大括号将属于main()段内容包围起来,称之为method(方法)。
main()方法为程序的主方法,在一个Java程序中有且只能有一个main()方法,它是程序运行的开端,通常看到的main() method如下面的语句片段所示:
public static void main(String args[]) // main() method,主程序开始
{
//…
}
如前一节所述,main() method之前必须加上public static void 这三个标识符。public代表main()公有的method;static表示main()在没有创建类对象的情况下,仍然可以被运行;void则表示main()方法没有返回值。main后的括号()中的参数String args[]表示运行该程序时所需要的参数,这是固定的用法,如果现在不了解也没有关系,在以后的章节中会一一介绍。
2.2.4 Java 程序的注释
为程序添加注释可以用来解释程序的某些语句的作用和功能,提高程序的可读性。也可以使用注释在原程序中插入设计者的个人信息。此外,还可以用程序注释来暂时屏蔽某些程序语句,让编译器暂时不要处理这部分语句,等到需要处理的时候,只需把注释标记取消就可以了,Java里的注释根据不同的用途分为三种类型:
·单行注释
·多行注释
·文档注释
单行注释:就是在注释内容前面加双斜线(//),Java编译器会忽略掉这部分信息。多用于对属性和变量的提示信息。如下所示:
int num;//定义一个整数
多行注释:就是在注释内容前面以单斜线加一个星形标记(/*)开头,并在注释内容末尾以一个星形标记加单斜线(*/)结束。当注释内容超过一行时一般使用这种方法,一般在源文件最开头,对整个源文件的详细说明或多行代码的注释。如下所示:
/*
* int c = 10;
* int x = 5;
*/
通常在一个源文件的开头利用多行注释对整个文件做一些说明,包括文件的名字、功能、作者、创建日期等等相关信息。
文档注释:是以单斜线加两个星形标记(/**)开头,并以一个星形标记加单斜线(*/)结束。用这种方法注释的内容会被解释成程序的正式文档,并能包含进如javadoc之类的工具生成的文档里,用以说明该程序的层次结构及其方法。后面会详细介绍。
请参阅《Java整个源文件的组织管理情况.txt》。
2.2.5 Java 中的标识符
Java中的包、类、方法、参数和变量的名字,可由任意顺序的大小写字母、数字、下划线(_)和美元符号($)组成,但标识符不能以数字开头,不能是Java中的保留关键字。标识符是严格区分大小写的。
·下面是合法的标识符:
yourname
your_name
_yourname
$yourname
·下面是非法的标识符:
class//跟关键字同名
67.9//数字开图
Hello Careers//包含空格
小提示:
刚接触编程语言,可能会觉得记住上面的规则很麻烦,所以标识符最好永远用字母开头,而且尽量不要包含其他的符号。当然还要尽量做到顾名思义。
2.2.6 Java 的关键字
和其他语言一样,Java中也有许多保留关键字,如public、static等,这些保留关键字不能当作标识符使用。下面列出了Java中的保留关键字,这些关键字并不需要强记,因为一旦使用了这些关键字做标识符时,编辑器会自动提示错误。另外,Java关键字都是小写的。
Java中的保留关键字:
abstract、assert、boolean、break、byte、case、catch、char、class、continue、default、do、double、else、enum、extends、false、final、finally、float、for、if、implements、import、instanceof、int、interface、long、native、new、null、package、private、protected、public、return、short、static、super、switch、synchronized、this、throw、throws、transient、true、try、void、volatile、while
要特别注意的是,虽然goto、const在Java中并没有任何意义,却也是保留字,与其它的关键字一样,在程序里不能用来做为自定义的标识符。
2.2.7 Java 的数据类型
数据类型在程序语言的构成要素里,占有相当重要的地位。Java的数据类型可分为原始数据类型与引用数据类型。
原始数据类型也称为基本数据类型,它们包括了最基本的boolean、byte、char、short、int、long、float与double等类型。另一种数据类型为引用数据类型,它是以一种特殊的方式指向变量的实体,这种机制类似于C/C++的指针。这类的变量在声明时是不会分配内存的,必须另外进行开辟内存空间的操作,如字符串与数组均属于这种数据类型。
在这里只是先介绍基本数据类型,引用数据类型会在以后的章节中介绍。
在Java中规定了八种基本数据类型变量来存储整数、浮点数、字符和布尔值。如图2-2所示:
图2-2 Java的数据类型
2.2.7.1 基本数据类型
Java的基本数据类型如表2-1所示:
表2-1 Java的基本数据类型
2.2.7.1.1 整数类型
当数据不带有小数或分数时,即可以声明为整数变量,如3,-147等即为整数。Java中,整数数据类型可以分为long、int、short及byte四种,如表2-2所示:
表2-2 整数型
从上表可以看出,long为64位,也就是8个字节(bytes),可表示范围为-9223372036854775808到9223372036854775807;int为32 位,也就是4个字节,表示范围为-2147483648到2147483647;若是数据值的范围在-32768到32767之间时,可以声明为short(短整数)类型;若是数据值更小,在-128到127之间时,可以声明为byte类型以节省内存空间。
举例来说,想声明一个短整型变量sum时,可以在程序中做出如下的声明:
short sum; //声明snum为短整型
经过声明之后,Java即会在可使用的内存空间中,寻找一个占有2个字节的块供sum变量使用,同时这个变量的范围只能在-32768到32767之间。
需要注意的是,Java把整数常量的数据类型均视为int型,因此,如果在程序中使用了超过2147483647这个大小的常量,编译时将发生错误,如下面的范例:
范例:TestJava2_3.java
//下面这段程序说明了值的可取范围的问题
public class TestJava2_3
{
public static void main(String args[])
{
long num = 329852547553; // 声明长整型变量
System.out.println("num = " + num);
}
}
如果编译上面的程序代码,将会得到下列的错误信息:
TestJava2_3.java:5: integer number too large: 329852547553
long num = 329852547553;
这是因为把整数常量看成是int类型,但329852547553这个整数已超出了int类型所能表示的范围,因此虽然把num的类型设为long,但编译时仍然会发生错误。要解决这个问题,只要在整数常量后面加上一个大写的“L”或小写的“l”即可,此举代表该常量是long类型的整数常量。所以只要把第6行的语句改成:
long num = 329852547553L;
即可成功地编译运行。
·数据类型的最大值与最小值
Java提供了long、int、short及byte四种整数类型的最大值、最小值的代码,以方便设计者使用。最大值的代码是MAX_VALUE,最小值是MIN_VALUE。如果要取用某个类型的最大值或最小值,只要在这些代码之前,加上它们所属的类的全名即可。举例来说,如果程序代码里需要用到长整数的最大值,如图2-3所示的语法表示。
图2-3 代码的表示法
由上面的语法可知,如果要使用某个类型的代码,则必须先指定该类型所在的类库以及该类型所属的类,但因java.lang这个类库属于常用类库,所以默认的Java程序会将它加载,因此在实际的应用上设计者可以将它省略。
Java所提供的整数的最大值与最小值的标识符及常量值,可在表2-3中查阅。若是不懂什么叫类库也没有关系,现在只要会使用它就行了,后面会讲。
表2-3 整数常量的最值
下面程序是输出Java定义的四种整数类型的常量的最大和最小值,可以将程序与上表做对照、比较。
范例:TestJava2_4.java
//下面这段程序调用了表2-3中的方法,可以得到数据类型的最大值和最小值
public class TestJava2_4
{
public static void main(String args[])
{
long long_max = java.lang.Long.MAX_VALUE; //得到长整型的最大值
int int_max = java.lang.Integer.MAX_VALUE; //得到整型的最大值
short short_max = Short.MAX_VALUE; //得到短整型的最大值
byte byte_max = Byte.MAX_VALUE; //得到Byte型的最大值
System.out.println("LONG的最大值:" + long_max);
System.out.println("INT 的最大值:" + int_max);
System.out.println("SHORT的最大值:" + short_max);
System.out.println("BYTE的最大值:" + byte_max);
}
}
输出结果:
LONG的最大值:9223372036854775807
INT 的最大值:2147483647
SHORT的最大值:32767
BYTE的最大值:127
程序TestJava2_4列出了各种整数类型的最大值,通过它的运行,可以了解到Java对于整数的最大值、最小值的规定。可以自己改写程序,输出一下最小值。
·溢出的发生
当整数的数据大小超出了可以表示的范围,而程序中又没有做数值范围的检查时,这个整型变量所输出的值将发生紊乱,且不是预期的运行结果。在下面的程序范例中,声明了一个整型的数,并把它赋值为整型所可以表示范围的最大值,然后将它分别加1及加2。
范例:TestJava2_5.java
//整数值如果超出了自己所可以表示范围的最大值,会出现溢出
public class TestJava2_5
{
public static void main(String args[])
{
int x = java.lang.Integer.MAX_VALUE; // 得到整型的最大值
System.out.println("x = " + x);
System.out.println("x+1 = " + (x + 1));
System.out.println("x+2 = " + (x + 2));
}
}
输出结果:
x = 2147483647
x+1 = -2147483648
x+2 = -2147483647
当最大值加上1时,结果反而变成表示范围中最小的值;当最大值加上2时,结果变成表示范围中次小的值,这就是数据类型的溢出。这个情形会出现一个循环,若是想避免这种情况的发生,在程序中就必须加上数值范围的检查功能,或者使用较大的表示范围的数据类型,如长整型。
当声明了一整数i,其表示的范围为-2147483648 ~ 2147483647之间,当i的值设为最大值2147483647,仍在整数的范围内,但是当x加1或加2时,整数x的值反而变成-2147483648和-2147483647,成为可表示范围的最小及次小值。
上述的情形就像计数器的内容到最大值时会自动归零一样。而在整数中最小值为-2147483648,所以当整数x的值最大时,加上1就会变成最小值-2147483648,也就是产生了溢出。可以参考图3-3来了解数据类型的溢出问题。
图2-4 数据类型的溢出
为了避免int 类型的溢出,可以在该表达式中的任一常量后加上大写的“L”,或是在变量前面加上long,作为强制类型的转换。以TestJava2_6为例,在下面的程序中加上防止溢出的处理,为了方便比较,特地保留一个整数的溢出语句。
范例:TestJava2_6.java
//下面的这段程序当整型发生溢出之后,用强制类型进行转换
public class TestJava2_6
{
public static void main(String args[])
{
int x = java.lang.Integer.MAX_VALUE;
System.out.println("x = " + x);
System.out.println("x + 1 = " + (x + 1));
System.out.println("x + 2 = " + (x + 2L));
System.out.println("x + 3 = " + ((long) x + 3));
}
}
输出结果:
x = 2147483647
x + 1 = -2147483648
x + 2 = 2147483649
x + 3 = 2147483650
程序说明:
1、第6行声明int类型的整数变量x,并赋值为整数最大值,即2147483647。
2、第7行输出x的值,即:2147483647。
3、第8行输出x+1的值,此时溢出发生,运行结果变成-2147483648。
4、第9行输出x+2的值,为了避免溢出发生,在表达式的常量部分2后加上L,执行结果变成2147483649。
5、第10行输出x+3的值,为了避免溢出发生,在表达式的整数部分x之前加上long,执行结果变成2147483650。
由上面的程序可知,处理int 类型的溢出,可以利用强制类型转换方式。但是对于long类型的溢出,就没有处理办法了,此时就需要在程序中加上变量值的界限检查,在运行时才不会发生错误。