📜  Java中的继承

📅  最后修改于: 2020-03-19 01:22:50             🧑  作者: Mango

继承是OOP(面向对象编程)的重要支柱。这是Java中允许一个类继承另一类的功能(字段和方法)的机制。
重要术语:

  • 超级类:被继承功能的类称为超级类(或基类或父类)。
  • 子类:继承另一个类的类称为子类(或派生类,扩展类或子类)。除了超类的字段和方法外,子类还可以添加自己的字段和方法。
  • 可重用性:继承支持“可重用性”的概念,即,当我们要创建一个新类并且已经有一个包含所需代码的类时,我们可以从现有类中派生新类。通过这样做,我们可以重用现有类的字段和方法。

用于继承的关键字是extends
语法 :

class derived-class extends base-class
{
   //方法和字段
}

示例:在下面的继承示例中,Bicycle类是基类,MountainBike类是扩展了Bicycle类的派生类,而Test类是要运行程序的驱动程序类。

//Java代码,展示继承
class Bicycle
{
    // Bicycle类有两个fields
    public int gear;
    public int speed;
    // Bicycle的构造器
    public Bicycle(int gear, int speed)
    {
        this.gear = gear;
        this.speed = speed;
    }
    // Bicycle有三个方法
    public void applyBrake(int decrement)
    {
        speed -= decrement;
    }
    public void speedUp(int increment)
    {
        speed += increment;
    }
    // toString()打印实例信息
    public String toString()
    {
        return("齿轮数 "+gear
                +"\n"
                + "车速 "+speed);
    }
}
// 测试代码
class MountainBike extends Bicycle
{
    // MountainBike在父类基础上增加了一个field
    public int seatHeight;
    // MountainBike的构造器
    public MountainBike(int gear,int speed,
                        int startHeight)
    {
        // 调用哪个基类(Bicycle)的构造器
        super(gear, speed);
        seatHeight = startHeight;
    }
    // MountainBike增加了一个方法
    public void setHeight(int newValue)
    {
        seatHeight = newValue;
    }
    // 重写toString(),打印更多信息
    @Override
    public String toString()
    {
        return (super.toString()+
                "\n座位高度 "+seatHeight);
    }
}
// 测试代码
public class Test
{
    public static void main(String args[])
    {
        MountainBike mb = new MountainBike(3, 100, 25);
        System.out.println(mb.toString());
    }
}

输出:

齿轮数 3
车速 100
座位高度 25

在上面的程序中,创建MountainBike类的对象时,超类的所有方法和字段的副本将在该对象中获取内存。这就是为什么通过使用子类的对象,我们还可以访问超类的成员。
请注意,在继承期间仅创建子类的对象,而不创建超类的对象。
该程序的说明图:

实际上,继承和多态在Java中一起使用,以实现快速的性能和代码的可读性。

 

Java中的继承类型

以下是Java支持的不同类型的继承。

    1. 单一继承:在单一继承中,子类继承一个超类的功能。在下图中,类A用作派生类B的基类。
      //Java展示单继承
      import java.util.*;
      import java.lang.*;
      import java.io.*;
      class one
      {
          public void print_mango()
          {
              System.out.println("芒果");
          }
      }
      class two extends one
      {
          public void print_for()
          {
              System.out.println("for");
          }
      }
      // 测试代码
      public class Main
      {
          public static void main(String[] args)
          {
              two g = new two();
              g.print_mango();
              g.print_for();
              g.print_mango();
          }
      }

      输出:

      芒果
      for
      芒果

       

    2. 多级继承: 在多级继承中,派生类将继承基类,并且派生类还充当其他类的基类。在下图中,类A充当派生类B的基类,后者又充当派生类C的基类。在Java中,类无法直接访问祖父母的成员。
      // Java展示多继承
      import java.util.*;
      import java.lang.*;
      import java.io.*;
      class one
      {
          public void print_mango()
          {
              System.out.println("芒果");
          }
      }
      class two extends one
      {
          public void print_for()
          {
              System.out.println("for");
          }
      }
      class three extends two
      {
          public void print_mango()
          {
              System.out.println("芒果");
          }
      }
      // 测试类
      public class Main
      {
          public static void main(String[] args)
          {
              three g = new three();
              g.print_mango();
              g.print_for();
              g.print_mango();
          }
      }

      输出:

      芒果
      for
      芒果

       

    3. 层次继承:在层次继承中,一个类充当多个子类的超类(基类)。在下图中,类A充当派生类B,C和D的基类。
      // Java展示层次继承
      import java.util.*;
      import java.lang.*;
      import java.io.*;
      class one
      {
          public void print_mango()
          {
              System.out.println("芒果");
          }
      }
      class two extends one
      {
          public void print_for()
          {
              System.out.println("for");
          }
      }
      class three extends one
      {
          /*............*/
      }
      // Drived class
      public class Main
      {
          public static void main(String[] args)
          {
              three g = new three();
              g.print_mango();
              two t = new two();
              t.print_for();
              g.print_mango();
          }
      }

      输出:

      芒果
      for
      芒果
    4. 多重继承(通过接口):在多重继承中,一个类可以具有多个超类,并且可以从所有父类继承功能。请注意,Java并没有支持多重继承与类,我们只能通过 Interfaces实现多重继承。在下图中,类C从接口A和B派生。
      // Java展示多重继承
      import java.util.*;
      import java.lang.*;
      import java.io.*;
      interface one
      {
          public void print_mango();
      }
      interface two
      {
          public void print_for();
      }
      interface three extends one,two
      {
          public void print_芒果();
      }
      class child implements three
      {
          @Override
          public void print_芒果() {
              System.out.println("芒果");
          }
          public void print_for()
          {
              System.out.println("for");
          }
      }
      // Drived class
      public class Main
      {
          public static void main(String[] args)
          {
              child c = new child();
              c.print_mango();
              c.print_for();
              c.print_mango();
          }
      }

      输出:

      芒果
      for
      芒果

       

    5. 混合继承(通过接口):它是两种或多种上述继承类型的混合。由于Java不支持类的多重继承,因此类也不可能实现混合继承。在Java中,我们只能通过Interfaces实现混合继承。

有关Java继承的重要事实

  • 默认超类:Object对象类除外,它没有超类。其他每个类只有一个,并且只有一个直接超类(单继承)。在没有其他任何显式超类的情况下,每个类都隐式为Object类的子类。
  • 超类只能是一个:超类可以具有任意数量的子类。但是一个子类只能有一个超类。这是因为Java不支持类的多重继承。尽管具有接口,但是Java不支持多重继承。
  • 继承构造函数:子类从其超类继承所有成员(字段,方法和嵌套类)。构造函数不是成员,因此它们不会被子类继承,但是可以从子类调用超类的构造函数。
  • 私有成员继承:子类不继承其父类的私有成员。但是,如果超类具有用于访问其私有字段的公共或受保护的方法(如getter和setter),则这些也可以由子类使用。

在子类中可以做什么?

在子类中,我们可以按原样继承成员,替换它们,隐藏它们或用新成员补充它们:

  • 继承的字段可以像其他任何字段一样直接使用。
  • 我们可以在子类中声明不在超类中的新字段。
  • 继承的方法可以直接使用。
  • 我们可以在子类中编写一个新的实例方法,该方法具有与超类中的签名相同的签名,从而将其覆盖(如上面的示例中,toString()方法被覆盖)。
  • 我们可以在子类中编写一个新的静态方法,该方法具有与超类中的签名相同的签名,从而其隐藏。
  • 我们可以在子类中声明不在超类中的新方法。
  • 我们可以编写一个隐式或使用关键字super调用超类构造函数的子类构造函数。