📄 java04_13.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.13 内部类</b></font></p>
<p align="left"> 内部类是由Java1.1之后提出的一种新型的类。我们前面所学习的类都是定义在包中,可以说是顶层类。而内部类则是可以<b>定义</b>在另外一个类的里面,为了便于描述,我们将包含了内部类的这个类称为<b>外部类</b>。这是对Java的重大改进。内部类对于简化事件处理非常有用。</p>
<p align="left">
和一般的类相同,内部类也是由成员变量和成员方法组成,它的定义和使用与普通类也很相似,但有一些细微的区别。</p>
<p align="left">
严格来说,内部类也分为三种:嵌入类(nested)、内部成员类(inner)和本地类。当类的前面有static修饰符时,它就是嵌入类,嵌入类只能和外部类的成员并列,不能定义在方法中。如果类和外部类的成员是并列定义的,且没有static修饰,则称为内部成员类。如果类是定义在某个方法中,则称为本地类。</p>
<p align="left">一、内部类的定义</p>
<p align="left">class HasStatic{ //一个顶层类<br>
static int j = 100;<br>
}<br>
<br>
class Outer{ //这是外部类<br>
int CommVaule=10;<br>
<br>
class Inner extends HasStatic{ //这是一个内部成员类<br>
static final int x = 3; //
这是正确的,可以有静态成员常量<br>
// static int y = 4;
// 错误,不能有静态成员变量<br>
}<br>
<br>
static class NestedButNotInner{ //这是一个嵌入类<br>
static int z = 5;
//正确,嵌入类可以有静态成员变量<br>
}<br>
<br>
public void fun(){ //这是Outer类的一个方法<br>
class localize{ <br>
//这是一个本地类,它定义在方法中,无论fun是否静态,都不能用static修饰localize<br>
//在localize类中,除了静态成员常量之外,不允许定义任何静态成员<br>
int k=3;<br>
static final int s=5;<br>
// static int y = 4;
// 错误,不能有静态成员变量<br>
} <br>
}<br>
}</p>
<p align="left"> 注意:内部类不能和包含它的外部类同名,也不能和其它的成员同名。和普通类一样,内部类也可以是final或abstract类型的。本地类不仅可以定义在一个方法的起始部分,它也可以像方法中的局部变量一样,定义在某个块语句中。不同方法中的本地类是可以同名的,甚至也可以和嵌入类和内部成员类同名(当然最好不要这样做)。</p>
<p align="left">二、内部类访问外部类的成员</p>
<p align="left">
如果内部类要访问包含它的外部类的成员,有很多比较繁琐的规定,我们通过一个具体的例子来说明。我们将上面的Outer类改成这个样子:</p>
<p align="left">class Outer{<br>
int CommValue=10;<br>
static int SV=100;<br>
<br>
class Inner extends HasStatic{<br>
static final int x = 3; <br>
public void call(){ //这个方法可以直接访问外部类的任意成员<br>
System.out.println("外部类的实例变量CommValue="+CommValue);<br>
System.out.println("外部类的静态变量SV="+SV);<br>
vfun();<br>
} <br>
/*
内部成员类除了静态成员常量,不允许包含任何其它静态成员,定义下面这种方法是不行的:
public static void scall(){} */<br>
}<br>
<br>
static class NestedButNotInner extends HasStatic{ //记住:嵌入类是静态的<br>
static int z = 5; <br>
public void call(){
//由于call是在嵌入类中<br>
System.out.println("外部类的静态变SV="+SV);
//它只能访问外部类的静态成员<br>
//无论call是否是静态的,它都不能访问CommValue,也不能调用fun()这个实例方法<br>
//当然,访问本类中的成员则遵守一般类的规则<br>
} <br>
}<br>
<br>
public void vfun(){<br>
final int fv=3;<br>
int fk=10; <br>
class localize{<br>
public void call(){<br>
System.out.println("外部类的静态变量SV="+SV);<br>
System.out.println("外部类的实例变量CommValue="+CommValue); <br>
System.out.println("方法的局部常量fv="+fv);<br>
//它不能访问fk,只能访问方法中定义的局部常量<br>
}<br>
}<br>
<br>
System.out.println("这是外部类的成员方法");<br>
} <br>
<br>
public static void sfun(){<br>
final int fv=3;<br>
int fk=10; <br>
class localize{ //这个本地类可以和vfun()中的本地类同名<br>
public void call(){<br>
System.out.println("外部类的静态变量SV="+SV);<br>
// System.out.println("外部类的实例变量CommValue="+CommValue);
//错误<br>
}<br>
}<br>
<br>
System.out.println("这是外部类的成员方法");<br>
} <br>
}</p>
<p align="left"> Java允许内部类中再嵌套内部类,但这样并没有太多的实际意义,而且使得程序非常难读懂,所以我们不赞成这样做。</p>
<p align="left">现在,我们将内部类定义时所能拥有的成员归纳成下表:</p>
<table border="1" width="80%">
<tr>
<td width="17%"> </td>
<td width="14%">静态常量</td>
<td width="14%">静态变量</td>
<td width="14%">实例变量</td>
<td width="15%">实例常量</td>
<td width="15%">静态方法</td>
<td width="15%">实例方法</td>
</tr>
<tr>
<td width="17%">嵌入类</td>
<td width="14%">√</td>
<td width="14%">√</td>
<td width="14%">√</td>
<td width="15%">√</td>
<td width="15%">√</td>
<td width="15%">√</td>
</tr>
<tr>
<td width="17%">内部成员类</td>
<td width="14%">√</td>
<td width="14%"> </td>
<td width="14%">√</td>
<td width="15%">√</td>
<td width="15%"> </td>
<td width="15%">√</td>
</tr>
<tr>
<td width="17%">本地类</td>
<td width="14%">√</td>
<td width="14%"> </td>
<td width="14%">√</td>
<td width="15%">√</td>
<td width="15%"> </td>
<td width="15%">√</td>
</tr>
</table>
<p align="left">下表是内部类访问外部类成员时所拥有的访问权限(由于内部类是外部类的成员,所以访问其它成员时并不受访问权限修饰符public,private,protected的限制)</p>
<table border="1" width="84%" height="174" rules=all>
<tr>
<td width="20%" height="16"></td>
<td width="14%" height="16">静态常量</td>
<td width="13%" height="16">静态变量</td>
<td width="13%" height="16">实例变量</td>
<td width="13%" height="16">实例常量</td>
<td width="13%" height="16">静态方法</td>
<td width="13%" height="16">实例方法</td>
</tr>
<tr>
<td width="20%" height="33">嵌入类</td>
<td width="14%" height="33">√</td>
<td width="13%" height="33">√</td>
<td width="13%" height="33"> </td>
<td width="13%" height="33"> </td>
<td width="13%" height="33">√</td>
<td width="13%" height="33"> </td>
</tr>
<tr>
<td width="20%" height="31">内部成员类</td>
<td width="14%" height="31">√</td>
<td width="13%" height="31">√</td>
<td width="13%" height="31">√</td>
<td width="13%" height="31">√</td>
<td width="13%" height="31">√</td>
<td width="13%" height="31">√</td>
</tr>
<tr>
<td width="20%" height="32">本地类(在实例方法中)</td>
<td width="14%" height="32">√</td>
<td width="13%" height="32">√</td>
<td width="13%" height="32">√</td>
<td width="13%" height="32">√</td>
<td width="13%" height="32">√</td>
<td width="13%" height="32">√</td>
</tr>
<tr>
<td width="20%" height="32">本地类(在静态方法中)</td>
<td width="14%" height="32">√</td>
<td width="13%" height="32">√</td>
<td width="13%" height="32"> </td>
<td width="13%" height="32"> </td>
<td width="13%" height="32">√</td>
<td width="13%" height="32"> </td>
</tr>
</table>
<p align="left">另外,本地类如果要访问包含自己的方法所定义的局部量的话,只允许访问局部常量。</p>
<p align="left">三、内部类的使用</p>
<p align="left">1. 各类型的内部类之间的相互引用</p>
<p align="left">我们仍然用上面的例子,不过这回简化一下:</p>
<p align="left">class Outer{<br>
<br>
class Inner extends HasStatic{<br>
NestedButNotInner a =new NestedButNotInner();
//内部成员类可以使用嵌入类<br>
public void call(){ <br>
vfun();<br>
} <br>
}<br>
<br>
static class NestedButNotInner extends HasStatic{ <br>
// Inner a =new Inner(); //错误,嵌入类不允许使用内部成员类<br>
public void call(){ } <br>
}<br>
<br>
public void vfun(){ //这是实例方法<br>
class localize{<br>
Inner a = new Inner(); //正确<br>
NestedButNotInner b =new NestedButNotInner(); // 正确<br>
public void call(){ }<br>
}<br>
System.out.println("这是外部类的成员方法");<br>
} <br>
<br>
public static void sfun(){ //这是静态方法<br>
class localize{<br>
// Inner a = new Inner();
//错误,不允许使用内部成员类<br>
NestedButNotInner b =new NestedButNotInner(); // 正确<br>
public void call(){ }<br>
}<br>
class localize2{<br>
localize a =new localize(); //正确<br>
}<br>
localize2 b=new localize2(); //正确<br>
System.out.println("这是外部类的成员方法");<br>
} <br>
}</p>
<p align="left"> 从上面的例子中我们可以看出,内部类之间能不能使用取决于静态还是非静态。但本地类的作用域只在包含它的方法内,外部不能访问它。</p>
<p align="left">2. 在外面访问内部类</p>
<p align="left">
我们们再定义一个类,通过它来使用前面定义的这些内部类。该类定义如下:</p>
<p align="left">class useOuter{<br>
public static void main(String argv[]){<br>
Outer.NestedButNotInner a = new Outer.NestedButNotInner(); //嵌入类可以直接用<br>
Outer.Inner b;<br>
Outer outObj=new Outer();<br>
b=outObj.new Inner(); //内部成员类必须通过外部类创建<br>
a.call();<br>
b.call();<br>
}<br>
} </p>
<p align="left">
由于内部成员类是非静态的,必须通过外部类的实例来引用,嵌入类则不必。而对于本地类,在外部是无法看见的,只能通过调用包含它的方法来使用它。</p>
<p align="left">三、内部类的作用</p>
<p align="left"> 首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能。<br>
<br>
不过你可能要质疑,更改一下方法的不就行了吗?的确,以此作为设计内部类的理由,实在没有说服力。<br>
<br>
真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题——没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。特别是在GUI程序设计时,可以通过定义多个内部类来分别继承各事件的适配器类,解决了多事件的处理问题,而不必为每个接口都写实现代码。<br>
</p>
<p align="left"><a href="index.htm">回目录</a> <a href="java04_12.htm">上一课</a>
<a href="java05_01.htm">下一课</a></p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -