Java中继承、多态与类的复用 下载本文

内容发布更新时间 : 2024/5/19 15:12:22星期一 下面是文章的全部内容请认真阅读。

本文结合Java的类的复用对面向对象两大特征继承和多态进行了全面的介绍。首先,我们介绍了继承的实质和意义,并探讨了继承,组合和代理在类的复用方面的异同。紧接着,我们根据继承引入了多态,介绍了它的实现机制和具体应用。此外,为了更好地理解继承和多态,我们对final关键字进行了全面的介绍

继承

继承是所有OOP语言不可缺少的部分,在java中,使用extends关键字来表示继承关系。当创建一个类时,总是在继承,如果没有明确指出要继承的类,就总是隐式地从根类 Object 进行继承。如果两个类存在继承关系,则子类会自动继承父类的方法和变量,在子类中可以直接调用父类的方法和变量。需要指出

的是,在java中,只允许单继承,也就是说,一个类最多只能显式地继承于一个父类。但是,一个类却可以被多个类继承 成员变量的继承

当子类继承了某个类之后,便可以使用父类中的成员变量,但是并不是完全继承父类的所有成员变量

子类能够继承父类的 public 和 protected 成员变量 ,不能够继承父类的 private 成员变量,但可以通过父类相应的getter/setter方法进行访问;

?

?

对于父类的包访问权限成员变量,如果子类和父类在同一个包下,则子类能够继承,否则,子类不能够继承;

?

对于子类可以继承的父类成员变量,如果在子类中出现了同名称的成员变量,则会发生 隐藏 现象,即子类的成员变量会屏蔽掉父类的同名成员变量。如果要在子类中访问父类中同名成员变量,需要使用super关键字来进行引用。 成员方法的继承

同样地,当子类继承了某个类之后,便可以使用父类中的成员方法,但是子类并不是完全继承父类的所有方法

子类能够继承父类的 public和protected成员方法 ,不能够继承父类的 private成员方法;

?

?

对于父类的包访问权限成员方法,如果子类和父类在同一个包下,则子类能够继承,否则,子类不能够继承;

?

对于子类可以继承的父类成员方法,如果在子类中出现了同名称的成员方法,则称为 覆盖 ,即子类的成员方法会覆盖掉父类的同名成员方法。如果要在子类中访问父类中同名成员方法,需要使用super关键字来进行引用。 隐藏和覆盖是不同的。 隐藏 是 针对成员变量和静态方法 的,而 覆盖 是 针对普通方法 的。

基类的初始化与构造器

我们知道,导出类就像是一个与基类具有相同接口的新类,或许还会有一些额外的方法和域。但是,继承并不只是复制基类的接口。当创建一个导出类对象时,该对象会包含一个基类的子对象。这个子对象与我们用基类直接创建的对象是一样的。二者的区别在于,后者来自于外部,而基类的子对象被包装在导出类对象的内部

因此,对基类子对象的正确初始化是至关重要的,并且Java也提供了相应的方法来保证这一点:

导出类必须在构造器中调用基类构造器来执行初始化,而基类构造器具有执行基类初始化所需的所有知识和能力。

?

?

当基类含有默认构造器时,Java会自动在导出类的构造器插入对该基类默认构造器的调用,因为编译器不必考虑要传递什么样的参数的问题。

?

若父类不含有默认构造器,或者导出类想调用一个带参数的父类构造器,那么在导出类的构造器中就必须使用 super 关键字显式的进行调用相应的基类的构造器,并且该调用语句必是导出类构造器的第一条语句。

组合,继承,代理

在Java中,组合、继承和代理三种技术都可以实现代码的复用。 1,组合(has-a)

通过在新的类中加入现有类的对象即可实现组合。即,新的类是由现有类的对象所组成。该技术通常用于想在新类中使用现有类的功能而非它的接口这种情形。也就是说,在新类中嵌入某个对象,让其实现所需要的功能,但新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口。 2,继承(is-a)

继承可以使我们按照现有类的类型来创建新类。即,我们采用现有类的形式并在其中添加新代码。通常,这意味着我们在使用一个通用类,并为了某种特殊需要而将其特殊化。本质上,组合和继承都允许在新的类中放置子对象,组合是显式地这样做,而继承则是隐式地做。

3,代理(继承与组合之间的一种中庸之道:像组合一样使用已有类的功能,同时像继承一样使用已有类的接口)

代理是继承与组合之间的一种中庸之道,Java并没有提供对它的直接支持。在代理中,我们将一个成员对象置于所要构造的类中(就像组合),但与此同时我们在新类中暴露了该成员对象的接口/方法(就像继承)

我们使用代理时可以拥有更多的控制力,因为我们可以选择只提供在成员对象中方法的某个子集。

final关键字

? ?

一个永不改变的编译时常量;

一个在运行时被初始化的值,而你不希望它被改变。

对于编译期常量这种情况,编译器可以将该常量值带入任何可能用到它的计算式中,也即是说,可以在编译时执行计算式,这减轻了一些运行时负担。在Java中,这类常量必须满足两个条件:

是基本类型,并且用final修饰;

在对这个常量进行定义的时候,必须对其进行赋值。

空白final

Java允许生成 空白final , 即:声明final但又未给定初值的域 final参数

final参数 主要应用于局部内部类和匿名内部类中 final方法

final关键字作用域方法时,用于锁定方法,以防任何继承类修改它的含义。这是出于设计的考虑:想要确保在继承中使方法行为保持不变,并且不会被覆盖

? ?