Java语言面向对象高级程序设计

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

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!