夯实Java基础(三)——面向对象之继承

一、继承概述

继承是Java面向对象的三大特征之一,是比较重要的一部分,与后面的多态有着直接的关系。继承就是子类继承父类的特征和行为,使得子类对象(实例)具备父类的实例域和方法,或子类从父类继承方法,使得子类具备父类相同的行为。java

①、Java继承的特色:this

  • Java只支持单继承 ,不支持多继承(如A继承B,A继承C),但支持多层继承(如A继承B,B继承C) 。
  • 子类拥有父类非private的属性,方法。(其实子类继承父类后,仍然认为获取了父类的private结构,只是由于封装的影响,使得子类不能直接调用父类的结构而已)
  • 子类能够拥有本身的属性和方法,即子类能够对父类进行扩展。
  • 子类能够用本身的方式实现父类的方法。
  • 提升了类之间的耦合性(继承的缺点,耦合度高就会形成代码之间的联系)。

②、继承的好处:spa

  • 减小代码的冗余,提升代码的复用性。
  • 便于功能的扩展。
  • 为后面多态的使用提供了前提。

③、类的继承格式:code

在Java中经过 extends 关键字来实现继承关系,形式以下:对象

class 父类 {
    属性、方法
}
 
class 子类 extends 父类 {
    属性、方法
}

 提到Java的继承,确定离不开this,super关键字和构造器的使用,下面来介绍一下:blog

二、this、super关键字

this关键字:表示引用当前对象或正在建立的对象。可用于调用本类的属性、方法、构造器。继承

public class Test {
    public static void main(String[] args) {
        Father father=new Father("tang_hao",20);
        father.show();
    }
}
class Father{
    String name;
    int age;

    public Father() {
    }

    public Father(String name) {
        //调用本类的无参构造器
        this();
        this.name = name;
    }

    public Father(String name, int age) {
        //调用本类的有参构造器
        this(name);
        this.age = age;
    }

    public void show(){
        System.out.println("name"+this.name+",age"+this.age);
    }
}

super关键字:表示引用当前对象的父类。可用于调用父类的属性、方法、构造器。编译器

public class Test {

    public static void main(String[] args) {
        Son son=new Son();
        son.show();
    }
}
class Father{
    String name="Father";
    int age=40;

    public Father() {
        System.out.println("调用了父类的无参构造器");
    }

    public void show(){
        System.out.println("父类的Show方法");
    }
}

class Son extends Father{
    String name="Son";
    int age=20;

    public Son() {
        //调用父类构造器
        super();
    }

    public void show(){
        System.out.println("子类的Show方法");
        System.out.println("本类属性:"+this.name+","+this.age);
        //调用父类方法
        super.show();
        System.out.println("父类属性:"+super.name+","+super.age);
    }
}

注意:在使用this、super调用构造器的时候,this、super语句必须放在构造方法的第一行,不然编译会报错。不能在子类中使用父类构造方法名来调用父类构造方法。 父类的构造方法不被子类继承。调用父类的构造方法的惟一途径是使用 super 关键字,若是子类中没显式调用,则编译器自动将 super();也就是说会一直调到Object类,由于Object是全部类的父类。静态方法中不能使用 super 关键字。编译

三、构造器

前面讲到子类能够继承父类的非private修饰的属性和方法,那么咱们思考一下?父类的构造器可以被子类继承吗?答案是:不能!对于构造器而言,它只可以被调用,而不能被继承。 调用父类的构造方法咱们使用super()便可。class

咱们先来看一个示例:

public class Father {
    protected String name;//姓名
    protected int age;//年龄

    public Father(){
        System.out.println("Father constructor");
    }

    public void eat(){
        System.out.println("Father eat...");
    }

    public void sleep(){
        System.out.println("Father sleep...");
    }
}

class Son extends Father{
    protected String name;//姓名
    protected int age;//年龄

    public Son() {
        System.out.println("Son constructor");
    }

    public void eat() {
        System.out.println("Son eat...");
    }

    public void sleep() {
        System.out.println("Son sleep...");
    }

    public static void main(String[] args) {
        Son son=new Son();
        son.eat();
        son.sleep();
    }
}

运行结果:

从运行的结果来看,咱们只new了Son的实例,可是却调用父类的无参构造器,并且先输出了父类构造器的语句。这是由于:若是子类中没显式调用父类构造器,则编译器会自动在构造器方法第一行加上super()。

经过这个示例能够看出,构建过程是从父类“向外”扩散的,也就是从父类开始向子类一级一级地完成构建。并且咱们并无显示的引用父类的构造器,这就是java的聪明之处:编译器会默认给子类调用父类的构造器。

可是,这个默认调用父类的构造器是有前提的:父类有默认构造器。若是父类没有默认构造器,咱们就要必须显示的使用super()来调用父类构造器,不然编译器会报错:没法找到符合父类形式的构造器。

public class Father {
    protected String name;//姓名
    protected int age;//年龄

    public Father(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat(){
        System.out.println("Father eat...");
    }

    public void sleep(){
        System.out.println("Father sleep...");
    }
}

class Son extends Father{
    protected String name;//姓名
    protected int age;//年龄

    public Son(String name, int age) {
        //这里父类没有默认构造器,因此必须显式的使用super()
        super("tang_hao",22);
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println("Son eat...");
    }

    public void sleep() {
        System.out.println("Son sleep...");
    }

    public static void main(String[] args) {
        Son son=new Son("tang_hao",20);
        son.eat();
        son.sleep();
    }
}

小结:子类会默认使用super()调用父类默认构造器,若是父类没有默认构造器,则子类必须显式的使用super()来调用父类构造器,并且super()必需要放在子类构造方法的第一行。

四、继承带来的问题

  1. 子类与父类存在严重的耦合关系。
  2.  继承破坏了父类的封装性。
  3. 子类继承父类的属性和方法,也就说明能够从子类中恶意修改父类的属性和方法。

因此能不使用继承关系就尽可能不要使用继承。

五、什么时候使用继承

  1. 子类须要额外增长属性,而不只仅是属性值的改变。
  2. 子类须要增长本身独有的行为方式(包括增长新的方法或重写父类的方法)。
相关文章
相关标签/搜索