Java知识梳理之封装继承多态(二)

70 阅读5分钟

       部分源码的Github网址为:github.com/hzka/JavaBo… 

(一)继承多态的基础概念
1.继承:所谓继承,就是在OOP中,从已知类中派生出新类。可以将多个类的共同特征和行动统一放在一个类中,以此来扩展更多特定的类。如果C1扩展自另一个类C2,C1称为子类、次类;C2称为父类、超类。如下图所示:园和矩形有蛮多相似的特征,将其的几个数据域和方法抽象出来形成超类GemotricObject。Circle和Rectangle继承自该类。在这里使用extends关键字来实现继承关系。具体项目如项目p302所示。

                                

       2.继承时注意的几点:子类比父类信息更多;父类私有数据子类不可直接使用,必须用父类定义的公用访问器/修改器访问;不是所有的关系都可继承,譬如:人和树很难建立关系;Java中不允许多重继承,一个Java类只可能继承自一个父类,可以使用接口来实现多重继承。
3.super关键字:可以调用父类的构造方法亦或是方法。
(1)使用super()或者super(parameters)来调用无参构造方法或参数匹配的构造方法。父类的构造方法是不被子类继承的,它只能从子类的构造方法中使用关键字super进行调用。
(2)当构造一个子类对象时,会首先调用父类的构造方法,形成构造方法链;如果在子类构造方法中没有被显式调用,编译器会自动将super作为构造方法的第一句。示例程序及结果如下:
(3)super除了可以引用父类的构造方法,也可以引用父类的方法。可以使用super.方法名(参数)的形式对对父类方法进行引用。

                      

       4.覆盖方法,子类从父类中继承方法,但有时子类需要修改父类中定义的方法的实现。可以称作方法覆盖。以P302项目为例,Geometricobject类中有toString方法,Circle4继承自Geometricobject,也有一个toString方法覆盖父类的该方法。在这里使用super.toString()访问Geometricobject中的方法。需要注意的是:(1)实例方法可访问时,它才能被覆盖;(2)静态方法可以继承,但不能覆盖,若子类中重定义了父类方法,则父类中的静态方法将被隐藏。

                                

       5.重载方法,方法签名不同,所谓方法签名,即由方法名称和一个参数列表(方法的参数的顺序和类型)组成。如下代码所示,a的执行结果均为10.0,b的执行结果为10和20.0。

6.Java中的每个类都源于java.lang.object类,若一个类没有指定继承性,则其父类默认为object类。所以这两者是一样的。所以有时候需要复写该类的toString()方法用来覆盖父类object类中的toString方法。

7.什么是多态?继承关系使得子类继承父类特征并附加了新特征,每个子类的实例是父类的实例,反之不成立。譬如:圆都是几何对象,但几何对象并非都是圆。程序示例如P302项目所示。从中可以得到:总可以将子类的实例传给需要父类类型的参数。多态是使用父类对象的地方均可以使用子类的对象。父类类型的变量可以引用子类类型的变量。
8.动态绑定:举个例子,toString方法在Object类中定义,而在Geometricobject类中覆盖,那么下面的代码中:o调用了那个toString方法呢?声明类型为Object,实际类型为Geometricobject。o到底调用哪个toString取决于o的实际类型。此称之为动态绑定。因此o指向了Geometricobject的toString方法。

      以下代码为例进行动态绑定的说明。方法m以Object为类型,则可使用任何对象(GraduteStrudent 、Student、Person或object的实例)最为参数调用m。

public class Main {
    public static void main(String[] args) {
        m(new GraduteStrudent());
        m(new Student());
        m(new Person());
        m(new Object());
    }
    public static void m(Object x){
        System.out.println(x.toString());
    }
}
class GraduteStrudent extends Student{}
class Student extends Person{
    @Override
    public String toString() {
        return "Student";
    }
}
class Person extends Object{
    @Override
    public String toString() {
        return "Person";
    }
}

       按照上图的动态绑定原则,运行结果为:

       9.对象转换与instanceof运算符:如上代码所示,m(new Student());等价于Object o = new Student();m(o);此之称之为隐式转换。显示转换分为向上类型转换和向下类型转换。向下类型转换:Student b = Student(o);但确保转换的对象时子类的实例,换而言之,转换存在失败的可能性,一个好的方法是在尝试转换之前,使用运算符instanceof来判断该对象是不是另一个对象的实例。但总是可以将子类的实例转换为一个父类的变量(向上类型转换)。举例P313代码如下:

public class Main {
    public static void main(String[] args) {
        Object object_01 = new Circle4(1);
        Object object_02 = new Rectanglel(1, 1);
        displayObject(object_01);
        displayObject(object_02);
    }
    private static void displayObject(Object object) {
        if (object instanceof Circle4) {
            System.out.println("Area: " + ((Circle4) object).getArea()+".Diameter is:"+((Circle4) object).getDiameter());
        } else if (object instanceof Rectanglel) {
            System.out.println("Area: " +((Rectanglel) object).getArea());
        }
    }
}

        10.protected数据和方法:数据方法的可见性如下图所示。这三张图说明了一切。

                          

       11.防止扩展和覆盖:想要防止类扩展和覆盖,使用final修饰符表明该类或者方法是终结的,是不能被覆盖的。
12.Objects的equals方法:检测两个引用变量是否指向同一个对象,应该在自己的类中覆盖这个方法以测试两个对象是否具有相同的内容。譬如:

                     

                              

(二)实例
1.数组线性表ArrayList:没啥技术含量,就是利用Arraylist类来存储不限定个数的对象。参考p315项目。

       2.自定义栈类:可以使用Arraylist来实现Stack,UML如下图。参考P318项目,注意堆栈先进后出的原则,使用Arraylist来模拟整个过程。

                         

(三)小结