您的位置:寻梦网首页编程乐园Java天地Core JavaJava基础教程
Java 天地

Java基础教程

第一章 Java的产生与特点
第二章 Java程序编译与运行环境
第三章 Java程序设计基础
第四章 Java应用程序的基本结构
第五章 Java的类
第六章 Java图形用户接口
第七章 Java的多线程
第八章 Java的“异常”
第九章 Java的输入输出操作

第三章 Java程序设计基础


3.1 Java编程概况

现在你可以复习一下Java语言的背景材料, 它的基本结构象C/C++, 但任何用面向过程语言编写过程序的人都可以了解Java语言的大部分结构。


3.1.1 程序结构

Java语言的源程序代码由一个或多个编译单元(compilation unit)组成, 每个编译单元只能包含下列内容(空格和注释除外): * 一个程序包语句(package statement ) * 入口语句(import statements) * 类的声明(class declarations) * 界面声明(interface declarations) 每个Java的编译单元可包含多个类或界面, 但是每个编译单元最多只能有一个类或者界面是公共的。 Java的源程序代码被编译之后, 便产生了Java字节代码。Java的字节代码由一些不依赖于机器的指令组成, 这些指令能被Java的运行系统(runtime system)有效地解释。Java的运行系统工作起来如同一台虚拟机。 在当前的Java实现中, 每个编译单元就是一个以.java为后缀的文件。 每个编译单元有若干个类, 编译后, 每个类生成一个.class文件。.class文件是Java虚拟机能够识别的代码。


3.1.2 注释

三种类型如下: //注释一行 /*一行或多行注释*/ /**文档注释**/

文档注释一般放在一个变量或函数定义之前, 指示在任何自动生成文档系统中调入。这些注释都是声明条目的描述。


3.1.3 标识符

变量, 函数, 类和对象的名称都是标识符, 程序员需要标识和使用的东西都需要标识符。 在Java语言里, 标识符以字符或_,$开头, 后面可以包含数字, 标识符是大小写有区别的, 没有长度限制。

有效的标识符 myname ict_network Hello _sys_path $bill

例子: int a_number; char _onechar; float $bill;

关键词: abstract continue for new switch

boolean default goto null synchronized

break do if package this

byte double implements private threadsafe

byvalue else import protected throw

case extends instanceof public transient

catch false int return true

char final interface short try

class finally long static void

const float native super while

其它保留词以下单词被保留使用: cast future generic inner

operator outer rest var


3.1.4 数据类型

Java使用五种基本类型:integer(整数),floating(浮点数),point(指针),Boolean(布尔变量),Character or String(字符或字符串)。

integer整数: 下边给出的数据表示都是整数的例子: 4, 15, 089, 0xAD00

整数长度数据类型表示

8 bits byte

16 bits short

32 bits int

64 bits long

floating 浮点数: 下边给出的数据表示都是浮点数的例子: 6.37, 3.7E15, 3e8

浮点数长度数据类型表示

32 bits float

64 bits double

Boolean 布尔变量: 下边是布尔变量的两种可能取值: true false

Character 字符: 下边给出的都是字符的例子: a (tab) u????(unicode)

String 字符串: 下边给出的都是字符串的例子: "This is a string literal" "中国科学院计算所"

数组: 你可以定义任意类型的数组。

  char s[]; //这是字符型数组;
  int [] array; //这是整型数组;
        //你还可以定义数组的数组。 
  int block[][]=new int [2][3]; 

数组边界在运行时被检测, 避免堆栈溢出和内存崩溃。

在Java里, 数组实际上是一个对象, 数组有一个成员变量: length。你可以用这个成员函数来查看任意数组的长度。

  int a[][] = new int [10][3];
  a.length;  // 10
  a[0].length;   // 3 

创建数组: 在Java里创建数组, 你可使用两种基本方法之一。 创建一个空数组:

  int list[]=new int[50]; 

或你可以用初始数值填充数组:

  String names[] = { "Chenji","Yuan","Chun","Yang" }; 

相当于下面功能:

  String names[]; 
  names = new String[4]; 
  names[0]=new String("Chenji"); 
  names[1]=new String("Yuan"); 
  names[2]=new String("Chun"); 
  names[3]=new String("Yang"); 

在编译时你不能象下例那样创建静态数组。

  int name[50];  //将产生一个编译错误

你也不能用new操作去填充一个没定义大小的数组。

  int name[]; 
  for (int i=0;i<9;i++) { 
    name[i] = i; 
  } 

3.1.5 表达式

Java语言的表达式和C语言非常类似。

运算符运算符(operator)优先级从高到底排列如下:   .   [ ]   ()   ++   --   !   ~   instanceof   *   /   %   +   -   <<   >>   >>>   <   >   <=   >=   ==   !=   &   ^   &&   ||   ? : =   op   =   ,

整数运算符在整数运算时, 如果操作数是long类型, 则运算结果是long类型, 否则为int类型, 绝不会是byte, short或char型。这样, 如果变量i被声明为short或byte, i+1的结果会是int。 如果结果超过该类型的取值范围, 则按该类型的最大值取模。单目整数运算符是:

运算符操作 - 单目非 ~ 位补码 ++ 加1 -- 减1

++运算符用于表示直接加1操作。 增量操作也可以用加运算符和赋值操作间接完成。++ lvalue (左值) 表示lvalue+=1, ++lvalue 也表示lvalue =lvalue +1 (只要lvalue没有副作用)。--运算符用于表示减1操作。++和--运算符既可以作为前缀运算符, 也可以做为后缀运算符。 双目整数运算符是:

运算符操作: ** + 加 - 减 * 乘 / 除 % 取模 & 位与 | 位或 ^ 位异或 << 左移 >> 右移(带符号) >>> 添零右移

整数除法按零舍入。 除法和取模遵守以下等式: ( a/b ) * b + ( a%b ) == a 整数算术运算的异常是由于除零或按零取模造成的。 它将引发一个算术异常。 下溢产生零, 上溢导致越界。 例如: 加1超过整数最大值, 取模后, 变成最小值。一个op=赋值运算符, 和上表中的各双目整数运算符联用, 构成一个表达式。 整数关系运算符<, >, <=, >=, ==和!=产生boolean类型的数据。

布尔运算符布尔(boolean): 变量或表达式的组合运算可以产生新的boolean值。 单目运算符!是布尔非。 双目运算符 &, | 和^是逻辑AND, OR和XOR运算符, 它们强制两个操作数求布尔值。 为避免右侧操作数冗余求值, 用户可以使用短路求值运算符 & & 和 | |。 用户可以使用==和!=, 赋值运算符也可以用 &=、|=、^=。 三元条件操作符? : 和C语言中的一样。

浮点运算符: 浮点运算符可以使用常规运算符的组合: 如单目运算符++、--, 双目运算符+、-、* 和/, 以及赋值运算符+=, -=, *=, 和/=。 此外, 还有取模运算: %和%=也可以作用于浮点数, 例如: a%b和a-((int) (a/b)*b)的语义相同。 这表示a%b的结果是除完后剩下的浮点数部分。 只有单精度操作数的浮点表达式按照单精度运算求值, 产生单精度结果。 如果浮点表达式中含有一个或一个以上的双精度操作数, 则按双精度运算, 结果是双精度浮点数。

数组运算符: 数组运算符形式如下: <expression> [ <expression>] 可给出数组中某个元素的值。 合法的取值范围是从0到数组的长度减1。 取值范围的检查只在运行时核实)。

字符串连接运算符:字符串连接运算符以String对象实现。 运算符"+"完成合并字符串操作, 如果必要则自动把操作数转换为String型。如果操作数是一个对象, 它可定义一个方法toString( ) 返回该对象的String方式, 例如 float a = 1.0 print (“The value of a is”+ a );
字符串连接运算符用到字符串上的例子 String s=“a=”+ a; +=运算符也可以用于String。注意, 左边(下例中的s1)仅求值一次。 s1+=a; //s1=s1+a //若a非String型, 自动转换为String型。

对象运算符: 双目运算符instanceof 测试某个对象是否是指定类或其子类的实例。 例如:

  if (myObject instanceof MyClass) { 
    MyClass anothermyObject=( MyClass) myObject; 
    … 
  }

是判定myObject是否是MyClass的实例或其子类的实例。

强制和转换: Java语言和解释器限制使用强制和转换, 以防止出错导致系统崩溃。 整数和浮点数之间可以来回强制转换, 但整数不能强制转换成数组或对象。对象不能被强制为基本类型。


3.1.6 Java流控制

下面几个控制结构是从C语言借鉴的。

分支结构

if/else分支结构

  if (Boolean) { 
    statemanets; 
  } else { 
    statements; 
  } 

switch分支结构

  switch(expr1) { 
    case expr2: statements; 
    break; 
    case expr3: statements; 
    break; 
    default: statements; 
    break; 
  } 

循环结构for循环结构

  for (init expr1;test expr2;increment expr3) { 
      statements; 
  }

While循环结构

  While(Boolean) { 
    statements; 
  }

Do循环结构

  do { 
    statements; 
  } 
  while (Boolean); 

一般顺序控制

  break [label];
  continue [label];
  reutrn expr; 
  label:statement; 

for循环例子下面是一个程序例子, 画几条线, 分别用红, 绿, 蓝颜色, 这段程序可能是Java函数的一部分:

    int count; 
    for (count=1;count<=12;count++) { 
      switch (count % 3) { 
        case 0: setColor(Color.red); break; 
        case 1: setColor(Color.blue); break; 
        case 2: setColor(Color.green); break; 
      } 
      g.drawLine(10,count*10,80,count*10); 
    } 

3.2 Java变量和函数的实例

Java的类包含变量和函数。 数据变量可以是一些原始的类型, 如int, char等。 成员函数是一些可执行的过程。例如, 下面程序里:

  public class ClassOne { 
    int i; public ClassOne() { 
      i=10; 
    } 
    public void Add_i(int j) { 
      i=i+j; 
    }
  } 

ClassOne包含一个变量i和两个成员函数, ClassOne(int first)和Add_i(int j)。

成员函数: 成员函数是一些可被其它类或自己类调用的处理子程序。 一个特殊的成员函数叫构造函数, 这个函数名称一般与本类名称相同。 它没有返回值。

构造函数和成员函数: 当你在Java里定义一个类时, 你可定义一个或多个可选的构造函数, 当创建本类的一个对象时用某一个构造函数来初始化本对象。 用前面的程序例子来说明, 当ClassOne类创建一个新实例时, 所有成员函数和变量被创建(创建实例)。 构造函数被调用。 ClassOne mc: mc = new ClassOne();

关键词new用来创建一个类的实例, 一个类用new初始化之前并不占用内存, 它只是一个类型定义, 当mc对象初始化后, mc对象里的i变量等于10。 你可以通过对象名来引用变量i。(有时称之为实例变量) mc.i++;//mc实例变量加1 因为mc有ClassOne类的所有变量和成员函数, 我们可以使用同样的语法来调用成员函数 Add_i: Add_i(10); 现在mc.i变量等于21.

结束函数: Java并不支持析构函数(C++里的定义), 因为java本身提供对象无用时自动清除的功能, 同时它也提供了一个自动拉圾箱的成员函数, 在清除对象时被调用:

    Protected void finalize() { 
      close(); 
    } 


3.3 对象有效范围和废物自动回收

对象有一定的生命期并在它的生命期间使用资源, 当一个对象不再被使用时, 它应释放内存,,, 避免内存溢出。 在Java里, 收集和释放内存是一个叫自动废品回收站的线程的责任。这个线程监视对象有效范围并给一个走出有效范围的对象作上标识。

例如:

    String s;//没有分配内存 
    s = new String("oldstring");//分配内存 
    s ="newstring";//重新分配内存(创建新对象)

我们将在以后访问String类时将更加明白它的工作过程, 但它的快速工作过程是这样的:
1. 创建一个新的String类对象并填充以"oldstring"
2. 创建另一个String对象并填充以"newstring" 注意我们创建了两个对象。 Stirng对象 "oldstring"和Stirng对象"newstring"

在第三条语句里, 第一个包括"oldstring"的叫做s的对象已走出了有效范围, 没有任何方法可以再访问他, 我们现在有一个新的对象也叫s, 包含"newstring"。 在下一个废品回收线程, 前一个对象将被标识并清除。


3.4 子类

子类是利用存在的对象创建一个新对象的机制, 比如,如果你有一个Horse类, 你可以创建一个Zebra子类, Zebra是Horse的一种。

  class Zebra extends Horse { 
    int number_OF_stripes: 
  } 

关键词extends来定义对象有的子类。 Zebra是Horse的子类。 Horse类里的所有特征都将拷贝到Zebra类里, 而Zebra类里可以定义自己的成员函数和实例变量。 Zebra称为Horse的派生类或继承。 另 外, 你也许还想覆盖基类的成员函数。 用ClassOne说明, 下面是一个派生类覆盖Add_i功能的例子。

  import ClassOne; 
  public class NewClass extends ClassOne { 
    public void Add_i(int j) { 
      i=i+(j/2); 
    } 
  } 

当NewClass类的实例创建时, 变量i初始化值为10, 但调用Add_i产生不同的结果。

    NewClass mnc; 
    mnc=new NewClass(); 
    mnc.Add_i(10); 

访问控制: Java里当你创建一个新类时, 你可以标明变量和成员函数的访问层次。

  public:
  public void AnyOneCanAccess(){ } 

public实例变量和成员函数可以任意其它类调用。

  protected:
  protected void OnlySubClasses(){} 

protected实例变量和成员函数只能被其子类调用。

  private: 
  private String CreditCardNumber;

private实例变量和成员函数只能在本类里调用。

  friendly: 
  void MyPackageMethod(){} 

缺省的, 如果没有定义任何防火控制, 实例变量或函数缺省定义成friendly, 意味着可以被本包里的任意对象防问, 但其它包里的对象不可防问。

静态成员函数和变量: 有些时候, 你创建一个类, 希望这个类的所有实例都公用一个变量。也就是说, 所有这个类的对象都只有实例变量的同一个拷贝。这种方法的关键词是static, 例如:

  class Block { static int number=50; } 

所有从Block类创建的对象的number变量值都是相同的。无论在哪个对象里改变了number的值, 所有对象的number都跟着改变。 同样的, 你可以定义static成员函数, 但这个成员函数不能访问非static函数和变量。

  class Block { 
    static int number = 50; 
    int localvalue; 
    static void add_local(){ 
      localvalue++;//没 有 运 行 
    } 
    static void add_static() { 
      number++;//运行 
    } 
  } 

3.5 this和super

访问一个类的实例变量时, this关键词是指向这个类本身的指针, 在前面ClassOne例子中,我们可以增加构造函数如下:

  public class ClassOne { 
    int i; 
    public ClassOne() { 
      i = 10; 
    } 
    public ClassOne (int value){
      this.i = value; 
    } 
    public void Add_i(int j) { 
      i = i + j; 
    } 
  } 

这里, this指向ClassOne类的指针。 如果在一个子类里覆盖了父类的某个成员函数, 但又想调用父类的成员函数, 你可以用super关键词指向父类的成员函数。

  import ClassOne; 
  public class NewClass extends ClassOne { 
    public void Add_i (int j) { 
      i = i+(j/2); 
      super.Add_i (j); 
    } 
  }

下面程序里, i变量被构造函数设成10, 然后15, 最后被父类(ClassOne)设成25。

  NewClass mnc; 
  mnc = new NewClass(); 
  mnc.Add_i(10); 

3.6 类的类型

至今为止, 我用在类前面只用了一个public关键词, 其实它有下面4种选择:

abstract: 一个abstract类必须至少有一个虚拟函数, 一个abstract类不能直接创建对象, 必须继承子类后才能。

final: 一个final类声明了子类链的结尾, 用final声明的类不能再派生子类。

public: public类能被其它的类访问。 在其它包里, 如果想使用这个类必须先import, 否则它只能在它定义的package里使用。

synchronicable: 这个类标识表示所有的类的成员函数都是同步的。


3.7 抽象类

面向对象的一个最大优点就是能够定义怎样使用这个类而不必真正定义好成员函数。 如果程序由不同的用户实现时是很有用的, 这不需用户使用相同的成员函数名。

在java里Graphics类里一个abstract类的例子如下:

  public abstract class Graphics { 
    public abstract void drawLine(int x1,int y1,int x2, int y2); 
    public abstract void drawOval(int x,int y,int width, int height); 
    public abstract void drawRect(int x,int y,int width, int height); 
    ... 
  }

在Graphics类里声明了几个成员函数, 但成员函数的实际代码是在另外一些地方实现的。

  public class MyClass extends Graphics { 
    public void drawLine (int x1,int y1,int x2,int y2) { 
      <画线程序代码> 
    } 
  }

当一个类包含一个abstract成员函数, 这个类必须定义为abstract类。 然而并不是abstract类的所有的成员函数都是abstract的。 Abstract类不能有私有成员函数(它们不能被实现), 也不能有静态成员函数。


3.8 接口

当你确定多个类的操作方式都很相象时, abstract成员函数是很有用的。 但如果你需要使用这些abstract成员函数, 必须创建一个新类, 这样有时很繁琐。接口提供了一种抽象成员函数的有利方法。 一个接口包含了在另一个地方实现的成员函数的收集。 成员函数在接口里定义为public和abstract。 接口里的实例变量是public, static和final。 接口和抽象的主要区别是一个接口提供了封装成员函数协议的方法而不必强迫用户继承类。

    例 子:  
  public interface AudiClip { //Start playing the clip
    void play(); //Play the clip in a loop. 
    void loop(); //Stop playing the clip 
    void stop(); 
  } 

想使用Audio Clip接口的类使用implenents关键词来提供成员函数的程序代码。

  class MyClass implements AudioClip { 
    void play(){
      <实现代码> 
    } 
    void loop{
      <实现代码> 
    } 
    void stop{
      <实现代码> 
    } 
  } 

优点: 一个接口类可以被任意多的类实现, 每个类可以共享程序接口而不必关心其它类是怎样实现的。

  class MyOtherClass implements AudioClip { 
    void stop(){ 
      <实现代码> 
    } 
    ... 
  } 

内部成员函数: Java还提供了调用C和C++函数的方法。 用native关键词来定义C和C++的函数。

  public class Date { 
    int now; public Date() { 
      now = time (); 
    } 
    private native int time (); 
    static { 
      System.loadLibrary("time"); 
    } 
  } 

一些Java代码写好后, 就需要以下步骤执行:
1. 用javah来创建头文件(.h)
2.用javah来 创 建stub文 件
3.用C和C++写native成员函数的代码
4.编译stub文件和.C文件成一个动态可加载库
5.用java运行java程序或appletviewer运行applet

注意: Native成员函数超出了类的范围。


3.9 包(Packages)

包(Package)由一组类(class)和界面(interface)组成。 它是管理大型名字空间, 避免名字冲突的工具。 每一个类和界面的名字都包含在某个包中。 按照一般的习惯, 它的名字是由“.”号分隔的单词构成, 第一个单词通常是开发这个包的组织的名称。

定义一个编译单元的包: 编译单元的包由package语句定义。 如果使用package语句, 编译单元的第一行必须无空格, 也无注释。 其格式如下: package packageName; 若编译单元无package语句, 则该单元被置于一个缺省的无名的包中。

使用其它包中的类和界面: 在Java语言里提供一个包可以使用另一个包中类和界面的定义和实现的机制。 用import关键词来标明来自其它包中的类。 一个编译单元可以自动把指定的类和界面输入到它自己的包中。 在一个包中的代码可以有两种方式来定义来自其它包中的类和界面:

* 在每个引用的类和界面前面给出它们所在的包的名字;

  //前缀包名法 
  acme. project.FooBar obj=new acme. project. FooBar( ); 

* 使用import语句, 引入一个类或一个界面, 或包含它们的包。 引入的类和界面的名字在当前的名字空间可用。 引入一个包时, 则该包所有的公有类和界面均可用。 其形式如下:

  // 从 acme.project 引入所有类
  import acme.project.*; 

这个语句表示acme.project中所有的公有类被引入当前包。 以下语句从cme.project包中进入一个类Employec_List。

  //从 acme. project而引入 
  Employee_List import acme.project.Employee_list; 
  Employee_List obj = new Employee_List( ); 

在使用一个外部类或界面时, 必须要声明该类或界面所在的包, 否则会产生编译错误。

import(引用): 类包(class package)用import关键词调入, 指定package名字如路径和类名, 用*匹配符可以调入多于一个类名。

  import java.Date; 
  import java.awt.*; 

如果java源文件不包含package, 它放在缺省的无名package。 这与源文件同目录, 类可以这样引入:

  import MyClass。

Java系统包: Java语言提供了一个包含窗口工具箱, 实用程序, 一般I/O, 工具和网络功能的包。

java.applet 这个包包含量了一些设计applet的类, 用一个类Applet和三个接口。 AppletContext; AppletStub; 和AudioClip.

java.awt 另一个窗口工具箱包.awt, 包含了一些产生装饰物和GUI成员的类。 这个package包括: Button, Checkbox, Choice, Component, Graphics, Menu, Pane1, TextArea和TextField。

java.io I/O package包含文件输入/输出类, FileInput Stream和File OutputStream.

java.lang 这个包包含Java语言类, 包含: 对象, 线程, 异常出口, 系统, 整数, 原点, 数学, 字符等。

java.net 这个类支持TCP/IP网络协议, 并包含Socket类, URL和URL相联系的类。

java.util 这个类包含一些程序的同步类, 包含Date, Dictionary类等。


3.10 异常

当在Java程序中发生一个错误时, 例如: 一个变量的值非法, 代码会发现这个错误, 并引发一个异常(exception)。 在缺省的情况下, 异常会输出一个错误消息, 然后中止线程的执行。 但是, 程序自己可以定义异常处理段(exception handler)来截获(catch)异常, 并从错误中恢复。 有一些异常是由Java解释器在运行时刻引发的。 实际上, 任何类都可以定义属于自己的异常, 并使用throw语句引发它们。 一个throw(引发)语句是由throw关键字和一个对象构成。 按常规, 该对象应该是Exception类的实例或其子类的实例。 throw语句会引起执行转向相应的异常处理段。 当一个throw语句执行时, 它下面的所有代码不再执行了, 它所在的方法也不再返回值。 下面的例子将演示如何创建一个Exception的子类, 然后引发一个异常。

  class MyException extends Exception { } 
  class MyClass { 
    void oops() { 
      if ( /* 不 出 现 错 误 */) {
        … 
      } else { /* 出 错 */ 
        throw new MyException( ); 
      } 
    }
  } 

为了定义一个异常处理段, 程序必须用try语句把可能产生异常的代码成组。 在try语句后面跟上一个或多个catch(截获)语句, 每个异常对应一个catch语句。 每个catch语句中包含着异常处理段。 例 如:

  try { 
    p.a=10; 
  } catch ( NullPointerException e) { 
    println(“p was null”); 
  } catch ( Exception e) { 
    println (“other errors occured”); 
  } catch ( Object obj) { 
    println(“Who threw that object?”); 
  } 

catch语句和一个方法定义类似, 只不过该方法只有一个参数, 且无返回类型。 参数可以是一个类或一个界面。 当一个异常发生时, 嵌套的try/catch语句会寻找出与该异常类相匹配的参数。 如果一个参数和指定异常匹配则: * 该参数和指定的异常是同一个类, 或 * 该参数是指定异常的子类, 或 * 如果参数是一个界面, 指定异常类实现了这个界面。 第一个参数和异常匹配的try/catch语句, 则与其匹配的catch语句执行。 在catch语句执行完后, 程序的执行被恢复。 但已不可能恢复到异常发生处再次执行。 例如:

  print ( "now"); 
  try { 
    print ("is"); 
    throw new MyException( ); 
    print ("a"); 
  } catch (MyException e) { 
    print ("the "); 
  } 
  print ("time"); 

打印为“now is the time”。 正如这个例子所示, 异常应该主要用于错误处理, 若用于其它方面会使代码晦涩难懂。 异常处理段是可以嵌套的, 允许异常处理可以发生在多个地方。 嵌套异常处理通常用于当第一个处理程序无法完全从错误中恢复过来的时候, 而不得不执行一些清除代码。 为了把异常处理控制传递给更高层的处理段, 可以再一次对截获对象实现throw操作。 注意再次实现throw异常的方法, throw语句执行完后, 会终止执行。

  try { 
    f. open ( ); 
  } catch(Exception e) { 
    f. close( ); throw e; 
  }

定局语句 finally(定局)语句是用于保证无论在异常是否发生的情况下, 某些代码被执行。 下例说明finally语句的用法:

  try { 
    //做某动些作
  } finally { 
    //此后清除; 
  } 

和以下代码类似

  try { 
    //做某动些作 
  } catch (Object e) { 
    //此后清除; 
    throw e; 
  }

即使try块中包含return, break, continue, throw语句, finally语句也会被执行。 例如: 下面的代码“finally”总是被输出, 而“aftertry”仅在a!=10时被输出。

  try { 
    if (a==10) { 
      return ; 
    } 
  } finally { 
    print ("finally"); 
  } 
  print ("after try"); 

运行时刻异常本节列出的清单是Java解释器引发的各种异常。 当运行时刻发现各种错误, 由解释器引发异常。

ArithmeticException 如果程序试图除0, 或用0取模, 会产生ArithmeticException(算术异常), 其它算术操作不会产生异常。 有关Java如何处理其它算术错误的信息, 见“整数运算符”和“浮点运算符”两节。 例如: 下面的代码将会引发ArithmeticException异常:

  class Arith { 
    public static void main (String args [ ] ) { 
      int j = 0; j = j/j; 
    } 
  }

NullPointerException 当程序试图访问一个空对象中的变量或方法, 或一个空数组中的元素时则引发NullPointerException(空指针异常)。 例如, 访问长度为0的数组a[0]。 有以下类声明, 运行时会引发NullPointerException异常:

  class Null { 
    public static void main(String args [ ]) { 
      String o = null; int a [ ] = null; 
      o.length( ); 
      a[0] = 0; 
    } 
  }

有趣的是, 如果我们引发一个空对象, 也会产一NullPointerException异常。

IncompatibleClassChangeException 当一个类的定义被改变, 而引用该类的其它类没有被重新编译时, 会产生这一异常。有四种类更改会导致运行时刻引发IncompatibleClassChangException异常。 * 一个类中的变量声明由static变成非static, 而其它访问该类这一变量的类没有被重新编译。 * 一个类中的变量声明由非static变成static, 而其它访问该类这一变量的类没有被重新编译。 * 类中声明的某个域被删除, 而其它访问该域的类没有被重新编译。 * 类中声明的某个方法被删除, 而其它访问该方法的类没有被重新编译。

ClassCastException 如果试图把对象o强制成Class C, 而o既不是Class C的实例, 也不是Class C子类的实例, 这时便会产生ClassCastException。

  class ClassCast { 
    public static void main (String args [ ] ) { 
      Object o = new Object( ); 
      String s = (string) o; 
      s.length( ); 
    } 
 } 

NagativeArraySizeException 如果一个数组的长度是负数, 则会引发NagativeArraySizeException(数组负下标)异常。 例如下面类定义的代码在运行时引发这一异常:

  class NegArray { 
    public static void main(String args [ ]) { 
      int a [ ] = new int [-1]; 
      a[0] = 0; 
    } 
  }

OutOfMemoryException 当系统无法再向应用程序提供内存时, 会引发OutOfMemoryException(内存溢出)异常。 这种异常只能出现在创建新对象的时候, 即new被调用的时候。 例如, 下面一段代码在运行时刻会引发OutOfMemoryException异常:

  class Link { 
    int a [ ] = new int [1000000]; 
    Link l; 
  } 
  Class OutOfMem { 
    public static void main(String args [ ]) { 
      Link root = new link( ); 
      Link cur = root; 
      while (true) { 
        cur.l = new Link( ); 
        cur = cur.l; 
      } 
    } 
  }

NoClassDefFoundException 如果一个类被引用, 但在运行时刻, 系统没有找到被引用的类, 这时会引发 NoClassDefFoundException(未找到类定义)异常。 例如, NoClass类的声明如下:

  class NoClass { 
    public static void main(String args [ ]) { 
      C c = new C ( ); 
    } 
  }

当NoClass运行时, 如果解释器找不到C类, 则会产生NoClassDefFoundException。 注意, 在NoClass被编译时C类一定要存在。

IncompatibleType Exception 如果试图为一界面作实例, 则会引发IncompatibleTypeException(类型不兼容)异常。 例如, 下面的代码会引发一个 IncompatibleTypeException。

  Interface I { } 
  class IncompType { 
    public static void main(String args [ ]) { 
      I r = (I) new ("I"); 
    } 
  } 

ArrayIndexOutOfBoundsException 试图访问数组中的一个非法元素时, 会引发ArrayIndexOutOfBoundsException(数组索引越界)异常。 例如:

  Class ArrayOut { 
    public static void main(String args [ ]) { 
      int a [ ]=new int[0]; 
      a[0]=0; 
    } 
  }

UnsatisfiedLinkException 如果一个方法被声明为本机, 但该方法在运行时刻却不能连接到一个例程体上去时, 会产生 UnsatisfiedLinkException(无法连接)异常。 例如:

  Class NoLink { 
    static native void foo( ); 
    public static void main(String args [ ]) { 
      foo( ); 
    } 
  }

InternalException InternalException(内部)异常是不能被引发的。 只有在运行失败作一致性检查时, 才会引发这个异常。


本章小结

1. Java语言的基本结构象C/C++。

2. Java语言的源程序代码由一个或多个编译单元(compilation unit)组成。


(作者: 袁小春  来源: 不详)