admin 管理员组

文章数量: 887021


2024年2月28日发(作者:java技术前沿的论坛)

JAVA(免费版)

第三章

① Java中类的最简单的定义格式如下:

[类的修饰符] class 类名 [extends 父类名] {

变量声明;

构造方法定义;

其他方法定义;

}

② 创建一个类的对象的格式如下:

类名 对象名=new构造方法(实际参数);

③ 在类的外部,访问类中的变量和调用类中的方法格式如下:

对象名.变量名

对象名.方法名(实际参数)

3.1.1 类的修饰符

1.类访问权限修饰符:

public(公共的)

用关键字public修饰一个类,表明该类可以被任何其他类使用。如果一个类没有public修饰符,则这个类只能在它所在包中访问。

2.abstract(抽象的)

用abstract修饰的类是一个不完整的类,称为抽象类,因为该类中含有没有方法体的抽象方法。抽象类没有具体实例。

3.final(最终的)

用final修饰的类称为最终类。最终类不能有子类。

3.1.2 类的成员

一个类定义中可以有以下3种类型的成员。

1.域(field)

通常类中声明的变量称为域,用来描述类的属性或状态。一个类中的域既可以是基本数据类型,也可以是其他类的对象等。

2.方法(method)

是对类中变量进行操作的可执行代码序列,定义了该类对象所具有的行为。

定义在一个类里面的类。

3.内部类

3.1.3 域、域的访问控制修饰符和其他修饰符

1.域的初始化

一个类中如果没有定义构造方法,则编译器会自动生成一个没有参数的构造方法,用来初始化类对象,并将类中变量自动初始化为该类型的默认值。

① 整型初始化为0;

② 实型初始化为0.0f、0.0d;

③ 逻辑型初始化为false;

④ 字符型初始化为‟ u0000‟;

⑤ 类对象初始化为null,表明引用不指向任何内存地址。

2.声明其他类对象作为一个类的域

类的域(变量)可以是基本数据类型,也可以是其他类的对象。如果一个类定义中包含另一个类的实

1

例,通常称为“HAS-A”,表示包含关系,即一个类实例“具有”对另一个类实例的引用。

3.域的访问控制

类的域在类的里面都是可见的,类中的所有方法都可以使用它们。

在类的外部,类中域的可见性由关键字public、private、protected来控制,称为类的域的访问权限修饰符。

4种访问权限所使用的修饰符和含义如下。

① public:用public修饰的成员可以被所有其他的类来访问。

② private:类中限定为private的成员只能被这个类本身访问,在类的外部,类的private成员是不可见的 。

③ protected:类中限定为protected成员。只有其子类(不论是否在同一个包中)以及同一个包内的其他类,才能访问该类的protected成员。

④ 缺省的:如果类成员的访问权限没有设定,这时类的成员具有包访问权限。

请注意,方法定义中的参数和方法体中的变量都是局部变量,不能使用上面的访问权限修饰符。

如果把类中的变量用public修饰,则这些变量完全公开,可以直接访问和修改。

面向对象程序设计中,通过类和类成员的访问控制级别的限定,较好地解决了封装和公开的问题。如4.封装和公开

果将成员变量标识为private,则它在类的外部不可见,使数据得到了封装。为了能够访问这些私有数据,就必须提供public或者protected的成员方法来获取(get)和设置(set)这些private变量的值。

通常获取和设置private变量的方法命名采用以下形式:

[public|protected] 变量类型 get变量名(){

return 变量名;

}

[public|protected] void set变量名(类型 参数名){

合法性检查并赋值;

}

5.静态域

类中的变量用来描述该类对象的属性,它们与每个具体对象相关联,因此也把它们称为类的实例变量。用static修饰的变量称为静态变量或静态域。

当一个变量用static修饰时,表明它不属于任何一个类的具体对象,而是所有对象共享,static变量只有一个拷贝,这个存储单元被所有对象共享。该类的任何一个对象访问和修改它时,都是对这个共享的存储单元进行操作。

由于静态变量属于整个类,即使没有创建任何对象时,类中的static变量也会存在,也可以使用静态变量,这时可以通过类名作前缀访问静态变量:

类名.静态变量

若创建了某个类的具体对象后,可以通过类名或对象名作前缀访问静态变量:

对象名.静态变量

6.最终域(final)

若类中的变量用关键字final修饰,则表明该变量一旦被显示的值(不能默认初始化)初始化后就不可能重新再赋值。因此,final修饰的变量通常是程序中不能改变的常量 。

public static final 类型 常量名=初始值;

常量名大写,名字中包含多个单字时用下划线分隔。

圆周率常量、自然常数Math.E等。基本数据类型包装类中的int类型的最大值_VALUE、最小值_VALUE等。

用final修饰的引用变量,也不能重新赋值来引用另一个对象,但可以修改final修饰的引用对象内的

2

数据。

7.域的声明格式

[public | protected | private] [static] [final] [transient] [volatile] 类型名 成员变量名;

3.1.4静态方法、抽象方法和最终方法

1.方法的访问控制修饰符

方法作为类的成员也有4种访问权限:public、private、protected和缺省的(没有访问控制修饰符)。

用static修饰的方法称为静态方法,它不属于类的具体对象,而是整个类的类方法。

如果一个方法总是以相同的方式运行,即它的运行与类的任何实例没有关系,其行为与对象的状态(实2.静态(static)方法

例变量的值)无关,这时该方法就应该用static修饰,使其成为静态方法。

两种方式调用静态方法:

类名.静态方法

对象名.静态方法

一个类里面的静态方法中只能处理静态变量;静态方法中只能调用静态方法。下面的程序编译时出现错误提示。

3.最终(final)方法

关键字final可用来修饰类中的方法,称为最终方法。将一个方法标识为final的主要目的是防止子类重新定义继承自父类的方法。

4.抽象(abstract)方法

用关键字abstract修饰的方法,称为抽象方法。抽象方法只有方法头,没有方法体,而是以一个分号方法修饰符abstract和final不可能同时使用。

结束。抽象方法的声明通常出现在抽象类和接口中,这些内容将在本章3.3节和3.4节讲述。

5.方法的定义格式

方法的定义格式如下:

[public | protected | private] //指明方法的访问控制级别

[static] //指明是整个类拥有的类方法

[final | abstract] //不能同时使用

[native] //指明是本地方法

[synchronized] //指明是同步方法

返回值类型 方法名(参数列表) [throws 异常] {

….;

}

3.1.5 构造方法

1.构造方法的规则

① 构造方法名称必须与类名相同。

② 构造方法一定不能有返回值类型。

③ 构造方法可以使用3种访问控制修饰符public、protected、private或缺省的,对应的访问级别与类成员一样。

④ 构造方法不能用static修饰,因为构造方法只用于创建类的实例。

⑤ 如果类中不定义任何构造方法,编译器会自动生成默认的无参数的构造方法;如果类中定义了构造方法,编译器不会自动生成默认构造方法。

⑥ 类中的构造方法可以根据需要重载多个参数列表不同的版本。这些重载的构造方法可以相互调用,但必须通过this()调用,且必须作为构造方法内的第一条语句。本节后面将讲述构造方法的this调用。

⑦ 子类构造方法中可以调用其直接父类的构造方法,但必须通过super()调用,且必须作为子类构造方法内

3

的第一条语句。

2.构造方法的重载

当一个类因构造方法的重载而存在多个构造方法时,创建该类的对象的语句会根据给出的实际参数的当一个类有多个重载的构造方法时,构造方法里面可以调用类的其他构造方法,但必须通过this()调个数、参数的类型、参数的顺序自动调用相应的构造方法来完成对象的初始化工作。

用,且必须作为构造方法内的第一条语句。

3.1.6 关键字this

法。

③ 静态变量和静态方法不能通过this作前缀来使用。

④ 类中有多个重载的构造方法时,构造方法中可以通过this()调用其他构造方法,但必须是构造方法① 类定义中使用this,当创建该类的对象后,this代表类对象自身。

② 类中通过this、后跟圆点运算符,之后是类的实例变量名或实例方法名可以使用本类中的变量和方中的第一条语句。

3.1.7 抽象和封装

述。

通过组织包、设定类的访问权限和类成员的访问权限,使类这种数据类型对类的客户隐蔽其实现细节,从而实现数据封装。通过对象的封装,实现了模块化和信息隐藏,有利于程序的可移植性和安全性,同时也利于对复杂对象的管理。

3.3.2 类成员的继承和重新定义

1.定义子类的格式

[类的修饰符] class B extends A {

类的变量定义;

构造方法定义;

方法定义;

}

关键字extends表示继承关系,即类B是类A的子类、类A是类B的父类。

Java中一个类只能有一个直接父类,称为单继承,但一个父类可以派生多个子类。Java的根类是Object类,如果一个类没有使用关键字extends显示的指明其父类,Java中默认其父类是Object类。

2.类成员的继承

子类继承某个父类后,子类便具有父类的特性,从程序代码的角度来说,子类便拥有了父类的所有非私有(private)变量和方法,这些变量和方法通过继承都变成了子类的成员。

3.子类添加成员

在子类中加入自己的变量和方法。在单继承中,子类和它的父类的出发点基本上是相同的,继承的真正目的是定义子类时添加功能,或者对从其父类继承来的某些功能进行修改。

4.重新定义从父类继承来的成员——变量隐藏和方法覆盖

① 变量隐藏

当一个父类变量不适合子类时,子类可以把从父类继承来的同名变量重新定义。子类若要引用父类的 super.变量名

同名变量,要用关键字super作前缀加圆点操作符引用父类的同名变量:

② 方法覆盖

把从父类继承来的方法重写,称为方法覆盖。子类覆盖父类的方法时,方法头要与父类一样,只是对方法体重写,从而完成满足子类的要求。

Java编程首要的任务之一就是创造新的数据类型——类,并描述这些数据类型对象之间的交互。通过对同一类对象的共同属性抽象出来并用数据(变量)来描述,把对象的动态特征抽象为行为,用方法来描

4

如果子类中调用被覆盖的父类中的同名方法,通过super关键字作前缀加圆点操作符实现调用:

super.方法名()

5.方法覆盖的规则

参数列表完全相同;返回类型相同;访问限制相同或更弱,但不能更强;抛出异常相同或更少、更有限的异常。

方法覆盖与方法重载是两个不同的概念。方法的重载是指同一个类中定义多个同名方法,它们的参数列表不同,但可以有不同的返回值类型。重载方法调用时根据其参数类型、个数和顺序来区分。子类可以对继承来的方法重载。方法覆盖是指子类把继承来的方法重新定义,方法头一样,但方法体不同,即方法实现的功能不同,从而满足子类自己的特殊要求。

3.3.3 子类对父类构造方法的调用——关键字super

关键字super的使用规则如下。

① super.变量名:引用被子类隐藏的父类中的变量;

③ super(参数):子类构造方法中调用父类构造方法,但必须是子类构造方法中的第一条语句。this( )② super.方法名:调用被子类覆盖的父类中的方法;

和super( )调用只能有其一,不能同时都有。

3.3.4 父类和子类对象的转换

Java语言允许父类对象和子类的对象之间进行类型转换。子类对象可以自动向父类对象转换,但父类对象转换为子类对象时,必须要强制类型转换,转换的格式为:

(子类名)父类对象

下面的语句使用前面讲过的MyCircle类和MySphere类创建对象,都是合法的:

MyCircle obj1=new MyCircle(8,8,5);

MyCircle obj2=new MySphere(8,8,8,10);

MySphere obj3=( MySphere)obj2;

在运行时,Java总是能够根据引用的实际实例动态地选择将要运行的方法的实际版本。Java能够根据其引用的实例类型正确地调用方法,这是Java中的运行多态性的体现。

当子类实例赋值给父类对象引用后,父类对象引用的实际上是子类实例,但通过这个父类引用只能引用子类中与父类同名的那些成员。若成员变量出现隐藏,引用的是父类变量;若成员方法出现覆盖,引用的是子类方法。

3.3.5 抽象类和最终类

1.抽象类

一种表示抽象概念、不能被实例化的类,其作用是为派生类提供一个恰当的父类。

Java中的抽象方法是只有方法头、没有方法体的方法。

如果一个类中包含抽象方法,则该类必须声明为abstract。

抽象方法只能存在于抽象类(或接口)中。如果一个类继承自某个抽象类,而没有具体实现其父类中的所有抽象方法,则该类也必须声明为抽象类(用abstract修饰)。

2.最终类

如果一个类没有必要(或使其不能)再派生子类时,通常将该类用final关键字修饰,表明它是一个最终类。最终类是处在类的层次结构中最底层的类。

用final修饰的类通常是有固定作用、完成一定标准功能的类,例如Java类库中的数学类(Math)等,该类中封装了数学中的一些常用的数学常量,以及常用数学方法,它们都是完成确定和标准功能的一些方法,Math类已没有必要再派生任何子类,因此Java中将该类定义为final类。

final类不能再派生子类。

3.4.1 接口概述

Java语言不支持多继承,但它通过另外一种机制实现了与类的多继承相似的功能。这种机制就是Java中的

5

接口(interface)。

Java语言的接口中,只能定义静态常量和抽象方法。由于接口中包含的方法都是抽象方法,所以定义接口相当于声明程序开发的一组协议或约定。实际上,Java中的接口可以看成是一个没有具体实现的“类”。凡是需要实现这种特定功能的类,都可以在类声明中使用关键字implements声明该类“继承”这些属性和方法的集合。 接口的定义中包含的是抽象方法,而编写抽象方法的方法体,实现方法的特定功能都是在实现接口的类中具体完成的 。接口也可以继承,但Java中接口可以多继承,即一个接口可以继承多个接口。一个类可以同时实现多个接口。

3.4.2 自定义接口和实现接口

1.如何自定义接口

用关键字 interface 定义接口,接口中的成员只有静态常量和抽象方法,文件名保存为:接口名.java。

接口的定义格式如下:

[public] interface 接口名称 [extends 父接口名列表]

{

//静态常量

[public][static][final] 数据类型 变量名=常量值;

//抽象方法

[public][abstract] 返回值类型 方法名(参数列表);

}

接口中的成员变量必须是public(公有的)、static(静态的)和final(最终的)。

接口中的成员方法必须是public(公共的)和abstract(抽象的)。

接口也具有继承性,通过关键字extends表明继承关系,Java中的接口支持多继承,被继承的多个父接口之间用逗号分隔,形成父接口名列表。

2.如何实现接口

一个类可以实现一个或多个接口,声明实现接口的关键字是implements,后跟要实现的接口名。如果接口中有多个抽象方法,而实现接口的类只需使用其中的一个,也必须为其他抽象方法加上花括号,只是花括号中没有语句。

一个类实现接口时定义格式如下:

[修饰符] class 类名 [extends 父类名] implements 接口A,接口B,…

{

类的成员变量和成员方法;

为接口A中的所有方法编写方法体,实现接口A;

为接口B中的所有方法编写方法体,实现接口B;

}

一个类实现接口后,将继承接口中的所有静态常量,为该类所用。

一个类实现接口后,如果该类不是一个抽象类,则该类的类体中必须为接口中的所有抽象方法编写方一个类实现接口后,接口中的成员就被该类所拥有,因此,在单继承的情况下通过实现多个接口达到法体。

了多继承的目的,增加了类的功能。

3.4.3 Java类库中的接口实现举例

实现多线程(Thread)的Runnable接口,它在包中,该接口中有一个抽象方法run( ):

public interface Runnable {

public void run();

}

Java中处理动作的事件(ActionEvent),如按钮点击事件、文本框的回车事件响应等是通过ActionListener

6

接口实现的,它在包中。ActionListener接口中有一个抽象方法actionPerformed(ActionEvent e):

public interface ActionListener {

public void actionPerformed(ActionEvent e);

//有动作时执行

}

对键盘上键的敲击做出响应,Java中专门定义了名字为KeyListener的接口,它在包中,该接口中包含以下3个响应不同键盘事件(KeyEvent)的抽象方法。

public interface KeyListener {

public void keyTyped(KeyEvent e);

//键敲击(压下并释放)时执行。

public void keyPressed(KeyEvent e);

//键压下时执行。

public void keyReleased(KeyEvent e);

//键释放时执行。

}

上面3个方法中的参数类型KeyEvent是Java中定义的键盘事件类。

KeyEvent类在 包中,该类有一个名字为getKeyChar()的方法,该方法的功能是得到所敲击的键代表的字符。例如,敲击键盘字符键r,方法调用Char()将返回字符‟r‟。

第五章 (1)

5.1.1 异常的基本概念

异常(Exception)也称例外,是在程序运行过程中发生的、打断程序正常执行的事件。异常可分为两大类型:Error类代表编译和系统的错误,不许捕获;Exception类代表标准Java库方法所激发的异常,有人称做公共异常,这是为方便程序员处理异常。

Java语言异常处理类层次如下所示。

Object

Throwable

Error

Exception

5.1.2 异常示例

利用Exception类的方法获取更多的信息。

(1)public String toString():返回描述当前异常对象信息的字符串。

(2)public String getMessage():返回描述当前异常对象信息的详细信息。

(3)public void printStackTrace():没有返回值,屏显当前异常对象使用堆栈的轨迹,即程序先后调用了哪些方法,使得运行过程产生了这个异常对象。

5.1.3 异常机制

Java程序在执行过程中如出现异常,会自动生成一个异常对象,该异常对象被交给Java运行的系统,这个过程称为抛出(throw)异常。当然,程序也可强制抛出异常;Java运行时系统接收到异常对象后,会寻找处理这一异常的代码,并把此异常对象交给其处理,这一过程称为捕获(catch)异常 。

系统定义的运行异常都可由系统自动抛出,用户自定义的异常必须借助throw(抛出)语句来定义何种情况才算是产生了对应此种异常的错误,并抛出这个异常类的对象。

throw 异常对象

含有throw语句的方法必须在方法头中增加throws异常类名列表,格式如下:

修饰符 返回类型 方法名(参数列表)throws 异常类名列表{}

try/catch构造允许用户捕获某段代码的异常。如果一个异常是由try子句中的某语句所导致,Java就试图将

7

此异常递送至适当的catch子句。catch子句可以看成有一个实参且无返回类型的方法声明。一条try子句可以有多个catch子句,分别有不同的实参类型;Java以类似选择重载方法的做法挑出适当的catch子句。

try{语句组

}catch(异常类名 异常形式参数名){异常处理语句组;

}catch(异常类名 异常形式参数名){异常处理语句组;

}catch(异常类名 异常形式参数名){异常处理语句组;

}finally{异常处理语句组;}

如果代码周围没有try/catch子句,或者未找到匹配的catch子句,则异常就会向上抛至调用方法。如果异常仍未得到捕获,则进一步抛至更上一层,直至异常得到处理。

用户可以创建自己的异常,这需要完成如下工作:

(1)声明一个新的异常类,它以Exception类或其他某个已经存在的系统异常类或用户异常类为父类;

(2)为新的异常类定义属性和方法,或隐藏和覆盖父类的属性和方法,使这些属性和方法能体现该类所对应的错误信息。

第五章 (2)

 Java中的异常用于处理非预期的情况,如文件没找到,网络错误,非法的参数

 Java中的异常类定义了程序中遇到的轻微的错误条件。

 Java程序运行过程中所发生的异常事件可分为两类:

 Error: JVM系统内部错误、资源耗尽等严重情况。 Java中的错误类定义了程序中不能恢复的严重错误条件。如内存溢出、类文件格式错误等。这一类错误由Java运行系统处理,不需要我们去处理。

 Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,例如:

 对负数开平方根

 空指针访问

 试图读取不存在的文件

 网络连接中断

public class Test4_1{

public static void main(String[] args) {

String friends[]={"lisa","bily","kessy"};

for(int i=0;i<5;i++) {

n(friends[i]); //friends[4]?

}

}

n("nthis is the end");

}

程序Test4_1编译正确,运行结果:java Test4_1

lisa

bily

kessy

ndexOutOfBoundsException

at Test8_(Test8_:5)

8

Exception in thread "main"

public class NullRef{

}

程序编译正确,运行结果:java NullRef

interException

at (:6)

Exception in thread "main"

public class DivideZero{

}

程序编译正确,运行结果:java DivideZero

常见异常

eticException: / by zero

at (:6)

 RuntimeException

 错误的类型转换

 数组下标越界

 空指针访问

 IOExeption

 从一个不存在的文件中读取数据

 越过文件结尾继续读取

 连接一个不存在的URL

 在编写程序时,要在可能出现错误的地方加上检测的代码,如进行x/y时,要检测分母为0,数据为空,输入的不是数据而是字符等。过多的分支会导致程序的代码加长,可读性差。因此采用异常机制。

 Java程序的执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。

 如果一个方法内抛出异常,该异常会被抛到调用方法中。如果异常没有在调用方法中处理,它继续被抛给这个调用方法的调用者。这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常。

Exception in thread "main"

int x;

int y;

DivideZero c=new DivideZero();

y=3/c.x;

n(“program ends ok!”);

public static void main(String[] args) {

int i=1;

NullRef t=new NullRef();

t=null;

n(t.i);

public static void main(String[] args) {

}

}

9

 如果一个异常回到main()方法,并且main()也不处理,则程序运行终止。

 程序员通常只能处理Exception,而对Error无能为力。

异常举例

public class Test4_2{

public static void main(String[] args) {

try {

for(int i=0;i<5;i++) {

n(friends[i]);

String friends[]={"lisa","bily","kessy"};

}

}

catch(ArrayIndexOutOfBoundsException e) {

}

n("nthis is the end");

n("index err");

}

}

程序Test4_2运行结果:java java4_2

lisa

bily

kessy

index err

this is the end

2.

public class DivideZero1{

}

程序DivideZero1运行结果:java DivideZero1

divide by zero error!

program ends ok!

捕获异常

 捕获异常是通过try-catch-finally语句实现的。

int x;

int y;

DivideZero1 c=new DivideZero1();

try{

}

catch(ArithmeticException e){

}

n("program ends ok!");

n("divide by zero error!");

y=3/c.x;

public static void main(String[] args) {

}

10

try

{

}

catch( ExceptionName1 e )

{

}

catch( ExceptionName2 e )

{

...... //当产生ExceptionName2型异常时的处置措施

}

[ finally{

...... //无条件执行的语句

} ]

 捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码 try

放在try语句块中。

 catch (Exception e)

 在catch语句块中是对异常对象进行处理的代码。每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象,当catch多个时,注意具体异常置前,Exception尽量置后。

如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。

如:中,可以用ArithmeticException类作为参数,也可以用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。但不能是与ArithmeticException类无关的异常,如NullPointerException,那么,catch中的语句将不会执行。

 捕获异常的有关信息:

与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法。

 getMessage( ) 方法,用来得到有关异常事件的信息

 printStackTrace( )用来跟踪异常事件发生时执行堆栈的内容,没有返回值,屏显当前异常对象使用堆栈的轨迹,即程序先后调用了哪些方法,使得运行过程产生了这个异常对象。

 g( )输出异常信息

 finally

 捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。不论在try代码块中是否发生了异常事件,finally块中的语句都会被执行。即使try或catch中使用了return也会执行finally.

 例外:若try或catch中使用了(-1);则不会执行finally.

 finally语句是任选的

1 OutputStreamWriter out = ...

2 tion conn = ...

...... //当产生ExceptionName1型异常时的处置措施

...... //可能产生异常的代码

11

3 try { // ⑸

4 Statement stat = Statement();

5 ResultSet rs = eQuery(

6 "select uid, name from user");

7 while (())

8 {

9 n("ID:" + ing("uid") // ⑹

10 ",姓名:" + ing("name"));

11 }

12 (); // ⑶

13 ();

14 }

15 catch(Exception ex) // ⑵

16 {

17 tackTrace(); //⑴,⑷

18 }

 前面但使用的异常都是RuntimeException类或是它的子类,这些类的异常的特点是:

即使没有使用try和catch捕获,Java自己也能捕获,并且编译通过 ( 但运行时会发生异常使得程序运行终止 )。

 如果抛出的异常是IOException类的异常,则必须捕获,否则编译错误。(当在某方法中throws抛出此类异常,则调用该方法必须catch,否则出错)

 如果父类中的方法抛出多个异常,则子类中的覆盖方法要么抛出相同的异常,要么抛出异常的子类,但不能抛出新的异常(注:构造方法除外)。

IOException异常处理举例

import .*;

public class Test4_3{

public static void main(String[] args) {

FileInputStream in=new FileInputStream("");

int b;

b = ();

while(b!= -1) {

b = ();

}

();

((char)b);

}

}

程序Test8_3编译结果: examplejavac Test4_

exampleTest4_:4: 未报告的异常 tFoundException ;必须被捕获或被声明抛出

FileInputStream in=new FileInputStream("");

b = ();

^

exampleTest4_:6: 未报告的异常 ption ;必须被捕获或被声明抛出

12

^

exampleTest4_:9: 未报告的异常 ption ;必须被捕获或被声明抛出 b = ();

^

exampleTest4_:11: 未报告的异常 ption ;必须被捕获或被声明抛出 ();

^

4 个错误

import .*;

public class Test4_3{

}

声明抛出异常

 声明抛出异常是Java中处理异常的第二种方式

 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。

 在方法声明中用throws子句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

 声明抛出异常举例:

public void readFile(String file) throws FileNotFoundException {

……

// 读文件的操作可能产生FileNotFoundException类型的异常

FileInputStream fis = new FileInputStream(file);

..……

public static void main(String[] args){

}

try{

FileInputStream in=new FileInputStream("");

int b;

b = ();

while(b!= -1) {

}

();

((char)b);

b = ();

}catch (IOException e) {

n(e);

}finally {

n(" It‟s ok!");

}

}

import .*;

public class Test4_5{

public static void main(String[] args){

Test4_5 t = new Test4_5();

13

}

}

try{ //不写atch将发生错误

le();

}catch(IOException e){ }

public void readFile()throws IOException {

}

FileInputStream in=new FileInputStream("");

int b;

b = ();

while(b!= -1) {

}

();

((char)b);

b = ();

重写方法声明抛出异常的原则

public class TestA {

public void methodA() throws IOException {

……

}

重写方法不能抛出比被重写方法范围更大的异常类型

}

public class B1 extends TestA {

public void methodA() throws FileNotFoundException {

……

}

}

public class B2 extends TestA {

public void methodA() throws Exception { //error

……

}

}

人工抛出异常

 Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要需要人工创建并抛出

 首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运行环境)。

 IOException e =new IOException();

 throw e;

 可以抛出的异常必须是Throwable或其子类的实例。下面的语句在编译时将会产生语法错误:

throw new String("want to throw");

创建用户自定义异常类

用户自定义异常类MyException,用于描述数据取值范围错误信息。用户自己的异常类必须继承

14

现有的异常类。

class MyException extends Exception {

private int idnumber;

}

方法的重载(overload)

 方法的重载

 就是在同 一个类中允许同时存在一个以上的同名方法,只要它们的参数个数或类型不同即可。在这种情况下.该方法就叫被重载(overloaded)了,这个过程称为方法的重载(method

overloading)。

 参考程序

 Java的编译器能够根据调用方法时所传递的参数的个数和类型选择相应的方法。重载方法的参数列表必须不同,要么是参数的个数不同,要么是参数的类型不同,重载函数的返回值类型可以相同,也可以不同

 重载构造的条件:方法与类的名称相同,但参数类型或参数个数不同,才能构成方法的重载。例如

?? Point(int x,int y){ }与Point(int a,int b){ }是否为同一个构造方法??

class Point

{

int x,y;

Point(int a,int b)

{x=a;

y=b;

}

void output()

{n(x);

n(y);

}

{ x=x;

y=y;

}

public static void main(String[] args)

{Point pt;

pt=new Point(3,3);

public MyException(String message, int id) {

}

public int getId() {

}

return idnumber;

super(message);

er = id;

void output(int x,int y)

(5,5);

();

}

15

}

分析左边程序结果为多少?是3 3 还是5 5?

特殊变量this

 this变量代表对象本身

 当类中有两个同名变量,一个属于类(类的成员变量),而另一个属于某个特定的方法(方法中的局部变量),使用this区分成员变量和局部变量。

 使用this简化构造函数的调用。

 可以在构造方法的第一行使用this关键字调用其它(重载的)构造方法

分析备注中中this(1,1);的作用及程序结果

 关于实例方法和实例数据成员的进一步说明

一个类所有的实例(对象)调用的成员方法在内存中只有一份拷贝,尽管在内存中可能有多个对象,而数据成员在类的每个对象所在内存中都存在着一份拷贝。this变量允许相同的实例方法为不同的对象工作。每当调用一个实例方法时,this变量将被设置成引用该实例方法的特定的类对象。方法的代码接着会与this所代表的对象的特定数据建立关联。

再论关键字static

 在Java类中声明变量、方法和内部类时,可使用关键字static做为修饰符。

 static标记的变量或方法由整个类(所有实例)共享,如访问控制权限允许,可不必创建该类对象而直接用类名加„.‟调用。

 static成员也称类成员或静态成员,如:类属性、类方法、静态方法等。

 总结

 变量分成员变量(全局)和局部变量

 成员变量分静态(static)成员变量(类变量)和非静态成员变量(实例变量)。

 静态成员变量可以由类直接调用,所有该类的对象(实例)都共享它的空间。而实例变量的操作必须由该类的实例来调用操控,且不同实例的该类变量分配不同的空间。

 对应的方法也有静态方法和实例方法。

类属性应用举例

class Person {

private int id;

public static int total = 0;

public Person() {

}

public class OtherClass {

public static void main(String args[]) {

= 100; // 不用创建对象就可以访问静态成员

n();

Person c = new Person();

//访问方式:类名.类属性 类名.类方法

total++;

id = total;

}

16

}

n(); //输出101

}

类方法(class Method)

没有对象的实例时,可以用类名.方法名()的形式访问由static标记的类方法。

class Person {

private int id;

private static int total = 0;

public static int getTotalPerson() {

return total;

}

public Person() {

total++;

}

public class TestPerson {

public static void main(String[] args) {

n("Number of total is " +alPerson());

//没有创建对象也可以访问静态方法

n( "Number of total is "+ alPerson());

Person p1 = new Person();

id = total;

}

}

类方法

}

 在static方法内部只能访问类的static属性,不能访问类的非static属性。

class Person {

private int id;

private static int total = 0;

public static int getTotalPerson() {

id++; //非法

return total;

}

public Person() {

total++;

}

class Person {

private int id;

因为不需要实例就可以访问static方法,因此static方法 内部不能有this。

id = total;

}

17

private static int total = 0;

public static void setTotalPerson(int total){

=total; //非法,在static方法中不能有this,也不能有super

}

public Person() {

total++;

}

public class TestPerson {

public static void main(String[] args) {

}

符号常量 final

 符号常量( final声明)

 在程序中经常使用某个常量,例如圆周率、最大值等,可以用一个符号常量代替。使用关键字final定义常量,例如:

final double PI=3.1415926;

 作为一种约定,在定义常量时,通常采用大写形式。

 final常量可以在声明的同时赋初值,也可以在构造函数中赋初值。

 为了节省内存,我们通常将常量声明为静态的(static)。

 例:分析备注中的例子;求圆的面积和周长。

 理解继承是理解面向对象程序设计的关键。

 在Java中,通过关键字extends继承一个已有的类,被继承的类称为父类(超类,基类),新的类称为子类(派生类)。

 参看备注中例子

 在Java中,不允许多继承。

 子类中也可创建新的方法。

方法的覆盖(override)

 定义:

 在子类中可以根据需要对从父类中继承来的方法进行改造

 覆盖方法又名方法的重置、重写

 覆盖方法的规则:

 覆盖方法必须和被覆盖方法具有相同的方法名称、参数列表和返回值类型

 覆盖方法不能使用比被覆盖方法更严格的访问权限

 适用范围

 只有子类才能覆盖父类的方法

 分析备注例子

特殊变量super

 特殊变量super,提供了对父类的访问。

 可以使用super访问父类被子类隐藏的变量或覆盖的方法。(参看备注前面的代码)

alPerson(10);

}

id = total;

}

18

 每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。

(参看备注后面的代码)

 构造方法不同于普通方法,不能继承。不能将super(30,40);换成Animal(30,40);

class Animal

{

}

class Fish extends Animal

{

}

class Integration

{

}

多态性

 通过覆盖父类的方法来实现,在运行时根据传递的对象引用,来调用相应的方法。

public static void main(String[] args)

{

//Animal an=new Animal();

Fish fh=new Fish();

}

int height;

Fish()

{ super();

n("fish construct");

}

void breathe()

{

}

e();

=40;

int height,weight;

Animal(int height,int weight)

{

}

void eat()

{

}

void sleep()

{

}

void breathe()

{

}

n("animal breathe");

n("animal sleep");

n("animal eat");

n("animal construct");

super(30,40);

n("fish bubble");

19

 参看备注例

 若将子类对象赋值给父类对象,在调用对应方法时,若有子类方法则调子类方法,若没有则调父类方法。

 多态的两种理解:编译多态(即重载函数)和运行多态(本例中调用不同引用对象执行不同方法)

 一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法

 举例:

Student m = new Student();

误。

= “pku”;

= “pku”;

//合法,Student类有school成员变量

//非法,Person类没有school成员变量

Person e = new Student();

错误的原因:属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错

20


本文标签: 方法 对象 变量 父类 子类