第5 章类的高级特性
5.1 例题解析
例5.1.1 详细解析Java中的抽象类。
【例题解析】
在Java语言中,abstractclass和interface是支持抽象类定义的两种
机制。在面向对象的概念中,所有的对象都是通过类来描绘的,但反过来
却不是这样,并不是所有的类都是用来描绘对象的。如果一个类中没有包
含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类往往用来表征在对问题领域进行分析、设计中得出的抽象概
念,是对一系列看上去不同但本质上相同的具体概念的抽象。例如,在进
行一个图形编辑软件的开发时,会发现问题领域存在着圆、三角形这样一
些具体概念,它们是不同的,但它们又都属于形状这样一个概念。形状这
个概念在问题领域中是不存在的,它是一个抽象概念。正是因为抽象的概
念在问题领域没有对应的具体概念,所以用于表征抽象概念的抽象类是不
能够实例化的。
例5.1.2 总结Java中abstractclass、interface、final和static的概念。
【例题解析】
在语法层面,Java语言对于abstractclass和interface给出了不同的
定义方式,下面以定义一个名为Demo的抽象类为例来说明这种不同。使
用abstractclass定义Demo抽象类的方式如下。 
abstract class Demo{ 
abstract void method1(); 
abstract void method2(); 
.} 
使用interface定义Demo抽象类的方式如下。 
interface Demo{ 
void method1();

44  JavaEE 零基础入门实验指导与习题解析 
void method2(); 
.} 
首先,在abstractclass方式中,Demo可以有自己的数据成员,也可以有非abstract 
的成员方法;而在interface方式的实现中,Demo只能够有静态的不能被修改的数据成
员,也就是必须是staticfinal的。不过,在interface中一般不定义数据成员,所有的成员
方法都是abstract的。从某种意义上说,interface是一种特殊形式的abstractclass。
abstractclass在Java语言中表示的是一种继承关系,一个类只能使用一次继承关
系。但是,一个类却可以实现多个interface。这也是Java语言的设计者在考虑Java对于
多重继承的支持方面的一种折中处理。
其次,在abstractclass的定义中,我们可以赋予方法默认行为。但是在interface的
定义中,方法却不能拥有默认行为。
abstractclass和interface所反映出的设计理念不同,abstractclass表示的是is-a关
系,interface表示的是like-a关系。
实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法,接
口中则不能有实现方法。
关于抽象类abstractclass: 
(1)只要是有一个或一个以上抽象方法的类必须用abstract声明为抽象类。
(2)抽象类中可以有具体的实现方法。
(3)抽象类中可以没有抽象方法。
(4)抽象类中的抽象方法必须被它的子类实现,如果子类没有实现,则该子类继续为
抽象类。
(5)抽象类不能被实例化,但可以由抽象父类指向的子类实例来调用抽象父类中的
具体实现方法,通常作为一种默认行为。
(6)要使用抽象类中的方法,必须有一个子类继承于这个抽象类并实现抽象类中的
抽象方法,通过子类的实例去调用。
关于接口interface: 
(1)接口中可以有成员变量,且接口中的成员变量必须初始化。
(2)接口中的成员方法只能是方法原型,不能有方法主体。
(3)接口的成员变量和成员方法只能是public(或默认不写,效果一样,都表示
public)。
(4)实现接口的类必须全部实现接口中的方法。
关于关键字final: 
(1)final可用于修饰成员变量、非抽象类(不能与abstract同时出现)、非抽象的成员
方法以及方法参数。
(2)final方法不能被子类的方法重写,但可以被继承。
(3)final类表示该类不能被继承,没有子类;final类中的方法也无法被继承。
(4)final变量表示常量,只能赋值一次,赋值后不能被修改。final变量必须初始化。

上篇 例题解析与习题解答  45 
(5)final不能用于修饰构造方法。
(6)对于final参数,只能使用该参数,不能修改该参数的值。
关于关键字static: 
(1)static可以修饰成员变量和成员方法,但不能修饰类以及构造方法。
(2)被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不
依赖类特定的实例,被类的所有实例共享。
(3)static变量和static方法一般通过类名直接访问,但也可以通过类的实例来访问
(不推荐这种访问方式)。
(4)static变量和static方法同样适用Java修饰符。用public修饰的static变量和
static方法在任何地方都可以通过类名直接访问,用private修饰的static变量和static方
法只能在声明的本类方法及静态块中访问,但不能用this访问,因为this属于非静态
变量。关
于static和final同时使用: 
(1)staticfinal用来修饰成员变量和成员方法,可简单理解为“全局常量”。
(2)对于变量,表示一旦赋值就不可修改,并且通过类名可以访问。
(3)对于方法,表示不可覆盖,并且可以通过类名直接访问。
例5.1.3 分析下列程序片段,指出程序中的错误。
(1)abstract class Name { 
private String name; 
public abstract boolean isStupidName(String name) {} 
} 
【例题解析】
abstractmethod必须以分号结尾,且不带花括号。
(2)public class Something { 
void doSomething () { 
private String s=""; 
int l=s.length(); 
} 
} 
【例题解析】
局部变量前不能放置任何修饰符(private、public和protected)。final可以用来修饰
局部变量,但它是非修饰符。
(3) abstract class Something { 
private abstract String doSomething (); 
} 
【例题解析】
abstract方法不能以private修饰。abstract方法是让子类实现具体细节的,不可以
用private把abstract方法封锁起来。同理,abstract方法前也不能加final。

46  JavaEE 零基础入门实验指导与习题解析
(4)public class Something { 
public int addOne(final int x) { 
return ++x; 
} 
} 
【例题解析】
intx被修饰成final意味着x不能在addOne方法中被修改。
5.2 习题解答
1.接口与抽象类有哪些异同点? 
参考答案: 
在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是
这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘
一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分
析、设计时得出的抽象概念,是对一系列看上去不同、但是本质上相同的具体概念的抽象。
正是因为抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类
是不能够实例化的。
接口与抽象类的主要异同点如下。
(1)接口定义了一组特定功能的对外接口与规范,而并不真正实现这种功能,功能的
实现留给实现这一接口的各个类来完成。抽象类一般作为公共的父类为子类的扩展提供
基础,这里的扩展包括属性上的和行为上的。而接口一般来说不考虑属性,只考虑方法, 
使得子类可以自由地填补或扩展接口所定义的方法。抽象类表示的是is-a关系,接口着
重表示的是can-do关系。
(2)抽象类在Java语言中表示的是一种继承关系,一个类只能使用一次继承。但
是,一个类却可以实现多个接口,接口可以解决多重继承问题。
(3)接口是抽象方法和常量值的定义的集合,从本质上讲,它是一种只包含常量与抽
象方法的特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实
现。接口里面不能有私有的方法或变量,接口中的所有常量必须是publicstaticfinal的, 
且必须给其初值(接口的实现类中不能重新定义,也不能改变其值)。接口中的方法必须
是publicabstract的,这是系统默认的,在定义接口时写不写修饰符都是一样的。抽象类
中可以有私有方法或私有变量,抽象类中的变量默认是友元型,其值可以在子类中重新定
义,也可以重新赋值。
(4)实现抽象类和接口的类必须实现其中的所有方法。在抽象类中可以有自己的数
据成员,也可以有非abstract的成员方法。而在接口中,只能够有静态的不能被修改的数
据成员,所有的成员方法都是abstract的。实现接口时一定要实现接口中定义的所有方
法,而实现抽象类时可以有选择地重写需要用到的方法。在一般的应用中,顶级的是接
口,然后是抽象类实现接口,最后才到具体类实现。

上篇 例题解析与习题解答  47 
2.区分接口与抽象类分别在什么场合使用。
参考答案: 
如果预计要创建类的多个版本,则创建抽象类,因为抽象类提供简单的方法来控制类
版本。如果创建的功能将在大范围的异类对象间使用,则使用接口;如果要设计小而简练
的功能块,则使用接口;如果要设计大的功能单元,则使用抽象类。如果要向类的所有子
类提供通用的已实现功能,则使用抽象类,抽象类主要用于关系密切的对象;而接口适合
为不相关的类提供通用功能。接口多定义对象的行为;抽象类多定义对象的属性。
3.一个类如何实现接口? 实现某接口的类是否一定要重载该接口中的所有抽象
方法?
参考答案: 
一个类使用关键字implements实现某接口。实现某接口的类如果不是抽象类,则需
要通过重载来实现该接口中的所有抽象方法;如果这个类是抽象类,则它可以不必实现该
接口中的所有抽象方法。
4.对于以下程序,运行javaStaticTest后得到的输出结果是什么? 
public class StaticTest { 
static { 
System.out.println("Hi there"); 
}p
ublic void print() { 
System.out.println("Hello"); 
}p
ublic static void main(String args []) { 
StaticTest st1=new StaticTest(); 
st1.print(); 
StaticTest st2=new StaticTest(); 
st2.print(); 
}} 
参考答案: 
Hi there 
Hello 
Hello 
5.编写程序,要求创建一个抽象类Father,其中有姓名、身高、体重等属性及爱好(唱
歌)等方法。创建子类Son类继承Father类,并且增加性格这个属性,改写父类的方法
(爱好)。
参考答案: 
public class test { 
public static void main(String args[]) { 
Son son=new Son("乖儿子",1.78f,61f, "篮球");

48  JavaEE 零基础入门实验指导与习题解析 
son.showInfo(); 
son.singsong(); 
} 
}a
bstract class Father { 
float high,weight; 
protected String name; 
Father(String name,float high,float weight) { 
this.name=name; 
this.high=high; 
this.weight=weight; 
}a
bstract void singsong(); 
abstract void showInfo(); 
}c
lass Son extends Father { 
String specialty; 
Son(String name, float high,float weight,String specialty) { 
super(name,high,weight); 
this.specialty=specialty; 
}v
oid singsong(){ 
System.out.println(name+"is singging loudly!"); 
}v
oid showInfo() { 
System.out.println("姓名:"+ name+";身高:"+ high+";体重:"+ weight+";爱好:"+ 
specialty); 
} 
}