继承在Java中是面向对象编程的核心概念之一。当对象之间存在”is-a”关系时,就会使用Java继承。在Java中,继承是使用`extends`关键字实现的。
Java中的继承
Java中的继承是通过从其他类继承来创建类之间的层次结构的方法。
Java的继承是传递性的 – 因此如果Sedan继承自Car,Car又继承自Vehicle,那么Sedan也从Vehicle类继承。Vehicle成为Car和Sedan的超类。
继承在Java应用程序中被广泛使用,例如扩展Exception类以创建一个包含更多信息(如错误代码)的应用程序特定的Exception类。例如NullPointerException。
Java继承示例
在Java中,每个类都隐式地扩展了java.lang.Object
类。因此,Object类位于Java继承层次结构的顶层。
让我们通过一个简单的例子来看看如何在Java中实现继承。
超类:Animal
package com.journaldev.inheritance;
public class Animal {
private boolean vegetarian;
private String eats;
private int noOfLegs;
public Animal(){}
public Animal(boolean veg, String food, int legs){
this.vegetarian = veg;
this.eats = food;
this.noOfLegs = legs;
}
public boolean isVegetarian() {
return vegetarian;
}
public void setVegetarian(boolean vegetarian) {
this.vegetarian = vegetarian;
}
public String getEats() {
return eats;
}
public void setEats(String eats) {
this.eats = eats;
}
public int getNoOfLegs() {
return noOfLegs;
}
public void setNoOfLegs(int noOfLegs) {
this.noOfLegs = noOfLegs;
}
}
动物是这里的基类。让我们创建一个继承自Animal类的Cat类。
子类:猫
package com.journaldev.inheritance;
public class Cat extends Animal{
private String color;
public Cat(boolean veg, String food, int legs) {
super(veg, food, legs);
this.color="White";
}
public Cat(boolean veg, String food, int legs, String color){
super(veg, food, legs);
this.color=color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
请注意,我们在Java中使用extends
关键字来实现继承。
Java继承测试程序
让我们编写一个简单的测试类来创建一个Cat对象并使用它的一些方法。
package com.journaldev.inheritance;
public class AnimalInheritanceTest {
public static void main(String[] args) {
Cat cat = new Cat(false, "milk", 4, "black");
System.out.println("Cat is Vegetarian?" + cat.isVegetarian());
System.out.println("Cat eats " + cat.getEats());
System.out.println("Cat has " + cat.getNoOfLegs() + " legs.");
System.out.println("Cat color is " + cat.getColor());
}
}
输出:
Cat类没有getEats()
方法,但程序仍然可以正常工作,因为它从Animal类继承而来。
重点
-
代码重用是继承的最重要好处,因为子类继承了超类的变量和方法。
-
超类的私有成员对子类不直接可访问。就像在这个例子中,Animal变量noOfLegs对Cat类不可访问,但可以通过getter和setter方法间接访问。
-
默认访问权限的超类成员只有在它们位于同一包中时,才对子类可访问。
-
超类构造函数不被子类继承。
-
如果超类没有默认构造函数,那么子类也需要定义一个显式构造函数。否则将引发编译时异常。在子类构造函数中,调用超类构造函数在这种情况下是强制性的,并且应该是子类构造函数中的第一条语句。
-
Java不支持多继承,子类只能继承一个类。Animal类隐式地继承了Object类,而Cat类则继承了Animal类,但由于Java继承的传递性,Cat类也同时继承了Object类。
-
我们可以创建子类的实例,然后将其赋值给超类变量,这被称为向上转型。以下是向上转型的简单示例:
Cat c = new Cat(); //子类实例 Animal a = c; //向上转型,因为Cat也是Animal
-
当将一个Superclass的实例分配给一个Subclass变量时,这就是向下转型。我们需要显式地将其转换为Subclass。例如;
Cat c = new Cat(); Animal a = c; Cat c1 = (Cat) a; // 显式转型,因为"c"实际上是Cat类型,所以可以正常工作
请注意,即使我们做错了,编译器也不会抱怨,因为有了显式转型。以下是一些在运行时会抛出
ClassCastException
的情况。Dog d = new Dog(); Animal a = d; Cat c1 = (Cat) a; // 运行时发生ClassCastException Animal a1 = new Animal(); Cat c2 = (Cat) a1; // 运行时发生ClassCastException,因为a1实际上是Animal类型
-
我们可以在Subclass中覆盖Superclass的方法。然而,我们应该始终使用@Override注解对重写的方法进行注解。编译器将知道我们正在重写一个方法,如果超类方法发生了变化,我们将在编译时获得错误,而不是在运行时获得不想要的结果。
-
我们可以使用super关键字调用超类方法和访问超类变量。当我们在子类中有相同名称的变量/方法但想访问超类变量/方法时,这很方便。当超类和子类中定义了构造函数并且我们必须显式调用超类构造函数时,也会用到这一点。
-
我们可以使用
instanceof
指令来检查对象之间的继承关系,让我们通过下面的例子来看一下。
```
Cat c = new Cat();
Dog d = new Dog();
Animal an = c;
boolean flag = c instanceof Cat; //normal case, returns true
flag = c instanceof Animal; // returns true since c is-an Animal too
flag = an instanceof Cat; //returns true because a is of type Cat at runtime
flag = an instanceof Dog; //returns false for obvious reasons.
```
- 我们不能在Java中扩展Final类。
- 如果您不打算在代码中使用超类,即您的超类只是一个基类来保存可重用的代码,那么您可以将它们保持为抽象类,以避免客户类进行不必要的实例化。这也将限制基类的实例创建。
Java 继承视频教程
I have recently published two videos on YouTube explaining Inheritance in detail with sample programs, you should watch them below.
您可以从我们的GitHub 存储库中查看更多继承示例。
参考:Oracle 文档
Source:
https://www.digitalocean.com/community/tutorials/inheritance-java-example