【Java】继承 覆盖 隐藏 绑定

继承(extends)

  • 继承可以实现代码的复用,被继承的类称为父类或超类(Superclass),继承而得到的类称为子类
  • 子类继承父类可访问(非私有)的成员变量和成员方法,可以修改父类的成员变量或重写父类的方法,可以添加新的成员变量或成员方法
  • 所有的类都是继承JAVA.lang.object而来,如没有,extends关键,则默认该类为object类的子类
  • 继承通过extends关键字实现,使用此关键字指出新定义类的父类,就完成两个类之间建立的继承关系
  • 间接子类,一个类的父类又是另一个类的子类,那么此类为最上层类的间接子类
  • 子类的每个对象也是其父类的对象(继承的"即是"性质),但父类对象不一定是他子类的对象
  • 执行子类的构造方法之前会先调用父类中没有参数的构造方法,其目的是为了要帮助继承自父类的成员做初始化操作
    • 构造方法是不能被继承的,但子类可以调用父类的构造方法,间接地继承会有父类的父类的构造方法被调用
    • 如果父类中有多个构造方法,通过super( )语句来调用父类特定的构造方法
    • 如果使用super( )语句调用了,父类中有参的构造方法,那么父类中无参的构造方法将不会被自动调用(子类有参构造方法中也默认有super(),父类无参构造方法调用语句)
    • 调用父类构造方法的super()语句必须写在子类构造方法的第一行(否则将会出现错误信息)
    • 如果没有用super()语句调用父类中特定的构造方法,而父类中只定义了有参数的构造方法,编译时会发生错误(定义有参构造方法,默认参构造方法消失)
    • Super()语句与this()语句必须放在构造方法内的第一行,所以两个语句无法共存在同一个构造方法中
  • 与this关键字一样,super指的也是对象,所以super同样不能在static环境中使用(静态方法和静态初始化器,其不需要对象来调用)
  • 在子类中可以使用super访问父类的成员
    • 如果父类中成员被定义为 受保护 那么子类中可以直接访问父类的成员
    • Protected,修饰符可以被该类自身与他在同一包中的其他类,在其包中的该类的子类访问
  • 覆盖(方法覆盖)
    • 子类重写父类的方法,要求方法名和参数类型完全一样(参数不能是子类),返回值和异常比父类小或者相同(即为父类的子类),访问修饰符比父类大或者相同。
    • 覆盖属于JAVA多态的一种
    • 覆盖是指在子类中定义名称 参数个数与类型与父类中完全相同的方法,用以重写父类中同名方法的功能
    • 覆盖时保证与父类有完全相同的方法头声明(方法名 返回值类型和参数列表),如果子类的方法头与父类的方法头完全相同,则不能继承,此时子类方法覆盖父类方法
    • 子类不能覆盖父类中声明为final(最终)和static(隐藏)的方法
      • 一个方法被继承,或者是被继承后不能被覆盖,那么这个方法就采用静态绑定
      • 静态绑定,在编译时分配空间,创建对象,是在运行时,在堆中分配空间
    • 默认情况下,所有的成员变量和成员方法都可以被覆盖,如果父类的成员不希望被子类的成员所覆盖,可以将他们声明为final(最终),程序中的其他部分可以访问继承,但不能修改
    • 方法不能交叉覆盖:子类实例方法不能覆盖父类的静态方法;
    • 子类的静态方法也不能覆盖父类的实例方法(编译时报错)
    • 如果一个 类 被final修饰符所修饰,说明这个类不能再被其他类继承,即该类不可能有子类,这种类被称为最终类
    • 所有被private修饰符限定为私有的方法,以及所有被包含在final类中的方法都被默认是final的,这些方法既不可能被子类所继承,也不可能被覆盖
    • 如果一个成员变量继被static修饰也被final修饰,它的含义就是常量,这样的常量只能在定义时被赋值(静态初始化器)
    • 覆盖时子类权限要大于父类权限
      • 在子类中覆盖父类方法时,可以扩大父类中的方法权限,但不能缩小父类中方法的权限,父类中方法覆盖时受保护的可以改为公共的,但不能改为私有的
    • 通过父类的对象(引用变量)访问子类的成员
      • 通过父类的对象访问,子类的成员只限于覆盖的情况发生时
      • 父类与子类的方法名称参数个数与类型必须完全相同,且只能访问覆盖过的方法
  • 隐藏(成员属性,static方法)
    • 静态绑定,在编译时分配空间,创建对象,是在运行时,在堆中分配空间
    • 父类和子类拥有相同名字的属性或者方法( 方法隐藏只有一种形式,就是父类和子类存在相同的静态方法)时,父类的同名的属性或者方法形式上不见了,实际是还是存在的。(向上转型访问的是父类属性或方法)
    • 父类和子类中含有的其实是两个没有关系的方法,它们的行为也并不具有多态性因此,通过一个指向子类对象的父类引用变量来调用父子同名的静态方法时,只会调用父类的静态方法。
    • 隐藏是对于静态方法和成员变量(静态变量和实例变量)而言的
    • (1)当发生隐藏的时候,声明类型是什么类,就调用对应类的属性或者方法,而不会发生动态绑定
    • (2) 属性只能被隐藏,不能被覆盖
    • (3)变量可以交叉隐藏:子类实例变量/静态变量可以隐藏父类的实例/静态变量
    • RTTI(run time type identification,运行时类型检查)
      • RTTI只针对覆盖,不针对隐藏:因为覆盖是动态绑定,是受RTTI约束的,隐藏(静态绑定)不受RTTI约束
      • 运行时类型为引用变量所指向的对象的类型,编译时类型是引用变量自身的类型
  • 绑定
    • 绑定:将一个方法的调用与方法所在的类(方法主体)关联起来。即决定调用哪个方法和变量。
    • 在java中,绑定分为静态绑定和动态绑定。也叫作前期绑定和后期绑定。
      • 静态绑定
        • 在程序执行以前已经被绑定(即在编译过程中就已经知道这个方法到底是哪个类中的方法)。
        • java当中的方法只有final、static、private修饰的的方法和构造方法是静态绑定的。
        • private修饰的方法:private修饰的方法是不能被继承的,因此子类无法访问父类中private修饰的方法。所以只能通过父类对象来调用该方法体。因此可以说private方法和定义这个方法的类绑定在了一起。
        • final修饰的方法:可以被子类继承,但是不能被子类重写(覆盖),所以在子类中调用的实际是父类中定义的final方法。(使用final修饰方法的两个好处:(1)防止方法被覆盖;(2)关闭java中的动态绑定)。
        • static修饰的方法:可以被子类继承,但是不能被子类重写(覆盖),但是可以被子类隐藏。
        • 如果父类里有一个static方法,它的子类里如果没有对应的方法,那么当子类对象调用这个方法时就会使用父类中的方法,而如果子类中定义了相同的方法,则会调用子类中定义的方法,唯一的不同就是:当子类对象向上类型转换为父类对象时,不论子类中有没有定义这个静态方法,该对象都会使用父类中的静态方法,因此这里说静态方法可以被隐藏而不能被覆盖。这与子类隐藏父类中的成员变量是一样的。隐藏和覆盖的区别在于,子类对象转换成父类对象后,能够访问父类被隐藏的变量和方法,而不能访问父类被覆盖的方法
        • 构造方法:构造方法也是不能被继承的(因为子类是通过super方法调用父类的构造函数,或者是jvm自动调用父类的默认构造方法),因此编译时也可以知道这个构造方法方法到底是属于哪个类的
      • 动态绑定
        • 在运行时期根据具体对象的类型进行绑定
        • 若一种语言实现了后期绑定,同时必须提供一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体
        • RTTI(run time type identification,运行时类型检查)
          • RTTI只针对覆盖,不针对隐藏:因为覆盖是动态绑定,是受RTTI约束的,隐藏(静态绑定)不受RTTI约束
          • 运行时类型为引用变量所指向的对象的类型,编译时类型是引用变量自身的类型
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章