原文: https://www.programiz.com/java-programming/inheritance

在本教程中,我们将借助示例学习 Java 中的继承。

继承是 OOP(面向对象编程)的关键功能之一,它使我们能够从现有类中定义一个新类。 例如,

  1. class Animal
  2. {
  3. // eat() method
  4. // sleep() method
  5. }
  6. class Dog extends Animal
  7. {
  8. // bark() method
  9. }

在 Java 中,我们使用extends关键字从类继承。 在这里,我们从Animal类继承了Dog类。

Animal是超类(父类或基类),Dog是子类(子类或派生类)。 子类继承超类的字段和方法。

Java 继承 - 图1


IS-A 关系

继承是 is-a 关系。 仅当两个类之间存在 is-a 关系时才使用继承。

这里有些例子:

  • 汽车是车辆。
  • 橙色是水果。
  • 外科医生是医生。
  • 狗是动物。

示例 1:Java 继承

  1. class Animal {
  2. public void eat() {
  3. System.out.println("I can eat");
  4. }
  5. public void sleep() {
  6. System.out.println("I can sleep");
  7. }
  8. }
  9. class Dog extends Animal {
  10. public void bark() {
  11. System.out.println("I can bark");
  12. }
  13. }
  14. class Main {
  15. public static void main(String[] args) {
  16. Dog dog1 = new Dog();
  17. dog1.eat();
  18. dog1.sleep();
  19. dog1.bark();
  20. }
  21. }

输出

  1. I can eat
  2. I can sleep
  3. I can bark

在这里,我们从超类Animal继承了子类DogDog类继承了Animal类的方法eat()sleep()

因此,Dog类的对象可以访问Dog类和Animal类的成员。

Java 继承 - 图2


protected关键字

在先前的教程中,我们了解了privatepublic访问修饰符。

  • private成员只能在类内访问
  • public成员可以从任何地方访问

您还可以分配方法和字段protected。 受保护的成员可以访问

  • 从类内部
  • 在其子类中
  • 在同一包内

这是可以访问访问修饰符的摘要。

子类 全局
public Yes Yes Yes Yes
private Yes No No No
protected Yes Yes Yes No

示例 2:protected关键字

  1. class Animal {
  2. protected String type;
  3. private String color;
  4. public void eat() {
  5. System.out.println("I can eat");
  6. }
  7. public void sleep() {
  8. System.out.println("I can sleep");
  9. }
  10. public String getColor(){
  11. return color;
  12. }
  13. public void setColor(String col){
  14. color = col;
  15. }
  16. }
  17. class Dog extends Animal {
  18. public void displayInfo(String c){
  19. System.out.println("I am a " + type);
  20. System.out.println("My color is " + c);
  21. }
  22. public void bark() {
  23. System.out.println("I can bark");
  24. }
  25. }
  26. class Main {
  27. public static void main(String[] args) {
  28. Dog dog1 = new Dog();
  29. dog1.eat();
  30. dog1.sleep();
  31. dog1.bark();
  32. dog1.type = "mammal";
  33. dog1.setColor("black");
  34. dog1.displayInfo(dog1.getColor());
  35. }
  36. }

输出

  1. I can eat
  2. I can sleep
  3. I can bark
  4. I am a mammal
  5. My color is black

在此,Animal类内部的type字段受到保护。 我们已经使用Main类访问了此字段,

  1. dog1.type = "mammal";

可能是因为AnimalMain类都在同一包(同一文件)中。


Java 方法覆盖

从上面的示例中,我们知道子类的对象也可以访问其超类的方法。

如果在超类和子类中定义了相同的方法,会发生什么?

好吧,在这种情况下,子类中的方法将覆盖超类中的方法。 例如,

示例 3:方法覆盖示例

  1. class Animal {
  2. protected String type = "animal";
  3. public void eat() {
  4. System.out.println("I can eat");
  5. }
  6. public void sleep() {
  7. System.out.println("I can sleep");
  8. }
  9. }
  10. class Dog extends Animal {
  11. @Override
  12. public void eat() {
  13. System.out.println("I eat dog food");
  14. }
  15. public void bark() {
  16. System.out.println("I can bark");
  17. }
  18. }
  19. class Main {
  20. public static void main(String[] args) {
  21. Dog dog1 = new Dog();
  22. dog1.eat();
  23. dog1.sleep();
  24. dog1.bark();
  25. }
  26. }

输出

  1. I eat dog food
  2. I can sleep
  3. I can bark

在此,eat()存在于超类Animal和子类Dog中。 我们创建了子类Dog的对象dog1

当我们使用dog1对象调用eat()时,将调用Dog内部的方法,而不会调用相同的超类方法。 这称为方法覆盖。

在上面的程序中,我们使用了@Override注解来告诉编译器我们正在覆盖方法。 但是,这不是强制性的。 在下一个教程中,我们将详细了解方法覆盖

如果需要从其子类中调用Animaleat()方法,则可以使用super关键字。

示例 4:super关键字

  1. class Animal {
  2. public Animal() {
  3. System.out.println("I am an Animal");
  4. }
  5. public void eat() {
  6. System.out.println("I can eat");
  7. }
  8. }
  9. class Dog extends Animal {
  10. public Dog(){
  11. super();
  12. System.out.println("I am a dog");
  13. }
  14. @Override
  15. public void eat() {
  16. super.eat();
  17. System.out.println("I eat dog food");
  18. }
  19. public void bark() {
  20. System.out.println("I can bark");
  21. }
  22. }
  23. class Main {
  24. public static void main(String[] args) {
  25. Dog dog1 = new Dog();
  26. dog1.eat();
  27. dog1.bark();
  28. }
  29. }

输出

  1. I am an Animal
  2. I am a dog
  3. I can eat
  4. I eat dog food
  5. I can bark

在这里,我们使用super关键字使用super()调用构造器。 此外,我们使用super.eat()调用了Animal超类的eat()方法。

请注意,在调用构造器和方法时,super的用法有所不同。 要了解更多信息,请访问 Java super关键字


继承类型

继承有五种类型。

  • 单一继承 - 类B仅从类A扩展。
  • 多级继承 - 类B从类A扩展而来; 然后C类从B类扩展。
  • 层次继承 - 类A充当类BCD的超类。
  • 多重继承 - 类C从接口AB扩展。
  • 混合继承 - 两种或更多种继承的混合。

Java 不支持通过类的多重继承和混合继承。 但是,我们可以通过接口在 Java 中实现多重继承。 我们将在后面的章节中了解接口。


为什么要使用继承?

  • 最重要的用途是代码的可重用性。 父类中存在的代码无需在子类中再次编写。
  • 通过方法覆盖实现运行时多态。 在后面的章节中,我们将学习有关多态的更多信息。