Java的继承和多态,super关键字,重载和覆盖

在程序设计中,多态性是指一个名词可以有多种语义。在OOP中,多态不仅指这一种情况,还与类密切相关。同一类的所有对象在收到同一条消息时,将采用同样的动作;而不同类的对象在收到同一消息时,可能采取不同的动作。利用多态可以使系统具有更好的可扩充性。
Java中的多态性主要通过继承中的覆盖(动态绑定)和方法的重载(静态绑定)来实现。

一、继承

子类自然继承父类中所定义的非private的成员变量和普通方法,唯有构造方法例外。

继承一般有多重继承和单一继承两种方式。在**单一继承**  中,每一个类最多只有一个父类,而**多重继承**可以有两个或两个以上的父类。Java不能直接使用多重继承,在某些特殊情况下,需要使用**接口**来实现。

子类的成员变量和父类的同名,称为父类的成员变量(属性)被隐藏;如果是成员方法同名,称父类的成员方法被覆盖。

1.属性的隐藏

  • 修饰符完全相同的情况:
  • 访问权限不相同的情况:Java规定,子类用于隐藏的变量可以和父类的访问权限不同,如果访问权限改变,以子类的权限为准。
  • 数据类型不相同的情况:Java允许子类变量与父类变量的类型完全不同,以修改后的数据类型为准。
  • 常量修饰符不相同的情况:Java允许父类常量被子类常量隐藏,也可以是父类的常(变)量被子类的变(常)量隐藏。
  • 静态修饰符不相同的情况:Java允许用实例成员变量来隐藏静态成员变量,也允许以静态成员变量来隐藏实例成员变量。

概括:子类变量可以修改继承下来的父类变量的任何属性,使用子类对象是,以修改之后的属性为准。

2.方法的覆盖

子类中,如果继承下来的方法不能满足自己的要求,可以将其重写一遍,称为“覆盖”。覆盖必须满足以下两个条件:

 - 方法名称必须相同
 - 方法的参数必须完全相同,包括参数的个数、类型和顺序。

只满足第一条,不满足第二条,就不是覆盖,是重载


  • 修饰符完全相同的覆盖
  • 访问权限不相同的情况:
    子类方法的访问权限可以与父类不同,但只允许更宽松,不允许更严格,它遵循的是“公开的不再是秘密”原则,没有任何办法能够改变这一原则。
  • 返回值数据类型不相同的情况:
    如果返回类型是基本类型,那么在覆盖时不允许出现返回值数据类型不相同的情况。
    如果返回类型是复合类型,覆盖时返回类型必须相容。即或者完全相同,或者子类的返回类型与父类的返回类型存在继承关系。
  • final 修饰符不相同的情况:
    final修饰方法,表示该方法是最终方法。它的子类不能覆盖该方法。一个非最终方法可以在子类中用final修饰变成最终方法。
  • 静态修饰符不同的情况:
    Java规定,静态方法不能被实例方法覆盖。同样实例方法也不允许用静态方法覆盖。
  • 构造方法没有继承机制。它根本不会被继承,也就不存在覆盖问题。Java规定,子类中无论哪个构造方法在执行时,都会先执行父类中无参的构造方法,除非显示地使用super调用其他的构造方法。

Java规定只有父类变量可以引用它的直接或间接子类对象。。反之,子类变量不可引用他耳朵祖先对象,即使采用强制类型转换,能通过编译,运行时也会出错。

//------文件名Base.java------
public class Base{
    public Base(){System.out.println("Base construct.");}
}    
    
//------文件名Derived.java------
public class Derived extends Base{
    public Derived(){
        System.out.println("Derived construct.");
    }
    public static void main(String[] args){
        Base oa = new Derived();//父类变量引用子类对象,成功
        Derived ob;
        oa=new Base();
        ob=(Derived)oa;//强制转换再引用,编译可以通过,但是运行报错
    }
}

二、super关键字

  • 使用super引用父类的成员

子类的变量和方法可以和父类的同名,在这种情况下,父类中的同名成员就被屏蔽起来了(不是清除)如果在子类中想要访问父类的成员,要用到super关键字。

super一般用法:
super.变量名 或 super.方法名([参数列表])
  • 使用super调用父类的构造方法
super的一般用法如下:
super([参数列表])//注意super只能在子类中用于调用父类的成员或构造方法。
使用时必须遵守的规则——
   它只能用在构造方法中。
   它只能是第一条执行语句。
   一个构造方法中只能有一条super语句。

注意:一旦显示地用super调用父类的构造方法,系统就不会再自动调用父类无参的构造方法啦
实际上,如果如果程序员不在子类的构造方法中写入super()或者this()这样的语句,系统会自动在第一行添加一条super()语句。

三、接口与多重继承

Java不允许用类直接实现多重继承,转而用接口来实现这一机制。接口需要用到interface关键字来定义,由成员属性和成员方法两部分构成。

1.接口的定义

[访问权限修饰符] interface 接口名 [extends 父接口1,父接口2,...]{
    //定义成员变量
    [public] [static] [final] 数据类型 变量名 = 初始值;
    //定义成员方法
    [public] [abstract] 返回类型 方法名([参数列表]);
}
  • interface表明是一个接口,访问权限修饰符和类使用的一样,默认访问权是包访问权,一般用public来修饰它。和类有区别的是,接口都是抽象的,所以无需使用abstract来修饰。
  • 接口中的成员属性都是常量。在默认情况下,接口中的成员变量具有“public static final”所联合规定的属性。可用“接口名.变量名”的形式直接使用。接口中不允许使用protected和private关键字。
  • 接口中的成员方法都是抽象方法。在默认情况下,接口中的成员方法具有“public abstract”所联合规定的属性。abstract和static不可联合使用,所以不可能是静态方法。
    因为static修饰的方法是静态方法,其可以直接被类所调用。而abstract修饰的方法为抽象方法,即无方法体的方法,不能够被直接调用,需要在子类或实现类中去编写完整的方法处理逻辑后才能使用。
  • 接口中的所有方法都是抽象的,而构造方法不可能是抽象方法,接口中自然就没有构造方法。

2.接口的实现

接口最终是要用类来实现的。类对接口的继承称为接口的实现。使用关键字implements。一般形式如下:

[类修饰符] class 类名 [extends 父类名][implements 接口名1 [,接口名2,...]]{
    //实现接口中的抽象方法
    public [返回值类型] 方法名([参数表]){//访问权限只能是public
        //方法体
    }
}

四、重载

Java允许在一个类中,多个方法拥有相同的名字,但在名字相同的同时,必须有不同的参数,这就是重载。编译器会根据实际情况来挑选正确的方法。如果编译器找不到匹配的参数,或者找出多个可能的匹配,会产生编译错误,这个过程称为重载解析。

  • 普通方法的重载:
    当方法同名时,为了让编译器区别他们,至少需要下面之一不同:
    1.参数个数不同;
    2.对于位置上的参数类型不同;

注意:不允许参数完全相同而只是返回值不同的情况出现。

另外,访问权限修饰符以及final修饰符对于重载没有影响。

只有在同一个类里面的同名方法才能称为重载,“同一类里面”包括该类从祖先那里继承下来的方法。

  • 构造方法的重载:为了避免错误,务必定义一个不带参的构造方法。

五、重载和覆盖的区别

  • 重载和覆盖的方法名称都相同,但重载要求参数列表不同,而覆盖则要求参数列表完全相同
  • 重载对于方法前面的修饰符没有限制,而覆盖则对这些修饰符的使用有限制
  • 同一类中的方法能够相互重载,但不能相互覆盖。子类对父类方法既可以重载也可以覆盖
  • 重载时,编译器在编译期间就可以确定调用哪一个方法,而覆盖则有可能在运行期间才能确定
运行时的多态运行时的多态性倘若XXX有两个含义,既是父类变量又是一个子类对象,则采用动态绑定的方法,
实例方法在调用方法时,该变量是什么对象,就调用该对象所属类的方法,与变量声明所属的类无关
静态方法变量XXX的调用在XXX声明时就已经确定好了,与指向的对象无关
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值