第8章 接口
825
2012-6-20

第八章 接口

8.1.1 接口概念的引入

为什么在买USB 电脑鼠标的时候,不需要问电脑配件的商家,USB 鼠标是什么型号的?

也不需要询问是满足什么要求?原因就是USB 接口是统一的、固定不变的一种型号,是一

种规范。所有的厂家都会按照这个规范,来制造USB 接口的鼠标。这个规范说明制作该USB

类型的鼠标应该做些什么,但并不说明如何做。

而Java 程序设计中的接口,也是一种规范。这个接口定义了类应该做什么?但不关心

如何做?即接口中只有方法名,没有方法体。

8.1.2 接口的概念

从专业的角度讲,接口只是说明类应该做什么,但并不指定应该如何去做。在实际开发

过程中,通过类来实现接口。接口只有方法名没有方法体,实现接口就是让其既有方法名又

有方法体。下面就举个有关接口的模型。

接口

应该作的事情一

{............}

应该作的事情二

{............}

应该作的事情三

{............}

这个例子只是声明了要做什么事情,但没有说明如何做,需要一个类去实现它,将它的

方法体完善。

148

8.1.3 接口的声明

接口的声明很简单,使用关键字“Interface”来声明。接口的形式跟类很相似,但要记

住接口是接口,类是类,两者不能混为一谈。接口是要求类如何做的一套规范。下面将举一

个实例,来演示如何声明接口。

///创建一个学校的接口

///在这个接口中,创建了很多个方法,并且这些方法没有方法体

public interface school

{

void setschoolname();

void setclassname();

void setstudentname();

void setstudentcode();

void setstudentsexy();

void setstudentbirthday();

void setfamilyaddress();

String getschoolname();

String getclassname();

String getstudentname();

String getstudentcode();

String getstudentsexy();

String getstudentbirthday();

String getfamilyaddress();}

上面的实例,演示了如何声明一个接口,可以看出整个接口中,只有几个设置器和访问

器的方法名称,并没有真正实现方法。另外还有一点,接口的声明必须是“Public”的,否

则没有任何意义。

8.1.4 接口的实现

接口的用处就是让类通过实现它,来执行一定的功能。下面通过实例演示接口的实现功

能,在看实例之前,先看看这个实例的流程,如图8.1 所示。

图8.1 有关接口的一个实例

首先看看学校接口的设计。

///声明一个学校接口,来告诉程序需要做些什么

149

///其中包括了很多方法。但是都没有去实现。即都没有函数体

interface school

{

void setschoolname(String schoolname);

void setclassname(String schoolclassname);

void setname(String name);

void setcode(String code);

void setsexy(String sexy);

void setbirthday(String birthday);

void setfamilyaddress(String familyaddress);

String getschoolname();

String getclassname();

String getname();

String getcode();

String getsexy();

String getbirthday();

String getfamilyaddress();

}

下面再来设计学生类,其代码如下:

///创建一个类,让它实现学校这个接口

///通过设置器来设置各个参数

///通过访问器来获得对象的参数

///通过tostring 方法来让对象以字符串形式输出。

class student implements school

{

private String schoolname;

private String classname;

private String studentname;

private String studentcode;

private String studentsexy;

private String studentbirthday;

private String familyaddress;

public void setschoolname(String schoolname)

{

this.schoolname=schoolname;

}

public void setclassname(String classname)

{

this.classname=classname;

}

public void setname(String studentname)

{

this.studentname=studentname;

}

public void setcode(String studentcode)

{

this.studentcode=studentcode;

}

public void setsexy(String studentsexy)

{

this.studentsexy=studentsexy;

}

public void setbirthday(String studentbirthday)

150

{

this.studentbirthday=studentbirthday;

}

public void setfamilyaddress(String familyaddress)

{

this.familyaddress=familyaddress;

}

public String getschoolname()

{

return schoolname;

}

public String getclassname()

{

return classname;

}

public String getname()

{

return studentname;

}

public String getcode()

{

return studentcode;

}

public String getsexy()

{

return studentsexy;

}

public String getbirthday()

{

return studentbirthday;

}

public String getfamilyaddress()

{

return familyaddress;

}

public String tostring()

{

String infor="学校名称:"+schoolname+" "+"班级名称:"+classname+" "+"学生姓名:

"+studentname+" "+" 学号: "+studentcode+" "+" 性别: "+studentsexy+" "+" 出生年月:

"+studentbirthday+" "+"家庭地址:"+familyaddress;

return infor;

}

}

下面再来设计教师类,其代码如下所示。

///让教师类实现学校这个接口

///设置器来设置各个参数

///通过访问器来获得各个参数

///通过tostring 方法来让对象以字符串形式输出

class teacher implements school

{

private String schoolname;

private String classname;

private String teachername;

151

private String teachercode;

private String teachersexy;

private String teacherbirthday;

private String familyaddress;

public void setschoolname(String schoolname)

{

this.schoolname=schoolname;

}

public void setclassname(String classname)

{

this.classname=classname;

}

public void setname(String teachername)

{

this.teachername=teachername;

}

public void setcode(String teachercode)

{

this.teachercode=teachercode;

}

public void setsexy(String teachersexy)

{

this.teachersexy=teachersexy;

}

public void setbirthday(String teacherbirthday)

{

this.teacherbirthday=teacherbirthday;

}

public void setfamilyaddress(String familyaddress)

{

this.familyaddress=familyaddress;

}

public String getschoolname()

{

return schoolname;

}

public String getclassname()

{

return classname;

}

public String getname()

{

return teachername;

}

public String getcode()

{

return teachercode;

}

public String getsexy()

{

return teachersexy;

}

public String getbirthday()

152

{

return teacherbirthday;

}

public String getfamilyaddress()

{

return familyaddress;

}

public String tostring()

{

String infor="学校名称:"+schoolname+" "+"班级名称:"+classname+" "+"教师姓名:

"+teachername+" "+"教师工号:"+teachercode+" "+"性别:"+teachersexy+" "+"出生年月:

"+teacherbirthday+" "+"家庭地址:"+familyaddress;

return infor;

}

}

主运行程序的代码如下所示。

///主运行函数

///从学生类中创建出几个对象

///从教师类中创建出几个对象

//通过设置器设置各个参数,在对象内部隐藏着访问器,来访问这些参数

///以字符串形式输出这些对象的字符串

public class schooltest

{

public static void main(String[] args)

{

student st1=new student();

student st2=new student();

teacher te1=new teacher();

teacher te2=new teacher();

st1.setschoolname("重庆大学");

st1.setclassname("计算机二班");

st1.setname("王浩");

st1.setcode("951034");

st1.setsexy("男");

st1.setbirthday("1975-07-21");

st1.setfamilyaddress("上海市浦东新区");

st2.setschoolname("重庆大学");

st2.setclassname("计算机三班");

st2.setname("赵丽");

st2.setcode("951068");

st2.setsexy("女");

st2.setbirthday("1975-10-09");

st2.setfamilyaddress("北京海淀区");

te1.setschoolname("四川大学");

te1.setclassname("计算机二班");

te1.setname("孙敏");

te1.setcode("00123");

te1.setsexy("女");

te1.setbirthday("1968-04-20");

te1.setfamilyaddress("重庆市沙坪坝区");

te2.setschoolname("四川大学");

te2.setclassname("机械系三班");

te2.setname("赵为民");

153

te2.setcode("11233");

te2.setsexy("男");

te2.setbirthday("1961-02-13");

te2.setfamilyaddress("成都市区");

System.out.println(st1.tostring());

System.out.println(st2.tostring());

System.out.println(te1.tostring());

System.out.println(te2.tostring());

}

}

}

运行结果

学校名称:重庆大学 班级名称:计算机二班 学生姓名:王浩 学号:951034 性别:男

出生年月:1975-07-21 家庭地址:上海市浦东新区

学校名称:重庆大学 班级名称:计算机三班 学生姓名:赵丽 学号:951068 性别:女

出生年月:1975-10-09 家庭地址:北京海淀区

学校名称:四川大学 班级名称:计算机二班 教师姓名:孙敏 教师工号:00123 性别

:女 出生年月:1968-04-20 家庭地址:重庆市沙坪坝区

学校名称:四川大学 班级名称:机械系三班 教师姓名:赵为民 教师工号:11233 性

别:男 出生年月:1961-02-13 家庭地址:成都市区

举这个例子的目的就是了解接口的用处。在这个程序段中,将接口作为一种规范,当要

提取一个学生类时,就用学生类来实现学校这个接口。当要提取一个教师类时,教师类也实

现学校这个接口。

接口的用处在于让整个程序段中相同类型的类有一个统一的规范,这样看到接口的定

义,就知道要实现它的类的功能。在类实现接口时,需要注意以下几点:

􀂉 声明类需要实现指定的接口。

􀂉 提供接口中所有方法的定义。

􀂉 实现接口的类时,其访问控制符必须全部是“public”的。

8.1.5 接口的多重实现

前面提到过接口能够补充继承的不足,现在讲解如何补充。继承必须是单继承的,即一

个类继承另一个类后,那这个类就不能继承其他类。而接口则无所谓,一个类可以实现一个

接口,也可以同时实现另一个接口。使用接口为编程提供了很大的方便,可以把上面的程序

段修改一下。为了能更好的理解这个程序,先看看程序的流程,如图8.2 所示。

 

 

图8.2 多重实现的流程图

首先是第一个学校接口的设计,代码如下所示。

interface school //创建一个接口

{

void setschoolname(String schoolname);

void setclassname(String schoolclassname);

void setname(String name);

void setcode(String code);

void setsexy(String sexy);

void setbirthday(String birthday);

void setfamilyaddress(String familyaddress);

}

第二个学校接口的设计,代码如下所示。

interface school1 //创建另一个接口

{

String getschoolname();

String getclassname();

String getname();

String getcode();

String getsexy();

String getbirthday();

String getfamilyaddress();

}

下面学习如何设计学生类,详细代码如下所示。

///创建一个类,让它实现学校这两个接口

///通过设置器来设置各个参数

///通过访问器来获得对象的参数

///通过tostring 方法来让对象以字符串形式输出。

class student implements school,school1 //一个类实现两个不同的接口

{

private String schoolname;

private String classname;

private String studentname;

private String studentcode;

private String studentsexy;

private String studentbirthday;

private String familyaddress;

public void setschoolname(String schoolname)

{

this.schoolname=schoolname;

}

public void setclassname(String classname)

{

this.classname=classname;

}

public void setname(String studentname)

{

this.studentname=studentname;

}

public void setcode(String studentcode)

{

this.studentcode=studentcode;

155

}

public void setsexy(String studentsexy)

{

this.studentsexy=studentsexy;

}

public void setbirthday(String studentbirthday)

{

this.studentbirthday=studentbirthday;

}

public void setfamilyaddress(String familyaddress)

{

this.familyaddress=familyaddress;

}

public String getschoolname()

{

return schoolname;

}

public String getclassname()

{

return classname;

}

public String getname()

{

return studentname;

}

public String getcode()

{

return studentcode;

}

public String getsexy()

{

return studentsexy;

}

public String getbirthday()

{

return studentbirthday;

}

public String getfamilyaddress()

{

return familyaddress;

}

public String tostring()

{

String infor="学校名称:"+schoolname+" "+"班级名称:"+classname+" "+"学生姓名:

"+studentname+" "+" 学号: "+studentcode+" "+" 性别: "+studentsexy+" "+" 出生年月:

"+studentbirthday+" "+"家庭地址:"+familyaddress;

return infor;

}

}

设计教师类的代码如下所示。

//让教师类实现学校这两个接口

///设置器来设置各个参数

///通过访问器来获得各个参数

156

///通过tostring 方法来让对象以字符串形式输出

class teacher implements school,school1 //一个类实现两个不同的接口

{

private String schoolname;

private String classname;

private String teachername;

private String teachercode;

private String teachersexy;

private String teacherbirthday;

private String familyaddress;

public void setschoolname(String schoolname)

{

this.schoolname=schoolname;

}

public void setclassname(String classname)

{

this.classname=classname;

}

public void setname(String teachername)

{

this.teachername=teachername;

}

public void setcode(String teachercode)

{

this.teachercode=teachercode;

}

public void setsexy(String teachersexy)

{

this.teachersexy=teachersexy;

}

public void setbirthday(String teacherbirthday)

{

this.teacherbirthday=teacherbirthday;

}

public void setfamilyaddress(String familyaddress)

{

this.familyaddress=familyaddress;

}

public String getschoolname()

{

return schoolname;

}

public String getclassname()

{

return classname;

}

public String getname()

{

return teachername;

}

public String getcode()

{

return teachercode;

157

}

public String getsexy()

{

return teachersexy;

}

public String getbirthday()

{

return teacherbirthday;

}

public String getfamilyaddress()

{

return familyaddress;

}

public String tostring()

{

String infor="学校名称:"+schoolname+" "+"班级名称:"+classname+" "+"教师姓名:

"+teachername+" "+"教师工号:"+teachercode+" "+"性别:"+teachersexy+" "+"出生年月:

"+teacherbirthday+" "+"家庭地址:"+familyaddress;

return infor;

}

}

主运行程序将上面设计的类,通过对象的形式输出。其详细代码如下所示。

///主运行函数

///从学生类中创建出几个对象

///从教师类中创建出几个对象

//通过设置器设置各个参数,在对象内部隐藏着访问器,来访问这些参数

///以字符串形式输出这些对象的字符串

public class schooltest

{

public static void main(String[] args)

{

student st1=new student();

student st2=new student();

teacher te1=new teacher();

teacher te2=new teacher();

st1.setschoolname("重庆大学");

st1.setclassname("计算机二班");

st1.setname("王浩");

st1.setcode("951034");

st1.setsexy("男");

st1.setbirthday("1975-07-21");

st1.setfamilyaddress("上海市浦东新区");

st2.setschoolname("重庆大学");

st2.setclassname("计算机三班");

st2.setname("赵丽");

st2.setcode("951068");

st2.setsexy("女");

st2.setbirthday("1975-10-09");

st2.setfamilyaddress("北京海淀区");

te1.setschoolname("四川大学");

te1.setclassname("计算机二班");

te1.setname("孙敏");

te1.setcode("00123");

158

te1.setsexy("女");

te1.setbirthday("1968-04-20");

te1.setfamilyaddress("重庆市沙坪坝区");

te2.setschoolname("四川大学");

te2.setclassname("机械系三班");

te2.setname("赵为民");

te2.setcode("11233");

te2.setsexy("男");

te2.setbirthday("1961-02-13");

te2.setfamilyaddress("成都市区");

System.out.println(st1.tostring());

System.out.println(st2.tostring());

System.out.println(te1.tostring());

System.out.println(te2.tostring());

}

}

运行结果

学校名称:重庆大学 班级名称:计算机二班 学生姓名:王浩 学号:951034 性别:男

出生年月:1975-07-21 家庭地址:上海市浦东新区

学校名称:重庆大学 班级名称:计算机三班 学生姓名:赵丽 学号:951068 性别:女

出生年月:1975-10-09 家庭地址:北京海淀区

学校名称:四川大学 班级名称:计算机二班 教师姓名:孙敏 教师工号:00123 性别

:女 出生年月:1968-04-20 家庭地址:重庆市沙坪坝区

学校名称:四川大学 班级名称:机械系三班 教师姓名:赵为民 教师工号:11233 性

别:男 出生年月:1961-02-13 家庭地址:成都市区

在上面的程序段中,将一个接口分成了两个。然后用一个类同时实现两个接口,运行结

果依然不变。如果是继承就不允许这样,因为一个类只能继承一个类,不能继承多个类,这

就是接口的多重实现。

8.1.6 接口的属性

接口不是一个类,正因为其不是一个类,所以不能使用关键字“new”生成一个接口的

实例。虽然这样,还是可以声明一个接口变量,如:“school sc”。

如果要生成一个接口的实例,可以让接口变量,指向一个已经实现了此接口的类的对象,

如下面的例子。

School sc=new student();

另外,在接口中,不能声明实例字段及静态方法,但可以声明常量。其实接口不一定要

有方法,也可以全部是常量。这个在后面的章节中,随着应用的加深,读者会看到和体会到。

8.1.7 接口的继承

接口从某些方面具有类的一些特性,如有方法、有属性,那么是否像类一样可以继承?

回答是肯定的。接口的继承和类的继承一样,也是用关键字“extends”来实现,下面先看

一个有关接口继承的实例。实例的流程如图8.3 所示。

图8.3 接口继承的流程图

首先看看学校接口的设计,代码如下所示。

///创建一个接口

interface school

{

void setschoolname(String schoolname);

void setclassname(String schoolclassname);

String getschoolname();

String getclassname();

}

设计另一个学校接口,代码如下所示。

///这个接口继承了上面那个接口

interface school1 extends school

{

void setname(String name);

void setcode(String code);

void setsexy(String sexy);

void setbirthday(String birthday);

void setfamilyaddress(String familyaddress);

String getname();

String getcode();

String getsexy();

String getbirthday();

String getfamilyaddress();

}

设计学生类,代码如下所示。

///创建一个类,让它实现学校这个接口

///通过设置器来设置各个参数

///通过访问器来获得对象的参数

///通过tostring 方法来让对象以字符串形式输出。

class student implements school1 //学生类实现子接口

{

private String schoolname;

private String classname;

private String studentname;

private String studentcode;

160

private String studentsexy;

private String studentbirthday;

private String familyaddress;

public void setschoolname(String schoolname)

{

this.schoolname=schoolname;

}

public void setclassname(String classname)

{

this.classname=classname;

}

public void setname(String studentname)

{

this.studentname=studentname;

}

public void setcode(String studentcode)

{

this.studentcode=studentcode;

}

public void setsexy(String studentsexy)

{

this.studentsexy=studentsexy;

}

public void setbirthday(String studentbirthday)

{

this.studentbirthday=studentbirthday;

}

public void setfamilyaddress(String familyaddress)

{

this.familyaddress=familyaddress;

}

public String getschoolname()

{

return schoolname;

}

public String getclassname()

{

return classname;

}

public String getname()

{

return studentname;

}

public String getcode()

{

return studentcode;

}

public String getsexy()

{

return studentsexy;

}

public String getbirthday()

{

161

return studentbirthday;

}

public String getfamilyaddress()

{

return familyaddress;

}

public String tostring()

{

String infor="学校名称:"+schoolname+" "+"班级名称:"+classname+" "+"学生姓名:

"+studentname+" "+" 学号: "+studentcode+" "+" 性别: "+studentsexy+" "+" 出生年月:

"+studentbirthday+" "+"家庭地址:"+familyaddress;

return infor;

}

}

设计教师类,详细代码如下。

///创建一个类,让它实现学校这个接口

///通过设置器来设置各个参数

///通过访问器来获得对象的参数

///通过tostring 方法来让对象以字符串形式输出。

class teacher implements school1

{

private String schoolname;

private String classname;

private String teachername;

private String teachercode;

private String teachersexy;

private String teacherbirthday;

private String familyaddress;

public void setschoolname(String schoolname)

{

this.schoolname=schoolname;

}

public void setclassname(String classname)

{

this.classname=classname;

}

public void setname(String teachername)

{

this.teachername=teachername;

}

public void setcode(String teachercode)

{

this.teachercode=teachercode;

}

public void setsexy(String teachersexy)

{

this.teachersexy=teachersexy;

}

public void setbirthday(String teacherbirthday)

{

this.teacherbirthday=teacherbirthday;

}

public void setfamilyaddress(String familyaddress)

162

{

this.familyaddress=familyaddress;

}

public String getschoolname()

{

return schoolname;

}

public String getclassname()

{

return classname;

}

public String getname()

{

return teachername;

}

public String getcode()

{

return teachercode;

}

public String getsexy()

{

return teachersexy;

}

public String getbirthday()

{

return teacherbirthday;

}

public String getfamilyaddress()

{

return familyaddress;

}

public String tostring()

{

String infor="学校名称:"+schoolname+" "+"班级名称:"+classname+" "+"教师姓名:

"+teachername+" "+"教师工号:"+teachercode+" "+"性别:"+teachersexy+" "+"出生年月:

"+teacherbirthday+" "+"家庭地址:"+familyaddress;

return infor;

}

}

主运行类的代码如下所示。

///主运行函数

///从学生类中创建出几个对象

///从教师类中创建出几个对象

//通过设置器设置各个参数,在对象内部隐藏着访问器,来访问这些参数

///以字符串形式输出这些对象的字符串

public class schooltest

{

public static void main(String[] args)

{

student st1=new student();

student st2=new student();

teacher te1=new teacher();

teacher te2=new teacher();

163

st1.setschoolname("重庆大学");

st1.setclassname("计算机二班");

st1.setname("王浩");

st1.setcode("951034");

st1.setsexy("男");

st1.setbirthday("1975-07-21");

st1.setfamilyaddress("上海市浦东新区");

st2.setschoolname("重庆大学");

st2.setclassname("计算机三班");

st2.setname("赵丽");

st2.setcode("951068");

st2.setsexy("女");

st2.setbirthday("1975-10-09");

st2.setfamilyaddress("北京海淀区");

te1.setschoolname("四川大学");

te1.setclassname("计算机二班");

te1.setname("孙敏");

te1.setcode("00123");

te1.setsexy("女");

te1.setbirthday("1968-04-20");

te1.setfamilyaddress("重庆市沙坪坝区");

te2.setschoolname("四川大学");

te2.setclassname("机械系三班");

te2.setname("赵为民");

te2.setcode("11233");

te2.setsexy("男");

te2.setbirthday("1961-02-13");

te2.setfamilyaddress("成都市区");

System.out.println(st1.tostring());

System.out.println(st2.tostring());

System.out.println(te1.tostring());

System.out.println(te2.tostring());

}

}

运行结果

学校名称:重庆大学 班级名称:计算机二班 学生姓名:王浩 学号:951034 性别:男

出生年月:1975-07-21 家庭地址:上海市浦东新区

学校名称:重庆大学 班级名称:计算机三班 学生姓名:赵丽 学号:951068 性别:女

出生年月:1975-10-09 家庭地址:北京海淀区

学校名称:四川大学 班级名称:计算机二班 教师姓名:孙敏 教师工号:00123 性别

:女 出生年月:1968-04-20 家庭地址:重庆市沙坪坝区

学校名称:四川大学 班级名称:机械系三班 教师姓名:赵为民 教师工号:11233 性

别:男 出生年月:1961-02-13 家庭地址:成都市区

8.1.8 接口意义

接口不仅仅是一种规范,还是一种编程的思路。接口的所有方法和属性,都代表了后面

将要设计的类的基本思路,这些方法就代表着这个程序的需求,所以掌握好接口,对学好

Java 程序开发非常关键。

164

8.2 内部类

内部类就是在一个类的内部再创建一个类。下面介绍如何使用内部类编写程序代码,并

了解内部类在编写代码的过程中,为程序员提供了哪些方便和优点。

内部类究竟有什么好处:

􀂉 内部类的对象能够访问创建它的对象的所有方法和属性,包括私有数据。

􀂉 对于同一个外包中的其他类来说,内部类是隐形的。

􀂉 匿名内部类可以很方便的定义回调。

􀂉 使用内部类可以很方便的编写事件驱动的程序。

下面将这些特点贯穿整节,通过实例来讲述。

8.2.1 使用内部类来访问对象

下面将举个有关内部类的实例,在分析这个实例之前,先了解这个实例的流程,如图

8.4 所示。

图8.4 内部类访问对象的实例

首先看看如何设计学生类,代码如下所示。

///创建一个学生类

///在学生类中,创建姓名,学号,性别等参数

///使用设置器来设置参数

///使用访问器来获取参数值

public class students

{

private String name;

private String code;

private String sexy;

private String birthday;

private String address;

public void setname(String name)

{

this.name=name;

}

public void setcode(String code)

{

this.code=code;

}

public void setsexy(String sexy)

165

{

this.sexy=sexy;

}

public void setbirthday(String birthday)

{

this.birthday=birthday;

}

public void setaddress(String address)

{

this.address=address;

}

public String getname()

{

return name;

}

public String getcode()

{

return code;

}

public String getsexy()

{

return sexy;

}

public String getbirthday()

{

return birthday;

}

public String getaddress()

{

return address;

}

public String tostring()

{

String infor="学生姓名:"+name+" "+"学号:"+code+" "+"性别:"+sexy+" "+"出生年月:

"+birthday+" "+"家庭地址:"+address;

return infor;

}

public void setstudentcourse(String[] courses)

{

new course(courses);

}

}

再设计一个内部类,代码如下所示。

///内部类的创建,把内部类作为外部类的一个成员

private class course

{

private String[] courses;

private int coursenum;

///内部类的构造器

public course(String[] course)

{

courses=course;

166

coursenum=course.length;

getinfo();

}

///获得课程数组中的课程

private void get()

{

for(int i=0;i<coursenum;i++)

{

System.out.print(" "+courses[i]);

}

}

///按字符串形式输出

void getinfo()

{

System.out.println("学生姓名:"+students.this.name+"学生学号:"+students.this.code+"一

共选择了:"+coursenum+"门科,分别是:");

get();

}

}

}

在主运行方法内部实现输出,详细代码如下所示。

///在主运行方法中,通过学生类的方法来访问学生类的内部类courses

public static void main(String[] args)

{

String[] courses={"语文","数学","英语","化学"};

students st=new students();

st.setname("王浩");

st.setcode("200123");

st.setsexy("男");

st.setaddress("北京海淀区");

System.out.println(st.tostring());

st.setstudentcourse(courses);

}

其运行结果如下:

运行结果

学生姓名:王浩 学号:200123 性别:男 出生年月:null 家庭地址:北京海淀区

学生姓名:王浩学生学号:200123 一共选择了:4 门科,分别是:

语文 数学 英语 化学

类的访问控制符在前面章节中讲过,只能有“public”和“default”两种。那为什

么在这里的内部类会出现private 呢?

作为一个单独的类,的确只能有“public”和“default”两种访问控制符,但是作

为内部类,就可以使用“private”控制符。当内部类设置为“private”,包含此内部类

的外部类的方法才可以访问它。在这个程序段里,“students”类中的方法可以访问这

个内部类。

内部类如何创建对象呢?其实可以像一般的类一样,直接使用“new”关键字来创

建。在上面的实例中,使用一个方法来创建内部类的实例对象。

在上面的程序段中,内部类的构造器中包含了这个内部类要实现的所有方法。这里

注意,当类创建出对象之前,首先会访问构造器,会运行构造器中的所有方法。这样,

就相当于直接访问了内部类的私有方法,这种方法可以将对象中所有方法一并实现。

167

8.2.2 局部内部类

本小节通过对比局部变量,来学习局部内部类。局部变量就是在某个类的方法中定

义的变量,它的作用范围就在这个方法体内。同样局部内部类就是在类的方法中定义的

一个内部类,它的作用范围也在这个方法体内。把上面的实例修改一下,学习局部内部

类的使用。这个实例的流程,如图8.5 所示。

图8.5 局部内部类的实例流程图

首先设计一个学生类,代码如下所示。

///这是一个学生类

///通过设置器来设置对象参数

///通过访问器来获得对象参数

///通过tostring 方法让对象以字符串形式输出。

public class students

{

private String name;

private String code;

private String sexy;

private String birthday;

private String address;

public void setname(String name)

{

this.name=name;

}

public void setcode(String code)

{

this.code=code;

}

public void setsexy(String sexy)

{

this.sexy=sexy;

}

public void setbirthday(String birthday)

{

this.birthday=birthday;

}

public void setaddress(String address)

{

168

this.address=address;

}

public String getname()

{

return name;

}

public String getcode()

{

return code;

}

public String getsexy()

{

return sexy;

}

public String getbirthday()

{

return birthday;

}

public String getaddress()

{

return address;

}

public String tostring()

{

String infor="学生姓名:"+name+" "+"学号:"+code+" "+"性别:"+sexy+" "+"出生年月:

"+birthday+" "+"家庭地址:"+address;

return infor;

}

在前面设计的外部类的方法中,设计一个内部类,代码如下所示。

///将课程类作为外部类中的一个方法中的成员

public void setstudentcourse(String[] courses)

{

class course

{

private String[] courses;

private int coursenum;

public course(String[] course)

{

courses=course;

coursenum=course.length;

getinfo();

}

private void get()

{

for(int i=0;i<coursenum;i++)

{

System.out.print(" "+courses[i]);

}

}

private void getinfo()

{

169

System.out.println("学生姓名:"+students.this.name+"学生学号:"+students.this.code+"一

共选择了:"+coursenum+"门科,分别是:");

get();

}

}

///创建了一个内部类的对象,随着包含这个内部类的外部方法一起运行

new course(courses);

}

在主运行程序中,实现对象的输出,代码如下所示。

///在主运行方法中,使用学生类对象的方法,来访问局部类courses

public static void main(String[] args)

{

String[] courses={"语文","数学","英语","化学"};

students st=new students();

st.setname("王浩");

st.setcode("200123");

st.setsexy("男");

st.setaddress("北京海淀区");

System.out.println(st.tostring());

st.setstudentcourse(courses);

}

}

运行结果

学生姓名:王浩 学号:200123 性别:男 出生年月:null 家庭地址:北京海淀区

学生姓名:王浩学生学号:200123 一共选择了:4 门科,分别是:

语文 数学 英语 化学

这个程序从上一节的实例程序修改过来,把内部类放到了“students”类的一个方法体

内,这样的内部类就是局部内部类。

局部内部类是定义在外部类的方法中,与局部变量类似,在局部内部类前不加修饰符

“public”和“private”,其范围为定义它的代码块。局部内部类不仅可以访问外部类实例

变量,还可以访问外部类的局部常量,但要求外部类的局部变量是“final”的。其实,以上

做法相当于是为内部类添加了一个属性,这个属性就是外部类的“final”局部变量。在类外

不可直接访问局部内部类,以保证局部内部类对外是不可见的,只有在方法中才能调用其局

部内部类。

8.2.3 静态内部类

当一个内部类不需要引用它的外部类的方法、属性值时,可以将这个类设置为“static”,

这就是静态内部类。既然是静态的,包含它的类要引用它时,就可以不必创建对象,直接引

用。在静态内部类中只能访问外部类的静态成员。构造静态内部类对象,不再需要构造外部

类对象。

8.2.4 匿名内部类

在编写程序代码时,不一定要给内部类取一个名字,可以直接以对象名来代替。在图形

化编程的事件监控器代码中,会大量使用匿名内部类,这样可以大大的简化代码的编写,并

170

增强了代码的可读性。

8.3 常见疑难解答

8.3.1 匿名类如何在程序中使用

答:匿名类是一种特殊的局部内部类,用来继承一个类或者实现一个接口。匿名内部类

不能定义构造方法匿名内部类。在编译的时候由系统自动起名Out$1.class。如果一个对象编

译时的类型是接口,那么其运行的类型是实现这个接口的类,因为匿名内部类无构造方法,

所以其使用范围非常的有限。

8.3.2 接口与继承有什么区别

答:接口在本质上就是一个特殊的类。在语法上跟继承有着很大的差别。

􀂉 属性:接口中的所有属性都是公开静态常量,继承则无所谓。

􀂉 方法:接口中所有方法都是公开抽象方法,继承中所有的方法不一定都是抽象。

􀂉 接口方法:接口没有构造器,继承有构造器。

__