📄 java04_11.htm
字号:
<html>
<head>
<meta http-equiv="Content-Language" content="zh-cn">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Java程序设计</title>
</head>
<body background="Bg.gif">
<p align="center"><font size="5"><b>§4.11 接口</b></font></p>
<p align="left"> 接口是Java中用来实现多重继承的一种结构。它无论是从组织形式还是使用角度来看,都可以看成是一中特殊的抽象类。</p>
<p align="left"> 接口使用interface定义,也由成员变量和成员方法两部分构成,可以继承其它接口,也可以被其它接口和类继承——当类继承接口时一般称为“实现”</p>
<p align="left">一、定义接口</p>
<p align="left">
用户可以自行定义接口,一旦接口被定义,任何类都可以实现它,并且,一个类可以实现多个接口。接口的定义如下:</p>
<p align="left">[修饰符] interface 接口名 [extends 父接口1,父接口2,...]{<br>
//定义成员变量 <br>
[public][static][final] 数据类型 变量名=初始值;<br>
.........<br>
//定义成员方法<br>
[public][abstract]返回类型 方法名([参数列表]);<br>
}</p>
<p align="left"> 上面的说明中,interface表明这是一个接口,[修饰符]是访问权修饰符,和类一样,默认访问权是包访问权,我们一般用public来修饰它。和类有区别的是,接口都是abstract的。</p>
<p align="left"> extends和类中的一样,表明后面是接口的父接口。注意,这里的父接口可以有若干多个。接口的继承和类的继承基本原则是一样的,但是更简单(原因稍候就会看到)。</p>
<p align="left"> 接口中的成员变量都是<b>常量</b>。在缺省情况下,接口中的成员变量具有:<br>
public static
final<br>
所联合规定的属性,这三个修饰符中,static和final没有替代的关键字,这意味所有的成员变量都是静态的、最终的,所以也就是常量。唯一可能改变的是访问权限修饰符public,但在接口中,不允许使用protected和private关键字,这意味着所有的变量都是public类型的。</p>
<p align="left">
接口中的成员方法都是抽象方法。在缺省情况下,接口中的成员方法具有:<br>
public
abstract<br>
所联合规定的属性。同样public在这里不可改变,abstract没有可以替代的关键字,又由于abstract和static不可联合使用,所以不可能是静态方法,故所有的方法都是具有public访问权限的抽象实例方法。</p>
<p align="left">
接口的方法都是抽象的,而构造方法不可能为抽象方法,自然也就没有抽象的构造方法。</p>
<p align="left">二、接口的继承 </p>
<p align="left">
由于接口中的成员修饰符比类中的要简单得多,所以继承时的情况也简单得多。下面我们来看一个简单的例子。</p>
<p align="left">interface BaseColors {<br>
int RED = 1, GREEN = 2, BLUE = 4; //这里都是静态公共常量<br>
int getColorValue(int color); //这是一个抽象的公共方法<br>
}<br>
<br>
interface RainbowColors extends BaseColors { //以BaseColors为父接口<br>
int YELLOW = 3, ORANGE = 5, INDIGO = 6, VIOLET = 7; //新增加了4个成员常量<br>
//这个接口自动继承了父接口的3个成员常量和1个方法<br>
}<br>
<br>
interface PrintColors extends BaseColors {<br>
int YELLOW = 8, CYAN = 16, MAGENTA = 32;<br>
int getColorValue(int color); //这里覆盖了父接口的成员方法,但它仍然是抽象的<br>
int
getColorValue(); //还可以重载<br>
}</p>
<p align="left">
在上面的例子中,最后一个接口覆盖了父接口中的方法,这虽然没有语法错误,但实际上是多此一举。</p>
<p align="left">
这里例子都是单继承,所以很简单。但接口最重要的作用是实现多重继承,这就可能会出现歧义,我们看下面这个例子:</p>
<p align="left">interface LotsOfColors extends RainbowColors, PrintColors {//这是多重继承<br>
int FUCHSIA = 17, VERMILION = 43, CHARTREUSE = RED+90;<br>
}<br>
这里的LotsOfColors同时以RainbowColors和PrintColors为父接口,这样它就同时拥有父接口所有成员方法(2个)和成员常量(14个)。我们注意到,RainbowColors和 PrintColors中有一个同名的常量:YELLOW,只是值不同,这就会出现歧义。</p>
<p align="left">
虽然在编译这些接口时并不会报错,但一旦有某个类实现LotsOfColors方法,并引用YELLOW这个量时,就会出现编译错误。</p>
<p align="left">
还有一种常见的歧义是关于成员方法的,把前面的例子改一下:</p>
<p align="left">interface BaseColors {<br>
int getColorValue(int color); //这是一个抽象的公共方法<br>
}<br>
<br>
interface RainbowColors extends BaseColors{ <br>
void getColorValue();<br>
//它还自动继承了int getColorValue(int color)<br>
}<br>
<br>
interface PrintColors extends BaseColors {<br>
int getColorValue();<br>
//它也自动继承了int getColorValue(int color)<br>
}</p>
<p align="left">interface LotsOfColors extends RainbowColors, PrintColors {//这是多重继承<br>
}<br>
我们注意到LotsOfColors分别从RainbowColors和PrintColors中继承了一个int
getColorValue(int color)方法,这两个方法完全一样。由于它们都是抽象方法,所以在LotsOfColors中只会保留一份,这样在类实现接口的时候也只要实现一个就可以了。在大多数情况下,程序员根本不必考虑这些细节问题,这也是用接口来实现多重继承最大的优势。</p>
<p align="left"> 真正会产生歧义的是void
getColorValue()和int getColorValue()方法,由于它们的名称相同,参数相同,只有返回值不同,所以它们既不是重载又不是覆盖,编译器将不知道让LotsOfColors继承哪一个。幸运的是这种错误将会由编译器在编译时指出,无需程序员操心。所以程序员只要注意别让成员常量产生歧义就可以了。</p>
<p align="left">三、接口的实现</p>
<p align="left">
接口最终是要给类来实现的。若干没有继承关系的类可以实现同一个接口,一个类也可以实现多个接口,这些接口都称为该类的父接口或超接口。由于接口中只有抽象方法,所以一个非抽象的类必须实现父接口中<b>所有</b>的抽象方法。若父接口继承了其它的接口,则这些接口的抽象方法也要由该类来完成。若是该类同时是某些类的子类,而其父类实现了这些接口中的一部分方法,则该类只要能继承这些方法,也就视为对这些抽象方法的实现。</p>
<p align="left">
抽象类不受此限制,因为它可以将实现抽象方法的任务交由它的子类来完成。</p>
<p align="left">
我们先来看看类实现接口的一般形式:</p>
<p align="left">[类修饰符] class 类名 [extends 父类名] [implements
接口名1[,接口名2,...]]<br>
{ //类体<br>
//实现接口中的抽象方法<br>
<b>public</b> [返回值类型] 方法名([参数表]){ <br>
......}<br>
}</p>
<p align="left">
注意类在实现接口中的方法时,方法的访问权必须声明成public型(why?),它的参数、返回值也要和接口中的形式完全一致。下面我们来看一个完整的例子:</p>
<p align="left">public interface Colorable {<br>
void setColor(int color);<br>
int getColor();<br>
}<br>
<br>
public interface Paintable extends Colorable {<br>
int MATTE = 0, GLOSSY = 1;<br>
void setFinish(int finish);<br>
int getFinish();<br>
}</p>
<p align="left">class Point { int x, y; }<br>
<br>
class ColoredPoint extends Point implements Colorable {<br>
/* 本类必须实现接口Colorable中所有的抽象方法 */<br>
int color;<br>
public void setColor(int color) { this.color = color; }<br>
public int getColor() { return color; }<br>
}<br>
<br>
class PaintedPoint extends ColoredPoint implements Paintable{<br>
/* 接口Paintable中有4个抽象方法,但PaintedPoint只要实现其中的两个,另两个已经由ColoredPoint实现
*/<br>
int finish;<br>
public void setFinish(int finish) {<br>
this.finish = finish;<br>
}<br>
public int getFinish() { <br>
return finish;<br>
}<br>
}<br>
</p>
<p align="left"><a href="index.htm">回目录</a> <a href="java04_10.htm">上一课</a>
<a href="java04_12.htm">下一课</a></p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -