OOP-Java-08

  1. 继承、抽象类、接口和枚举
    1. 类的继承
    2. 抽象类
  2. 接口
    1. 枚举
    2. Java语言中的常用包(见补充材料)

继承、抽象类、接口和枚举

类的继承

  1. 基本知识

    1. 程序代码复用:通过类的继承方式,可以不用编写相同的代码就能开发出新的类。
    2. 被继承的类称为父类或超类(superclass),由继承而得到的类称为子类(subclass)。
    3. Java语言中不支持多重继承,所以一个类只能有一个直接父类。
    4. 父类是所有子类的公共成员的集合,而每个子类则是父类的特殊化,是对公共成员变量和方法在功能、内涵方面的扩展和延伸。
    5. 子类继承父类的成员变量和方法,同时还可修改重写添加父类的成员变量和方法。
    6. Java语言中有一个名为java.lang.Object的特殊类,所有的类都是直接或间接地继承该类而得到的。
  2. 子类的创建

    1. Java语言中类的继承是通过extends关键字来实现的,其格式如下:
      class SubClass extends SuperClass{
          ……
      }
      
    2. 子类可以从父类那里继承所有非private的成员作为自己的成员。
    3. 若无extends关键字,则该类默认为java.lang.Object类的子类。
    4. 子类的每个对象也是父类的对象(“即是”性质),但父类对象不一定是子类的对象。
    5. 见教材P116例8.1

      1. 例8.1程序说明:
      2. 使用继承过来的成员时,可利用“子类对象.父类成员名”格式进行。
      3. 构造方法是不能被继承的,但子类可以调用父类的构造方法
      4. 在执行子类的构造方法之前,将先调用父类中没有参数的构造方法,其目的是为了帮助继承自父类的成员做初始化的操作
    6. 调用父类中特定的构造方法
      1. 如果父类中有多个构造方法时,如何才能调用父类中某个特定的构造方法呢?
      2. 在子类的构造方法中通过super()来调用父类特定的构造方法。
      3. 例8.2 具体说明见教材。

    7. Person类(一个公司中有普通员工(Employees)及管理人员(Magagers)两类人员)

      1. 说明:子类不能直接访问从父类中继承的私有属性及方法,但可使用公有(及保护)方法进行访问
  3. 在子类中访问父类的成员

    1. 使用super不但可以访问父类的构造方法,还可以访问父类的成员变量和成员方法,但super不能访问在子类中添加的成员。访问父类成员的格式如下:
      super.变量名;
      super.方法名;
      
    2. 由于在子类中不能继承父类中的private成员,所以无法在子类(类外)里访问父类中的这种成员。
    3. 用protected修饰的成员,可以被该类自身、同一包中的其他类、其他包中的类三种类访问。
    4. 见教材P120 例8.3

    5. 子类中声明了与父类中相同的成员变量名,则从父类继承的变量将被隐藏;
    6. 子类拥有了两个相同名字的变量,一个继承自父类,另一个由自己声明;
    7. !!!****当子类执行继承自父类的方法时处理的是继承自父类的变量,而当子类执行它自己声明的方法时,所操作的就是它自己声明的变量;
    8. 使用super.属性访问被隐藏的父类属性;
    9. 调用从父类继承的方法,则操作的是从父类继承的属性。
  4. 覆盖

    1. 覆盖与重载相似,均是Java“多态性”的体现。
    2. 覆盖:指在子类中,定义名称、参数个数与类型均与父类完全相同的方法,用以重写父类里同名方法的功能
    3. 重载:是指在同一个类定义名称相同,参数列表不同的方法。
    4. 在子类中覆盖父类的方法时,可扩大父类中的方法权限,但不能缩小其权限。
    5. 不能覆盖父类中声明的final或static的方法。
    6. 见教材P121 例8.4

    7. 用父类的变量访问子类的成员:只限于“覆盖”的情况发生。
      1. 格式:
      父类 对象 = new 子类();
      对象.子类方法;
      
      1. 见教材 P123例8.5

      2. 方法覆盖的应用场合:
        1. 子类中实现与父类相同的功能,但采用不同的算法或公式;
        2. 在名字相同的方法中,要做比父类更多的事情;
        3. 在子类中需要取消从父类继承的方法。
  5. 不可被继承的成员与最终类

    1. 如果用final来修饰类的成员,则该成员为最终成员。
    2. 若父类的成员不希望被子类的成员所覆盖,则可将它们声明为final
    3. 最终类(final类):用final修饰的类。该类不能有子类。
    4. 成员变量若同时被static和final修饰,则表示常量,若没有初始化则按默认值初始化。
    5. 仅用final不用static修饰则必须且只能赋值一次,不能默认。方式:定义时赋值;构造方法赋值。

抽象类

  1. 基本概念

    1. 抽象类有点类似“模板”的作用,其目的是根据它的格式来创建和修改新的类。
    2. 但是并不能直接由抽象类创建对象只能通过抽象类派生出新的子类,再由其子类来创建对象。
    3. 也就是说,抽象类就是不能用new运算符来创建实例对象的类,它可以作为父类被它的所有子类所共享。
  2. 抽象类与抽象方法

    1. 抽象类的定义格式:
      //抽象方法,在抽象方法里,不能定义方法体。只需声明不需实现
      abstract class 类名{
          声明成员变量;
          返回值的数据类型 方法名(参数表){
                  ……
          } 
          abstract  返回值的数据类型 方法名(参数表);
          }
      
    2. 抽象类的子类必须实现父类中的所有抽象方法或将自己也声明成抽象类
    3. 由于抽象类是需要被继承的,所以abstract类不能用final来修饰。也就说,一个类不能既是最终类,又是抽象类,即关键字abstract与final不能合用
    4. 抽象类中不一定包含抽象方法,但包含抽象方法的类一定要声明为抽象类。
    5. 默认实现:JDK1.8之后,在接口里面可以定义default方法,default方法里面是可以具备方法体的,当子类实现该接口之后,不需要重写该方法即可以调用该方法。 (in another word:默认实现:被继承,并且没有被重写,可以被调用了,就称它默认实现了)
    6. 见教材P131例8.10

接口

  1. 接口的定义
    1. 接口与抽象类非常相似,区别
      1. 接口的数据成员都是静态常量;
      2. 接口中除了抽象方法外,还可以定义默认方法静态方法,但不能有普通方法。
    2. 接口的定义语法:
      //public若没有则为默认访问控制符
      [public] interface 接口名称 [extends 父接口名列表]{
          //默认为public static final,成员变量必须赋初值且不能修改
              [public][static][final] 数据类型 成员变量名=常量;
              //抽象方法,默认为public abstract
              [public][abstract] 返回值的数据类型 方法名(参数表);
              [public]static返回值类型 方法名(参数表){方法体}
              [public]default返回值类型 方法名(参数表){方法体}
      }
      
  2. 接口的实现与引用
    1. 接口的实现:利用接口的特性来建造类的过程。类似与继承,但不是extends,而是使用implements。
      1. 接口实现的语法格式:
        class  类名称  implements  接口名表 {
            ……
        }
        
      2. 一个类实现一个接口应注意的问题:
        1. 如果实现某接口的类不是abstract的抽象类,则在类的定义部分必须实现指定接口的所有抽象方法。
        2. 一个类在实现某接口的抽象方法时,必须使用完全相同的方法头。
        3. 接口中抽象方法被指定为public,所以类在实现方法时,必须显示地使用public修饰符。
        4. 接口可以作为一种引用类型来使用,可以声明接口类型的变量或数组,并用它来访问实现该接口的子类的对象。
        5. 非抽象类中不能有抽象方法
        6. 其他类要和实现了这些接口的类对接的 就靠这些公开的类的方法、属性来对接 类之间一定会有相互作用,一起干活,才是一个“系统” 所以相互作用就靠这些接口
        7. 见教材P134例8.11

    2. 接口的继承(扩展)
      1. 定义一个接口时可通过extends关键字声明该新接口是某个已存在的父接口的派生接口,它将继承父接口的常量、抽象方法和默认方法,但不能继承父接口的静态方法,也不能被实现类继承;
      2. 接口继承与类继承的区别:一个接口可以有一个以上的父接口,它们之间用逗号隔开,形成父接口列表。
      3. 如果接口中定义了与父接口同名的常量或相同的方法,则父接口中的常量被隐藏,方法被覆盖。
      4. 见教材P135例8.12

    3. 利用接口实现类的多重继承
      1. 多重继承:一个子类可以有一个以上的直接父类,该子类可以继承它所有直接父类的成员。
      2. Java语言虽不支持多重继承,但可以利用接口间接地解决多继承问题。
      3. 一个类只能有一个直接父类,但是它可以同时实现若干个接口。一个类实现多个接口时,在implements子句中用逗号分隔各个接口名。
      4. Java中接口的主要作用是可以帮助实现多重继承。
      5. 见教材P137例8.13

    4. 接口中静态方法和默认方法
      1. 接口中的静态方法与普通类中的静态方法定义相同。
      2. 接口中的默认方法用default修饰符来定义,默认方法可以被子接口或被实现该接口的类所继承,但子接口中若定义名称相同的默认方法,则父接口中的默认方法被隐藏。
      3. 如果一个类只extend父类,不重写父类的方法,会怎么样:会得到父类方法
      4. interface里的default方法也是一样的东西,如果implement了这个interface,但不override的话,就会获得interface里的那个方法实现
      5. interface有三种方法
        1. 一种static类方法(使用 接口名.静态方法 即可调用)
        2. 一种default默认方法(默认方法其实是子类可实现可不实现,子类也可以选择把它override掉)
        3. 一种需要子类实现的方法(没有static没有default没有方法体,等着子类实现)
      6. 见教材P138例8.14

    5. 解决接口多重继承中名字冲突问题
      1. 如果子接口中定义了与父接口同名的常量或者相同的方法,则父接口中的常量被隐藏,方法被覆盖。但在接口的多重继承中可能存在常量名或方法名重复的问题,即名字冲突问题。
      2. 对于常量,若名称不冲突,子接口可以继承多个父接口中的常量,如果多个父接口中有同名的常量,则子接口不能继承,但子接口中可以定义一个同名的常量。
      3. 对于多个父接口中存在同名的方法时,此时必须通过特殊的方式加以解决.
      4. 见教材P139-140

    6. 补充:方法覆盖与多态
      1. 从相同的基类派生出来的多个类型可被当作同一种类型对待,可对这些不同的类型进行同样的处理,由于多态性,这些不同派生类对象响应同一方法时的行为是有所差别的。
      2. 技术基础
        1. 向上塑型技术:一个父类的引用变量可以指向不同的子类对象;
        2. 动态绑定技术:运行时根据父类引用变量所指对象的实际类型执行相应的子类方法,从而实现多态性。
        3. 绑定:指将一个方法调用同一个方法主体连接到一起。
        4. 根据绑定时期的不同,可分为:
          1. 早期绑定:程序运行之前执行绑定
          2. 晚期绑定:也叫作“动态绑定”或“运行期绑定”,基于对象的类别,在程序运行时执行绑定
        5. 例:以绘图为例

        6. 塑型(type-casting):又称为类型转换
          1. 隐式(自动)的类型转换
          2. 显式(强制)的类型转换
          3. 塑型的对象包括:
            1. 基本数据类型:将值从一种形式转换成另一种形式;
            2. 引用变量:将对象暂时当成更一般的对象来对待,并不改变其类型;
          4. 只能被塑型为:
            1. 任何一个父类类型;对象所属的类实现的一个接口
          5. 例:塑型的概念的一个例子塑型的概念的一个例子

        7. 隐式(自动)的类型转换
          1. 基本数据类型:相容类型之间存储容量低的自动向存储容量高的类型转换
          2. 引用变量
            1. 被塑型成更一般的类:
              //将Manager类型的对象直接赋给Employee类的引用变量,系统会自动将Manage对象塑型为Employee类
              Employee  emp; 
              emp = new Manager(); 
              
            2. 被塑型为对象所属类实现的接口类型:
              Car  jetta = new Car(); 
              Insurable  item = jetta;
              
        8. 显式(强制)的类型转换
          1. 基本数据类型
            (int)871.34354;     // 结果为 871 
            (char)65;              // 结果为‘A’ 
            (long)453;            // 结果为453L
            
          2. 引用变量:还原为本来的类型
            Employee  emp; 
            Manager man;
            emp = new Manager();
            man = (Manager)emp; //将emp强制塑型为本来的类型
            
        9. 当一个类对象被塑型为其父类后,它提供的方法会减少。
          1. 案例图

          2. 当Manager对象被塑型为Employee之后,它只能接收getName()及getEmployeeNumber()方法,不能接收getSalary()方法
          3. 将其塑型为本来的类型后,又能接收getSalary()方法了

枚举

  1. 枚举类型的定义
    1. 如何写枚举
      [修饰符] enum 枚举类型名{
      枚举成员
      方法
      }
      
    2. 修饰符可以是public、private、internal。
    3. 枚举类型名:有两层含义,一是作为枚举名使用;二是表示枚举成员的数据类型,因此,枚举成员也称为枚举实例或枚举对象。
  2. 不包含方法的枚举类
    1. 每个枚举类型的成员都可以看作是Enum类的实例,
    2. 这些枚举成员默认被public final static修饰。
    3. 当访问枚举类型的成员时,直接使用枚举名调用枚举成员即可,即“枚举名.枚举成员”。
    4. 也可使用Enum类定义的valueOf()方法通过“枚举名.valueOf()”的形式进行调用来获取枚举的对象。
    5. 见教材例8.16

  3. 包含属性和方法的枚举类
    1. 因为枚举也是一种类,所以它具有与其他类几乎相同的特性,因此可以定义枚举的属性、构造方法以及方法。
    2. 但是,枚举的构造方法只是在构造枚举实例值时被调用。
    3. 每一个枚举实例值都是枚举的一个对象,因此创建每个枚举实例时都需要调用该构造方法。
    4. 见教材例8.17

Java语言中的常用包(见补充材料)


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,可以邮件至 963614756@qq.com。