继承和多态

继承

继承的概念

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

为什么要使用继承

当我们定义多个类存在相同的属性和行为时,代码存在重复了,导致后果就是代码量大且臃肿,而且维护性不高(维护性主要是后期需要修改的时候,就需要修改很多的代码,容易出

错),所以要从根本上解决这两段代码的问题,就需要继承,将两段代码中相同的部分提取出来组成 一个父类。

继承的写法

关键字(extends)

public Class A extends B {}

其中A称之为次类、子类、扩展类或派生类,B称之为超类、父类或基类

父类和子类

1、和传统的理解不同,子类并不是父类的一个子集。实际上,一个子类通常比它的父类包含更多的信息和方法。

2、父类中的私有数据域在该类之外是不可访问的。因此,不能再子类中直接使用。但是,如果父类中定义了公共的访问器/修改器,那么可以通过这些公共的访问器/修改器来访问和修改它们。

3、继承是用来为(is-a)建模的。不要仅仅为了重用方法这个原因而盲目的扩展一个类。例如:尽管Person类和Tree类可以共享类似高度和重量这样的通用特性,但是从Person类扩展出Tree类是毫无意义的。一个父类和它的子类必须存在(is-a)关系。

4、某些程序设计语言是允许从几个类派生出一个子类的。这种能力成为多继承。但是在java中是不允许多继承。一个java类只可能字节继承一个父类。这种限制称为单一继承。另外,java多继承是可以通过接口来实现的。

super关键字

关键字 super 代指父类,可以用来调用父类中的普通方法和构造方法。

调用构造方法

构造方法用于构造一个类的实例。不同于属性和普通方法,父类的构造方法不会被子类继承。它们只能使用关键字 super 调用父类的构造方法。

在子类的构造方法中可以通过 super() 调用父类的无参构造方法,也可以通过 super(arguments) 调用与参数匹配的父类构造方法。

super() 和 super(arguments)  必须出现在子类构造方法的第一行,这是显式调用父类构造方法的唯一方式 

构造方法链

class A {
    public A() {
        System.out.println("A的构造方法!");
    }
}

class B extends A {
    public B() {
        System.out.println("B的构造方法!");
    }
}

class C extends B {
    public C() {
        System.out.println("C的构造方法!");
    }
}

public class test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        C c = new C();
    }

}

上面的代码中,C继承了B,B继承了A,此时实例一个对象c,会出现什么样的结果呢? 结果如下

A的构造方法!
B的构造方法!
C的构造方法!

在代码中,我们并没有调用 super 关键字,为什么会出现这样的结果呢?

在任何情况下,构造一个类的实例时,将会调用沿着继承链的所有父类的构造方法。当构造一个子类的对象时,子类构造方法会在完成自己的任务之前,首先调用它的父类的构造方法。如果父类继承其他类,呢么父类构造方法又会在完成自己的任务之前,调用它自己的父类的构造方法。这个过程持续到沿着这个继承体系结构的最后一个构造方法被调用为止。这就是构造方法链(constructor chaining)。

也就是说:

class B extends A {
    public B() {
        System.out.println("B的构造方法!");
    }
}

class C extends B {
    public C() {
        System.out.println("C的构造方法!");
    }
}

等价于

class B extends A {
    public B() {
        super();
        System.out.println("B的构造方法!");
    }
}

class C extends B {
    public C() {
        super();
        System.out.println("C的构造方法!");
    }
}

super 关键字除了调用父类的构造方法外,也可以调用父类的普通方法: super.方法名(参数);

方法重写

子类从父类中继承方法。有时,子类需要修改父类中定义的方法的实现,这称作方法重写(method overriding)。

要重写一个方法,需要在子类中使用和父类一样的方法名以及一样的返回值类型来对该方法进行定义。

当父类的方法被重写时,如果想要在子类访问该方法,也可用 super 关键字调用。

注意:

1、仅当实例方法是可访问时,他才能被覆盖。因为私有方法在它的类本身以外是不能访问的,所以它不能被覆盖。如果子类中定义的方法在父类中是私有的,那么这两个方法完全没有关系。

2、与实例方法一样,静态方法也能被继承。但是,静态方法不能被覆盖。如果父类中的静态方法在子类中被重新定义,那么在父类中定义的静态方法将被隐藏。可以使用语法:

父类名.静态方法名 调用隐藏的静态方法

 重写与重载的区别

1、方法重写发生在通过继承而相关的不同类;方法重载可以发生在同一个类中,也可以发生在由继承而相关的不同类中。

2、方法重写具有同样的方法名和返回值类型;方法重载具有相同的名字,但是不同的参数列表。

Object类及其toString()方法

java中所有的类都继承自java.lang.Object类,即如果定义一个类时没有指定继承性,那么这个类的父类就被默认为Object。

Object类中的toString()方法

public String toString()

调用一个对象的toString()方法会返回一个描述该对象的字符串。默认情况下,他返回一个由该对象所属的类名、符号@以及该对象十六进制形式的内存地址组成的字符串。

这个信息不是很有用。通常,应该重写这个方法,这样可以返回一个代表该对象的描述性字符串。

多态

多态的三个前提

1、存在继承关系

B,C,D继承A

2、子类要重写父类的方法(这也是多态的弊端,就是:不能使用子类特有的成员属性和子类特有的成员方法。)

3、父类数据类型的引用指向子类对象。

A b = new B();

A c = new C();

A d = new D();

动态绑定

方法可以沿着继承链的多个类中实现。JVM决定运行时调用那个方法

声明类型和实际类型

A b = new B();

一个变量必须被声明为某种类型。变量的这个类型称为它的声明类型,在这里b的声明类型是A。

实例可以使用声明类型或它的子类型的构造方法创建。变量的实际类型是被变量引用的对象实际类,在这里b的实际类型是B

动态绑定的机制

假设对象o是类C1,C2,C3,...,Cn-1,Cn的实例,其中C1是C2的子类,C2是C3的子类,...,Cn-1是Cn的子类。如果o对象调用一个方法p,那么JVM会依次在类C1,C2,C3...,Cn-1,Cn中找方法p,直到找到为止。一旦找到,就停止查找,然后调用这个方法。

深入理解java多态性的例子

https://blog.csdn.net/thinkGhoster/article/details/2307001

方法调用的优先问题 ,优先级由高到低依次为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)

猜你喜欢

转载自www.cnblogs.com/zhanghongcan/p/8962676.html