第章Java语言面向对象高级程序设计.ppt
2023年6月22日星期四,第04章 Java语言面向对象高级程序设计,2023年6月22日星期四,【目的要求】,1掌握面向对象高级程序设计:主要包括消息通信、访问控制、封装、继承、多态性、抽象类、抽象方法、接口、内部类、匿名类等。2掌握Java修饰符:this、super、final、abstract、static等。3了解Java设计模式:模式的概念,模式的种类,Decorator、Faade、FactoryMethod和Proxy等设计模式,设计模式在接口中的应用。,2023年6月22日星期四,【重点难点】,教学重点访问控制、继承、多态性、抽象类、抽象方法、接口。教学难点 内部类、匿名类。教学课时理论4学时+课内上机2学时+课外上机2学时教学方法采用多媒体课件+启发式+任务驱动法相结合教学作 业P195:一T(不抄题);二T13,4,5,7,9;三,四,五,六T(不抄题);七T 1,2,3,5,6.,2023年6月22日星期四,第04章 Java语言面向对象高级程序设计,4.5.2 抽象方法 4.6 接口4.6.1 接口的概念4.6.2 接口的定义4.6.3 接口的实现4.6.4 接口与抽象类的比较4.7 内部类与匿名类4.7.1 内部类4.7.2 匿名类4.8 this、Super和修饰符4.8.1 this引用4.8.2 super关键字4.8.3 Java的修饰符4.9 Java的设计模式4.9.1 模式的概念4.9.2 创建模式4.9.3 结构模式4.9.4 行为模式4.9.5 设计模式在接口中的应用习题四实验四 Java面向对象高级程序设计,4.1 消息通信(Communication With Messages)4.1.1 消息的类型4.1.2 消息的使用4.2 访问控制4.2.1 类的访问控制4.2.2 类成员的访问控制4.3 继承4.3.1 创建子类4.3.2 继承的传递性4.3.3 子类对象的初始化4.3.4 子类继承父类的规则4.3.5 上转型与下转型对象4.3.6 继承的使用方法4.3.7 继承与组合区别4.4 多态性4.4.1 多态性的概念4.4.2 方法重载4.4.3 方法覆盖4.4.4 变量覆盖4.5 抽象类与抽象方法4.5.1 抽象类,2023年6月22日星期四,4.1 消息通信(Communication With Messages),4.1.1 消息的类型1公有消息与私有消息公有消息指由外界对象直接发送给某对象的消息;私有消息指对象自己发送给本身的消息,私有消息对外不开放,外界也不必了解它。外界对象只能向某对象发送公有消息,而不能发送私有消息,私有消息则由对象自身发送。,2023年6月22日星期四,4.1.1 消息的类型,2特定对象的消息特定对象的消息指将某对象可接收消息的方法集中在一起,将其消息组合而形成的一个粒度更大的消息,响应此消息的方法集对用户是透明的。特定对象的消息可分为三种类型:可以返回对象内部状态的消息;可以改变对象内部状态的消息;可以做一些特定操作,改变系统状态的消息。,2023年6月22日星期四,4.1.2 消息的使用,P134【例4-1】Java中的消息通信示例。程序清单4-1:MessageDemo.java,2023年6月22日星期四,4.2 访问控制,Java中的访问控制(Access Control)主要包括对包、类、接口、类成员和构造方法的访问控制等方面。除了包的访问控制由主机系统决定外,其他的访问控制通过访问控制符来实现。访问控制符是一组限定类、接口、类成员(成员变量和成员方法)是否可以被其他类访问的修饰符。类和接口的访问控制符只有public和默认(default)两种。类成员和构造方法的访问控制符有public、private、protected和默认(default)4种。,2023年6月22日星期四,4.2.1 类的访问控制,表4-1 类的访问控制符及可见性,2023年6月22日星期四,4.2.1 类的访问控制(续一),1类的公共访问控制(public)public类具有跨包访问性,以支持类的跨包访问。一个Java程序中最多有一个public类(也可以没有public类),若有则并用public类名作为整个程序的源程序文件名。定义在同一个程序文件中的所有类都属于同一个包(默认包或package指定名称的包)。处于同一个包中的类都是可见的,不需任何说明便可地互相访问和引用。一般地,处于不同包中的类相互之间是不可见的,而不能互相引用。只有当某个类的访问控制符为public时,它才能被其他包中的类可见和使用。,2023年6月22日星期四,4.2.1 类的访问控制(续二),若跨包访问public类,则先在引用它的另一个包中使用import语句引入此public类,然后方能访问和引用这个类,以创建这个类的对象,并访问这个类内部可见的数据成员和引用它的可见的成员方法。要特别指出的是,尽管处于不同包中的public类作为整体对其他类是可见的,但并不代表该类的所有数据成员和成员方法也同时对其他类是可见的,因为这些数据成员和成员方法还进一步受到类成员修饰符访问控制。只有当public类的数据成员和成员方法的访问控制符也被声明为public时,这个类的所有用public修饰的数据成员和成员方法也同时对其他类是可见的。P136【例4-2】不同包中的public类能被跨包访问,而不同包中的default类不能被跨包访问。程序清单4-2:E4_2A.java、E4_2Demo.java,2023年6月22日星期四,2类的默认访问控制(default),类的默认访问控制是指类没有访问控制符,它只具有包访问性,即只有在同一个包中的类和对象才能访问和引用默认访问控制的类,而不支持类的跨包访问。示例:类的默认访问控制示例如例4-2中的E4_2B类所示,由于p1包中的E4_2B类为default类,而只具有包访问性,因此它只能被其所在的p1包中的类(如E4_2A类)访问引用,而不能被尽管已引入到p1包中的p2包中类(如E4_2Demo类和E4_2C)访问引用。,2023年6月22日星期四,4.2.2 类成员的访问控制,类成员不仅包括在类体中声明的成员变量和成员方法,而且包括从它的直接父类继承的成员和从任何直接接口继承的成员。,表4-2 类成员的访问控制符及可见性,2023年6月22日星期四,1类成员的公共访问控制(public),public类型的类成员可被同一类、同一包中子类与非子类和不同包中的子类与非子类的代码访问引用。或者说public类成员可被能够访问它所在的包的任何代码所访问,它不受类域访问性、包域访问性和跨包域访问性的任何限制。,2023年6月22日星期四,1类成员的公共访问控制(public)(续一),P138【例4-3】对于不同包中和相同包中非子类的public类成员可任意访问。先在pubpac1包中的public类E4_3A中定义public类型的成员变量和成员方法,然后在pubpac2包中引入pubpac1包中的类后,由default类E4_3B中构造方法创建E4_3A类的实例,并访问其中的public成员,实现对public类成员的跨包访问,最后在主类publicDemo中创建E4_3B类的实例后,实现对同包类的public类成员的访问。程序清单4-3:E4_3A.java、publicDemo.java,2023年6月22日星期四,2类成员的保护访问控制(protected),protected类型的类成员可被同一类、同一包中子类与非子类和不同包中的子类的代码访问。或者说protected类成员可被除不同包的非子类以外的其他能够访问它所在包的任何代码所访问,它不受类域访问性、包域访问性的任何限制。P139【例4-4】允许包域访问protected类成员,而不能跨包访问不同包中非子类的protected类成员变量与成员方法。程序清单4-4:E4_4A.java、ProtectedDemo.java,2023年6月22日星期四,2类成员的保护访问控制(protected)(续一),P140【例4-4】分析:先在propac1包中的public类E4_4A中定义protected类型的成员变量和成员方法;然后在propac2包中引入propac1包中的类后,由default类E4_4B中构造方法创建E4_4A类的实例,并试图跨包访问其中的protected成员而不成最后在主类ProtectedDemo中创建E4_4B类的实例后,实现了对同包类的projected成员的访问。,2023年6月22日星期四,3类成员的默认访问控制(default),default类型(没有访问控制符)的类成员只能被同一类、同一包中子类与非子类的代码访问。它具有类域访问性和包域访问性。P140【例4-5】default类型的类成员,只具有类域和包域访问性,而不能跨包域访问。程序清单4-5:E4_5A.java、DefaultDemo.java,2023年6月22日星期四,P141【例4-5】分析:先在defpac1包中的public类E4_5A中定义default类型的成员变量和成员方法;然后在defpac2包中引入defpac1包中的类后,由default类E4_5B中构造方法创建E4_5A类的实例,并试图跨包访问其中的default成员而不成;最后在主类DefaultDemo中创建E4_5B类的实例后,实现了对同包类的default成员的访问。,2023年6月22日星期四,4类成员的私有访问控制(private),private类型的类成员只能被其所在类中的代码访问,它只具有类域访问性。P141【例4-6】private类型的类成员,只具有类域访问性,而不具备包域和跨包域访问性。程序清单4-6:E4_6A.java、PrivateDemo.java 说明:对于同一包中和不同包中子类的public、protected、default和privae成员的访问控制,请见4.3.34.3.4节相关内容。,2023年6月22日星期四,4.3 继承,继承(Inheritance)是两个类之间的一种泛化关系(一般-特殊关系),是一种由已有的类创建新类的机制。利用继承,可以先创建一个拥有共同属性的一般类,根据该一般类再创建具有特殊属性的新类。由继承而得到的类称为子类(Subclass),被直接或间接继承的类称为父类(Father Class),或叫超类(Superclass)或基类(Base Class)。子类继承父类的状态和行为,同时也可以修改父类的状态或重写父类的行为,并添加新的状态和行为。Java仅支持单继承,而不支持多重继承,即每个子类只允许有一个父类,而不允许有多个父类。但是可以从一个父类中生成若干个子类。继承不改变成员的访问权限,父类中的公有成员、保护成员和默认成员,在子类中仍然是公有成员、保护成员和默认成员。Java中的多继承将通过接口方式来实现。,2023年6月22日星期四,4.3.1 创建子类,在类的声明中加入extends子句来创建一个类的子类:class extends父类名/只允许一个直接父类 子类中的新增成员/子类体说明:关键字class用来定义类,关键字extends用来指出该类的直接父类,若没有extends子句,则表示该类的默认父类为java.lang.Object类。若“父类”又是某个类的子类,则“子类”同时也是该类的(间接)子类。“子类”可以继承“父类”中访问权限设定为public、protected和default的成员变量和成员方法,但是不能继承访问权限为private的成员变量和成员方法。例如:,2023年6月22日星期四,4.3.1 创建子类(续一),class A/类A继承类java.lang.Objectint a1=10;private int a2=20;public int getA2()return a2;class B extends A/类B继承类A,间接继承类/java.lang.Object/类B继承父类A的非私有成员:a1和getA2(),而私有成员a2不能被继承int b1=100;private int b2=200;public int getB2()return b2;,2023年6月22日星期四,4.3.2 继承的传递性,类的继承是可以传递的。类继承的传递性是指若类B继承类A,类C又继承类B,则类C应包含类A和类B的非私有成员,以及类C自身的成员。P143【例4-7】类继承的传递性。程序清单4-7:InheritanceTransferDemo.java,2023年6月22日星期四,4.3.3 子类对象的初始化,由于子类中包含有父类的非私有成员。在创建子类对象时,不仅要对自身成员变量初始化,而且还要对继承的父类中成员变量初始化。对象的初始化是通过调用构造方法来实现的。构造方法不能被继承,但可以在子类的构造方法中调用父类的构造方法。为了方便使用,系统规定用this()表示当前类的构造方法,用super()表示直接父类的构造方法。除Object类没有父类外,其他类的构造方法中应包含自身类的构造方法和直接父类的构造方法。,返回,2023年6月22日星期四,构造方法的特性,自动提供默认构造方法:若一个类中没有定义任何构造方法时,则系统自动提供一个没有参数的默认构造方法;若类中已定义任何构造方法,则系统将不提供默认构造方法。允许构造方法重载:一个类中可根据需要定义多个重载的构造方法,不同构造方法的选择是根据参数的个数、类型和顺序进行匹配。支持this()和super():在构造方法定义中,可使用this()来调用本类的其他构造方法,使用super()来调用父类的构造方法。若this和super都不用时,系统会自动调用super(),即父类的默认构造方法。调用this()或super()的构造方法的语句必须放在第一条语句,并且this()和super()最多只可调用其中一条。P144【例4-8】子类对象的初始化,掌握this()和super()的使用.,2023年6月22日星期四,4.3.4 子类继承父类的规则,由于子类受到父类成员的访问控制符和包的限制,子类并不能继承父类中所有的成员变量和成员方法。,表4-3 子类继承父类的规则,注:父类的构造方法不能被子类继承,只能通过super()来调用。父类中成员的访问权限在子类中是不变的。,2023年6月22日星期四,1父子类在同一包中的继承规则实例,若子类和父类在同一个包中,则子类继承父类中的public、protected和默认成员(成员变量和成员方法),将其作为子类的成员,但不能继承父类的private成员。P145【例4-9】同包中的子类只能继承父类中的非私有成员(public、protected和默认成员)。程序清单4-9:InheritanceRuleOfSamePackage.java,2023年6月22日星期四,2父子类在不同包中的继承规则(续一),若子类和父类不在同一个包中,则子类继承了父类中的public和protected成员变量和成员方法,将其作为子类的成员,但不能继承父类的默认和private成员。P146【例4-10】不同包中的子类只能继承父类中的public和protected成员,且不同包中的非子类不能调用protected成员,只有子类才能调用protected成员。程序清单4-10:InheritanceRuleOfDifferentPackage.java、A.java,2023年6月22日星期四,4.3.5 上转型与下转型对象,1子类对象和父类对象之间的转换Java允许父类对象和子类对象在一定条件下相互之间转换。其相互转换规则是:隐式(自动)转换:子类对象直接赋值给父类对象时,子类对象可自动转换为父类对象,称该父类对象是子类对象的上转型对象;强制转换:父类对象赋值给子类对象时,必须将父类对象强制转换为子类对象,称该子类对象是父类对象的下转型对象;没有继承关系的类类型,即不在继承树的同一个继承分支上,则不允许进行类型转换。,2023年6月22日星期四,2上转型对象,设类A是类B的父类,若有:A a;B b=new B();a=b;/a是b的上转型对象(子类对象可自动转型成父类对象)则称父类对象a是子类对象b的上转型对象。若有:B b;A a=new A();b=(B)a;/b是a的下转型对象(父类对象须强制转型成子类对象)则称子类对象b是父类对象a的下转型对象。,2023年6月22日星期四,2上转型对象(续一),对象的上转型对象的实体由子类负责创建,上转型对象会失去原对象的一些属性和功能。上转型对象的特性是:上转型对象不能操作子类新增的成员变量和成员方法。上转型对象可以操作子类继承或重写的成员变量和成员方法。若子类重写了父类的某个方法,则上转型对象调用该方法时一定是调用被子类重写的方法。若子类隐藏了父类的某个变量,则上转型对象访问该变量时,访问的是父类中被隐藏的变量。可以将对象的上转型对象再强制转换成子类对象,则该子类对象又具备了子类所给的所有属性和功能。P148【例4-11】上转型对象的使用。程序清单4-11:UpTransferObjectType.java,2023年6月22日星期四,3对象引用变量的动态绑定,引用变量是指类的对象的引用型变量,其绑定规则如下:(1)对于一个引用类型的变量,Java编译器按照它声明的类型来处理.(2)对于一个引用类型的变量,运行时Java虚拟机按照它实际引用的对象来处理。例如下转型对象的引用虽然编译可以通过,但运行时会抛出ClassCastException运行时异常。(3)在运行时环境中,通过引用类型变量来访问所引用对象的方法和属性时,Java虚拟机采用以下绑定规则:实例方法与引用变量实际引用的对象的方法绑定,这种绑定属于动态绑定,因为是在运行时由Java虚拟机动态决定的。静态方法与引用变量所声明的类型的方法绑定,这种绑定属于静态绑定,因为实际上是在编译阶段就已经做了绑定。成员变量(包括静态变量和实例变量)与引用变量所声明的类型的成员变量绑定,这种绑定属于静态绑定。因为实际上是在编译阶段就已经做了绑定。,2023年6月22日星期四,4.3.6 继承的使用方法,(1)继承树的层次不宜太多,尽量保持在两到三层(不包括顶层的Object类),以降低复杂度,提高可扩展性。(2)继承树的上层应尽可能为抽象层(如接口和抽象类)。(3)使用一棵继承树上的类时,尽可能把引用变量声明为继承树的上层类型,以提高系统之间的松耦合。若继承树上有接口类型,则尽可能把引用变量声明为继承树上层的接口类型。,2023年6月22日星期四,4.3.6 继承的使用方法(续一),(4)精心设计用于被继承的类提供良好的文档说明,以便开发人员正确安全地创建该类的子类。尽可能封装父类的实现细节,而把代表实现细节的属性和方法定义为private类型。将不允许子类覆盖的方法定义为final方法。父类的构造方法中不允许调用可被子类覆盖的方法,以防运行时出错。若不是专门为了继承而设计的类,随意继承它是不安全的,可以采取以下两种措施来禁止继承:把类声明为final类;把此类的所有构造方法声明为private类型,然后通过一些静态方法来负责构造自身的实例。,2023年6月22日星期四,4.3.7 继承与组合区别,组合关系和继承关系相比,前者最主要的优势是不会破坏封装。若类A与类C之间为组合关系,由类C封装实现,则其仅向类A提供接口;若类A与类C之间为继承关系,则类C会向类A暴露部分实现细节。组合关系虽然不会比继承关系减少编码量,但由于组合关系会降低系统的耦合性,提高了系统的可维护性。组合关系的缺点是比继承关系要创建更多的对象。对于组合关系,创建整体类的实例时,必须创建其局部类的实例;而对于继承关系,创建子类的实例时,无需创建父类的实例。,2023年6月22日星期四,4.4 多态性,多态性(Polymorphism)是面向对象方法的三个重要特性之一。多态是指在一个程序中相同的名字可以表示不同的实现。Java的多态性主要表现在三个方面:方法重载:指可在一个类中定义多个名字相同而实现不同的成员方法,它是一种静态多态性,或称编译时多态;方法覆盖(重写):即子类可以隐藏与父类中的同名成员方法,它是一种动态多态性,或称运行时多态;变量覆盖:即子类可以隐藏与父类中的同名成员变量。多态性大大提高了程序的抽象性和简洁性。从静态与动态的角度可将多态分为编译时多态(静态多态)和运行时多态(动态多态)。,2023年6月22日星期四,4.4.1 多态性的概念,(1)编译时多态(静态多态)编译时多态是指在编译阶段,编译器根据实参的不同来静态确定具体调用相应的方法,Java中的方法重载属于静态多态。(2)运行时多态(动态多态)运行时多态是指运行时系统能根据对象状态不同来调用其相应的成员方法,即动态绑定。Java中的方法覆盖属于动态多态。由于子类继承了父类的非私有属性,所以子类对象可以作为父类对象使用(即上转型对象)。程序中凡是使用父类对象的地方,都可以用子类对象来代替。可以通过引用子类的实例来调用子类的方法。,2023年6月22日星期四,4.4.2 方法重载,方法重载(Method Overloading)是指Java 的同一个类中的两个或两个以上的方法可以使用同一个名字,而它们的参数声明(个数、类型和顺序)不同。例如:add()方法可能有以下三个版本:public int add(int x,int y)return x+y;public double add(double x,double y)return x+y;/参数类型不同重载public double add(double x,double y,double z)return x+y+z;/参数个数不同重载,2023年6月22日星期四,4.4.2 方法重载(续一),重载方法并存于程序中,当一个重载方法被调用时,javac编译器会根据实参的个数、类型和顺序来表明实际调用的重载方法的版本。因此,每个重载方法的参数个数、类型和顺序必须是不同的。虽然每个重载方法可以有不同的返回类型,但返回类型并不足以区分所使用的是哪个方法。方法重载属于Java的静态多态,当Java在编译阶段调用一个重载方法时,形参与调用实参匹配的方法才被调用。方法重载的目的不是代码复用,它可以提高成员方法的抽象程度,对外提供一致简洁的使用接口。P151【例4-12】方法重载的使用。程序清单4-12:MethodOverloadingDemo.java,2023年6月22日星期四,构造方法重载,构造方法重载是指Java的同一个类可以有多个名字与类名相同,但参数不同的构造方法。P152【例4-13】构造方法重载。程序清单4-13:ConstructMethodOverloadingDemo.java,2023年6月22日星期四,4.4.3 方法覆盖,方法覆盖(Method Override)是指子类对父类中相同方法头的方法重新定义,又称为方法重写。这时子类和父类具有方法头(包括修饰符、方法名、参数表和返回值类型)相同,但方法体不同的同名方法。方法重写的原则是:改写后的方法不能比被重写的方法有更严格的访问权限。改写后的方法不能比被重写的方法产生更多的异常。调用重写方法的原则是:对子类的一个实例,若子类重写了父类的方法,则运行时系统调用子类的方法;对子类的一个实例,若子类继承了父类的方法(未重写),则运行时系统调用父类的方法。,2023年6月22日星期四,4.4.3 方法覆盖(续一),调用重写方法的格式是:一般地,在子类中通过“方法名”所调用的成员方法包括子类中的重写方法、继承自父类的方法(未重写)和子类新增的方法三种。若要访问父类中被覆盖的成员方法,则必须使用super关键字来表示父类对象,其一般调用格式是:super.(实参表);通过方法覆盖,可以在子类中修改父类中同名方法的功能。方法覆盖实现了在运行时的多态性,通过运行时的对象状态来调用其相应的成员方法,从而提高程序的简洁性和灵活性。P154【例4-14】方法覆盖的使用和父类中被覆盖方法的调用。程序清单4-14:MethodOverrideDemo.java,2023年6月22日星期四,方法覆盖与方法重载的异同,(1)相同点:二者都要求方法名相同;二者都可以用于抽象方法和非抽象方法。(2)不同点:方法覆盖要求参数签名必须一致,而方法重载要求参数签名必须不一致;方法覆盖只能用于子类覆盖父类的方法,方法重载用于同一个类的所有方法(包括从父类中继承而来的方法);方法覆盖对方法的访问权限和抛出的异常有特殊的要求,而方法重载在这方面没有任何限制;方法覆盖要求返回类型必须一致,而方法重载对此不做限制;父类的一个方法只能被子类覆盖一次,而一个方法在所在的类中可以被重载多次。,2023年6月22日星期四,4.4.4 变量覆盖,变量覆盖(Variable Override)是指在子类中对从父类继承过来的成员变量重新定义,即变量名相同而其类型相同或不同,又称为成员变量的隐藏。成员变量覆盖的处理规则是:在子类中将继承父类的同名变量“隐藏”了。若子类执行继承父类的操作,则使用继承自父类的变量;若子类执行自己定义的操作时,则使用自己定义的变量。若在子类中引用父类中继承的变量,则可使用super关键字来表示父类对象,其一般格式是:super.;P155【例4-15】成员变量的覆盖(隐藏)与super的使用.程序清单4-15:VariableOverrideDemo.java,2023年6月22日星期四,4.5 抽象类与抽象方法,抽象类是Java支持多态性的一种重要机制,通过抽象类可以统一处理一个类层次中的同名方法。在很多实际应用中,类层次的顶层类并不具备下层子类的一些功能实现,而将这些方法声明为抽象方法,在Java中含有抽象方法的类就叫抽象类。抽象类和抽象方法是被abstract修饰的类和方法。,2023年6月22日星期四,4.5.1 抽象类,其定义方法如下:abstract class/类体抽象类的特点是不能被实例化,只是一种概念类。使用抽象类的优点是可以充分利用它所具有的公共属性来提高程序的开发效率。抽象类一定有它的子类,而子类通常不是抽象类,若其子类是抽象类,则该抽象类一定会有不是抽象类的子类。抽象类与其子类的关系是继承关系。虽然抽象类不能定义对象,但是抽象类可以有构造方法,并能被其子类所调用。,2023年6月22日星期四,4.5.1 抽象类(续一),使用抽象类注意以下四点:abstract抽象类不能创建对象,必须通过子类继承后,由子类来创建对象。abstract抽象类中,可以没有抽象方法,也可以有一个或多个抽象方法(见4.5.2)。若一个类中含有abstract抽象方法,则该类必须被声明为抽象类。abstract抽象类不能被同时声明为final类。P157【例4-16】抽象类的定义、继承与应用。程序清单4-16:AbstractClassDemo.java,2023年6月22日星期四,4.5.2 抽象方法,抽象方法(Abstract Method)是指被abstract修饰的成员方法。抽象方法是一种仅有方法头,而无方法体的一种特殊方法。抽象方法不能实现任何操作,而只能作为所有子类中重载该方法的一个统一接口。抽象方法定义的一般格式是:abstract class/抽象类 abstract();/抽象方法在该定义中,使用了一个分号来替代方法体。存在抽象方法的类一定是抽象类,但抽象类不一定存在抽象方法。子类继承了父类的抽象方法后,使用不同的实现(即方法体)来重载它。于是便形成了若干个名字、返回值类型和参数表都相同,而方法体不同的重载方法。,2023年6月22日星期四,4.5.2 抽象方法(续一),使用抽象方法的好处是:抽象方法在不同类中重载,隐藏具体的实现细节信息,在程序中只需给出抽象方法名,而不必知道具体调用哪个方法。抽象方法对外提供了一个共同的接口,该抽象类的所有子类都可以使用该接口来实现该功能。使用抽象方法要注意以下两点:abstract抽象方法只允许方法声明,不允许实现;abstract抽象方法不能被同时声明为final方法。P158【例4-17】抽象方法与抽象类的关系与应用.程序清单4-17:AbstractMethodDemo.java,2023年6月22日星期四,4.6 接口,接口(Interface)是Java中支持多态性的另一种重要机制。接口允许多继承,是对类继承的扩充。一方面引进接口是为了弥补Java不支持多继承带来的不足,由于Java只支持单重继承而不支持多重继承,其类层次结构是树状结构,降低了复杂性,为了解决现实世界中存在的多继承问题,引进接口则可以实现类似于多重继承的网状层次结构。另一方面,从软件工程的角度看,引进接口可有效地将软件设计和实现分离,使开发者分工明确,提高了软件质量,在面向对象程序设计语言的发展中具有里程碑意义。,2023年6月22日星期四,4.6.1 接口的概念,Java中的接口有两种意思:概念性接口,指系统对外提供的所有服务,类的所有能被外部使用者访问的方法构成了类的接口。接口类型:指用interface关键字定义的接口,它明确地描述了系统对外提供的所有服务,清晰地把系统的实现细节与接口分离。Java中的接口类型(简称接口)实际上是由常量和抽象方法构成的特殊类。在接口定义中,仅规定了实现某些功能的对外接口和规范,但是不包含具体的实现,这些功能是在“实现”了该接口的各个类中完成的,在这些类中具体定义了接口中各个抽象方法的方法体。,2023年6月22日星期四,4.6.2 接口的定义,接口由接口首部和接口体两部分构成,定义接口的一般格式:public interface extends publicstaticfinal=;/常量说明 publicabstractnative(参数表)throws 异常列表;/抽象方法说明 其中,interface是定义接口的关键字。接口名的首字母大写,若多个单词组成接口名则每个单词的首字母大写。1)一个接口可以继承若干个父接口。2)一个类可以“实现”若干个接口,从而获得多个“父类”,实现多重继承。3)接口体由接口常量和抽象方法两部分组成,因此,接口是若干个常量和抽象方法的集合。,2023年6月22日星期四,接口的主要特性,接口与抽象类在表面上有些相似,如两者都不能被实例化。但接口对其中的成员变量和成员方法增加了许多限制,其主要特性有:接口的访问控制符有public和默认两种,被public修饰的是公有接口,可被所有类和接口使用。没有访问控制符(默认访问控制)的接口只能被同一个包中的其他类和接口使用接口中的成员变量必须是被public、static和final修饰的,默认都是“public static final”类型的变量,且必须被显式初始化。接口中的成员方法必须是被public和abstract修饰的,默认都是“public abstract”类型的方法。若接口中存在native方法(方法体使用非Java语言编写),则该接口需加native修饰符.,2023年6月22日星期四,接口的主要特性(续一),接口中只能包含“public static final”类型的成员变量和“public abstract”类型的成员方法。接口没有构造方法,不能被实例化。接口具有继承性。一个接口可以通过关键字extends来继承多个其他接口,从而实现“多重继承”。但接口不能实现另一个接口。接口必须通过类来实现它的方法。一个类只能继承一个直接父类,但可以用implements关键字来实现多个接口。与子类继承抽象父类相似,当类实现某个接口时,它必须实现接口中所有的抽象方法,否则这个类必须被定义为抽象类。不允许创建接口的实例,但允许定义接口类型的引用变量,该引用变量能引用这个接口类的实例。P160【例4-18】接口的定义与主要特性。程序清单4-18:InterfaceDefineDemo.java,2023年6月22日星期四,4.6.3 接口的实现,接口的实现是指接口被类实现,在它的实现类中具体给出接口中抽象方法的方法体。类中实现接口的一般方法是:在类的头部,使用关键字implements说明该类要实现的接口。若实现接口的类是非抽象类,则该类体内必须实现接口中所有的抽象方法,并且方法头应与接口中定义的完全一致。若实现接口的类是抽象类,则可以不实现接口中的所有方法,但是在抽象类的非抽象子类中对其父类所实现的接口中所有抽象方法都必须实现。一个类在实现某接口的抽象方法时,必须使用完全相同的方法头。若在类中实现方法时,则方法必须显式地被public修饰,因为接口的抽象方法均是显式或隐式的public方法。,2023年6月22日星期四,4.6.3 接口的实现(续一),P162【例4-19】使用接口描述堆栈的基本操作并用类实现其基本操作。堆栈是一种先进后出(First In and Last Out,FILO)的线性表,只允许从同端进行插入和删除,包括初始化、入(压)栈、出(弹)栈、栈判空、取栈顶元素等基本操作。程序清单4-19:CharStackDemo.java,2023年6月22日星期四,4.6.4 接口与抽象类的比较,1接口与抽象类的异同接口常常被用来为具有相似功能的一组类,对外提供一致的服务接口,这一组类可以是相关的,也可以是不相关的,而抽象类则是为一组相关的类提供一致的服务接口。所以,接口往往比抽象类具有更大的灵活性。(1)相同点:抽象类与接口都位于继承树的上层,代表系统的抽象层;都不能被实例化;都能包含有抽象方法。,2023年6月22日星期四,4.6.4 接口与抽象类的比较(续一),(2)不同点:在抽象类中可以为部分方法提供默认的实现,避免在子类中重复实现它们,提高了代码的可重用性,这是抽象类的优势所在;而接口中只能包含抽象方法,不可以有任何实现代码。抽象类与其子类之间存在泛化(层次/从属)关系,而接口与实现它的类之间则不存在任何层次关系,只存在实现关系。抽象类只能被单继承,而接口可以被多继承;一个类只能继承一个直接的父类,这个父类可以是抽象类,但一个类可以同时实现多个接口,这是接口的优势所在。在接口中只能声明公有的类常量字段,而抽象类中可以声明任何字段。抽象类能够尽可能地为它的相关子类提供公共特征性,包括属特征和行为特征,而接口则为一组子类仅提供一组对外的服务接口,即抽象方法。接口是在编译时处理,而抽象类是在运行时处理,接口比抽象类能节省运行开销。,2023年6月22日星期四,2使用接口的优势,对于已经存在的类继承树,可以方便地从类中抽象出新的接口,但是从类中抽象出抽象类却不那么容易,因此接口更有利于软件系统的维护与重构。使用接口,可以方便地对已经存在的系统进行自下而上的抽象。对于任意两个类,不管它们是否属于同一个父类,只要它们存在相同的功能,就能从中抽象出一个接口类型。接口中定义了系统对外提供的一组相关服务,接口并不能强迫它的实现类在语义上是同一种类型。,2023年6月22日星期四,3使用接口和抽象类的原则,接口是系统中最高层次的抽象类型,要用接口作为系统与外界交互的窗口。接口本身必须十分稳定,一旦制定,不要随意修改,否则会对外界使用者及系统内部都造成影响。可用抽象类来定制系统中的扩展点。,2023年6月22日星期四,4.7 内部类与匿名类,4.7.1 内部类1内部类的定义与优势一个类的内部也可以包含(嵌套)另一个类,称这个被包含的类为内部类(Inner Class)或嵌入类(Nested Class)。相应地,把包含内部类的类称之为外部类(Outer Class)。此外,将类定义代码不嵌套在其他类定义中的类称为顶层类(Top-level Class)。与一般的类相同,内部类也具有自己的成员变量和成员方法。通过建立内部类的对象,可以存取其成员变量和调用其成员方法。P167【例4-20】简单内部