• 1. 注意:开始用功了!第 1 页
  • 2. 《Java2实用教程(第4版)》 第5章子类与继承 第 2 页
  • 3. 导读主要内容 子类与父类 子类的继承性 子类与对象 成员变量的隐藏和方法重写 super关键字 final关键字 对象的上转型对象 继承与多态 abstract类与abstract方法 面向抽象编程 开-闭原则第 3 页
  • 4. §5.1 子类与父类 利用继承,可以先编写一个共有属性的一般类,根据该一般类再编写具有特殊属性的新类,新类继承一般类的状态和行为,并根据需要增加它自己的新的状态和行为。 由继承而得到的类称为子类,被继承的类称为父类(超类)。 第 4 页
  • 5. 5.1.1 声明子类 使用关键字extends来定义一个类的子类,格式如下: class 子类名 extends 父类名 { … } 例如: class Student extends People { … } 把Student类定义为People类的子类、People类是Student类的父类 第 5 页
  • 6. 5.1.2类的树形结构 Java的类按继承关系形成树形结构这个树形结构中,根节点是Object类 (Object是java.lang包中的类),即Object是所有类的祖先类。 除了Object类每个类有且仅有一个父类,一个类可以有多个或零个子类。如果一个类(除了Object类)的声明中没有使用extends关键字,这个类被系统默认为是Object的子类,即类声明“class A”与“class A extends Object”是等同的。 第 6 页
  • 7. §5.2 子类的继承性 所谓子类继承父类的成员变量作为自己的一个成员变量,就好象它们是在子类中直接声明一样,可以被子类中自己定义的任何实例方法操作。 所谓子类继承父类的方法作为子类中的一个方法,就好象它们是在子类中直接定义了一样,可以被子类中自己定义的任何实例方法调用。 第 7 页
  • 8. §5.2.1 子类和父类在同一包中的继承性 如果子类和父类在同一个包中,那么,子类自然地继承了其父类中不是private的成员变量作为自己的成员变量,并且也自然地继承了父类中不是private的方法作为自己的方法,继承的成员变量或方法的访问权限保持不变。第 8 页
  • 9. 下面的例子1中有4个类:People,Student.java,UniverStudent.java和Example5_1,这些类都没有包名(需要分别打开文本编辑器编写、保存这些类的源文件,比如保存到C:\ch5目录中),其中UniverStudent类是Student的子类,Student是People的子类。程序运行效果如图5.1。第 9 页
  • 10. §5.2.2 子类和父类不在同一包中的继承性   如果子类和父类不在同一个包中,那么,子类继承了父类的protected、public成员变量做为子类的成员变量,并且继承了父类的protected、public方法为子类的方法,继承的成员或方法的访问权限保持不变。 第 10 页
  • 11. 关于protected的进一步说明对于子类D声明的protected成员变量和方法,只要other类和D类在同一个包中,other类对象object就可以访问这些protected成员变量和方法 对于子类D从父类继承的protected成员变量和方法,需要追溯到成员变量和方法所在的“祖先”类,若other类和其祖先类在同一个包中,object对象就可以访问其protected变量和方法。第 11 页
  • 12. §5.2.3 继承关系(Generalization)的UML图 如果一个类是另一个类的子类,那么UML通过使用一个实线连接两个类的UML图来表示二者之间的继承关系,实线的起始端是子类的UML图,终点端是父类的UML图,但终点端使用一个空心的三角形表示实线的结束。 第 12 页
  • 13. §5.3 子类与对象 子类的构造方法创建一个子类的对象时,不仅子类中声明的成员变量被分配了内存,而且父类的成员变量也都分配了内存空间,但只将子类继承的那部分成员变量作为分配给子类对象的变量 。 子类中有一部分方法是从父类继承的,这部分方法可以操作子类未继承的变量 。5.3.1 子类对象的特点 5.3.2 关于instanceof运算符 instanceof运算符是Java独有的双目运算符,其左面的操作元是对象,右面的操作元是类,当左面的操作元是右面的类或其子类所创建的对象时,instanceof运算的结果是true,否则是false 例子2中,子类ChinaPeople的对象调用继承的方法操作未被子类继承却分配了内存空间的变量。程序运行效果如图5.3。第 13 页
  • 14. §5.4 成员变量的隐藏和方法重写 §5.4.1 成员变量的隐藏 对于子类可以从父类继承的成员变量,只要子类中声明的成员变量和父类中的成员变量同名时,子类就隐藏了继承的成员变量,子类自己声明定义的方法操作与父类同名的成员变量是指子类重新声明定义的这个成员变量。 第 14 页
  • 15. 子类隐藏继承成员变量的特点子类对象以及子类自己定义的方法操作与父类同名的成员变量是指子类重新声明的这个成员变量; 子类继承的方法所操作的成员变量一定是被子类继承或隐藏的成员变量第 15 页
  • 16. 例子3(Example5_3.java)中,Goods类有一个名字为weight的double型成员变量,本来子类CheapGoods可以继承这个成员变量,但是子类CheapGoods又重新声明了一个int型的名字为weight的成员变量.程序运行效果如图5.4 . 第 16 页
  • 17. §5.4.2 方法重写(Override) 子类通过重写可以隐藏已继承的实例方法。 1.重写的语法规则 如果子类可以继承父类的某个实例方法,那么子类就有权利重写这个方法。 方法重写是指:子类中定义一个方法,这个方法的类型和父类的方法的类型一致或者是父类的方法的类型的子类型,并且这个方法的名字、参数个数、参数的类型和父类的方法完全相同。 2.重写的目的 子类通过方法的重写可以隐藏继承的方法,子类通过方法的重写可以把父类的状态和行为改变为自身的状态和行为。 3. 重写的效果 一旦方法被重写,子类对象调用的方法一定是重写的方法,如果没有重写,而是继承了父类的方法,那么子类的对象可以调用从父类继承的方法。第 17 页
  • 18. 在下面的例子4(Example5_4.java)中,ImportantUniversity是University类的子类,子类重写了父类的enterRule()方法,运行效果如图5.5。 在下面的例子5中,子类B重写了父类的computer()方法,运行效果如图5.6。 第 18 页
  • 19. 3.重写的注意事项 重写父类的方法时,不允许降低方法的访问权限,但可以提高访问权限(访问限制修饰符按访问权限从高到低的排列顺序是:public、protected、友好的、private。) 4.JDK1.5对重写的改进 在JDK1.5版本之后,允许重写方法的类型可以是父类方法的类型的子类型,即不必完全一致(JDK1.5版本之前要求必须一致),比如父类的方法的类型是People,重写方法的类型可以是Student(假设Student是People的子类) 例子6中,父类的方法是Object类型,子类重写方法的类型是Integer类型 第 19 页
  • 20. §5.5 super关键字 5.5.1 用super操作被隐藏的成员变量和方法 子类可以隐藏从父类继承的成员变量和方法,如果在子类中想使用被子类隐藏的成员变量或方法就可以使用关键字super。比如super.x、super.play()就是访问和调用被子类隐藏的成员变量x和方法play(). 例子7中,子类使用super访问和调用被子类隐藏的成员变量和方法,运行效果如图5.7。 第 20 页
  • 21. §5.5.2 使用super调用父类的构造方法 子类不继承父类的构造方法,因此,子类如果想使用父类的构造方法,必须在子类的构造方法中使用,并且必须使用关键字super来表示,而且super必须是子类构造方法中的头一条语句。 例子8中,UniverStudent是Student的子类,UniverStudent子类在构造方法中使用了super关键字,运行效果如图5.8。 第 21 页
  • 22. §5.6 final关键字 final关键字可以修饰类、成员变量和方法中的局部变量。 第 22 页
  • 23. §5.6.1 final类 可以使用final将类声明为final类。final类不能被继承,即不能有子类。如: final class A { … … } 第 23 页
  • 24. §5.6.2 final方法 如果用final修饰父类中的一个方法,那么这个方法不允许子类重写。 第 24 页
  • 25. §5.6.3 常量 如果成员变量或局部变量被修饰为final的,就是常量。 例子9 使用了final关键字第 25 页
  • 26. §5.7 对象的上转型对象 假设,A类是B类的父类,当用子类创建一个对象,并把这个对象的引用放到父类的对象中时,比如:A a; a=new B(); 或 A a; B b=new B(); a=b; 这时,称对象a是对象b的上转型对象。第 26 页
  • 27. 1.上转型对象不能操作子类新增的成员变量;不能调用子类新增的方法。 2.上转型对象可以访问子类继承或隐藏的成员变量,也可以调用子类继承的方法或子类重写的实例方法。上转型对象操作子类继承的方法或子类重写的实例方法,其作用等价于子类对象去调用这些方法。因此,如果子类重写了父类的某个实例方法后,当对象的上转型对象调用这个实例方法时一定是调用了子类重写的实例方法。 例子10 中,monkey是People类型对象的上转型对象,运行效果如图5.10。 第 27 页
  • 28. 注意事项不要将父类创建的对象和子类对象的上转型对象混淆 不可以将父类创建的对象的引用赋值给子类声明的对象第 28 页
  • 29. §5.8 继承与多态 多态性就是指父类的某个方法被其子类重写时,可以各自产生自己的功能行为,下面的例子11展示了多态,运行效果如图5.11。 第 29 页
  • 30. §5.9 abstract类和abstract()方法 用关键字abstract修饰的类称为abstract类(抽象类)。如: abstract class A { … … } 用关键字abstract修饰的方法称为abstract方法(抽象方法),例如: abstract int min(int x,int y); 注意: 1.abstract类中可以有abstract方法,也可以有非abstract方法。 2.abstract类不能用new运算创建对象 3. abstract类的对象作上转型对象 例子12 使用了abstract类 第 30 页
  • 31. 注意事项abstract类可以没有abstract方法 如果一个abstract类是abstract类的子类,它可以重写父类的abstract方法,也可以继承父类的abstract方法。第 31 页
  • 32. §5.10 面向抽象编程 在设计一个程序时,可以通过在abstract类中声明若干个abstract方法,表明这些方法在整个系统设计中的重要性,方法体的内容细节由它的非abstract子类去完成。 使用多态进行程序设计的核心技术之一是使用上转型对象,即将abstract类声明对象作为其子类的上转型对象,那么这个上转型对象就可以调用子类重写的方法。 所谓面向抽象编程,是指当设计某种重要的类时,不让该类面向具体的类,而是面向抽象类,即所设计类中的重要数据是抽象类声明的对象,而不是具体类声明的对象。 Pillar类就是面向抽象类Geometry,Cirle和Rectangle 都是Geometry的子类. Application.java可以用Pillar 类创建出具有矩形底或圆形底的柱体了,程序运行效果如图5.12。 第 32 页
  • 33. §5.11 开-闭原则 所谓“开-闭原则”(Open-Closed Principle)就是让设计的系统应当对扩展开放,对修改关闭。 在设计系统时,应当首先考虑到用户需求的变化,将应对用户变化的部分设计为对扩展开放,而设计的核心部分是经过精心考虑之后确定下来的基本结构,这部分应当是对修改关闭的,即不能因为用户的需求变化而再发生变化,因为这部分不是用来应对需求变化的。 如果系统的设计遵守了“开-闭原则”,那么这个系统一定是易维护的,因为在系统中增加新的模块时,不必去修改系统中的核心模块。 第 33 页
  • 34. 结合 5.10 说明开-闭原则 如果将5.10节中的Pillar类、Geometry类以及Circle和Rectangle类看作是一个小的开发框架,将Application.java看作是使用该框架进行应用开发的用户程序,那么框架满足“开-闭”原则,该框架相对用户的需求就比较容易维护,因为,当用户程序需要使用Pillar创建出具有三角形底的柱体时,系统只需简单的扩展框架,即在框架中增加一个Geometry的Triangle子类,而无需修改框架中的其他类,如图5.14所示 第 34 页
  • 35. 5.12 应用举例 用类封装手机的基本属性和功能,要求手机即可以使用移动公司的ISM卡也可以使用联通公司SIM卡(可以使用任何公司提供的SIM卡) 例子13中的类:MobileTelephone,SIM,SIMOfChinaMobile, SIMOfChinaUnicom , Application 程序运行效果如图5.15。 1.问题的分析 2.设计抽象类 3.设计手机类 第 35 页
  • 36. 第 36 页