Java继承详解:面向对象编程中的继承概念与实例教程
Java中的继承
在Java中,继承是面向对象编程的核心概念之一。当两个对象之间存在”是一个”(is-a)关系时,我们可以使用Java继承。在Java中,继承是通过使用extends关键字来实现的。
在Java中,继承是通过从其他类继承来创建类的层次结构的方法。
Java的继承具有传递性——如果轿车(Sedan)继承了汽车(Car),而汽车继承了车辆(Vehicle),那么轿车也会从车辆类继承。车辆成为汽车和轿车的父类。
继承在Java应用程序中被广泛使用,例如通过扩展Exception类来创建一个特定于应用程序的异常类,该类包含更多的信息,如错误代码,例如NullPointerException(空指针异常)。
Java继承示例
每个Java类都隐式地继承了java.lang.Object类。因此,Object类位于Java的继承层次结构的顶层。
让我们来看一个简单的示例,了解如何在Java中实现继承。
父类:动物
package com.Olivia.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;
}
}
这里的基类是动物。让我们创建一个从动物类继承的猫类。
子类:猫
package com.Olivia.inheritance;
public class Cat extends Animal{
private String color;
public Cat(boolean veg, String food, int legs) {
super(veg, food, legs);
this.color="白色";
}
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 继承测试程序
让我们编写一个简单的测试类来创建一个猫对象并使用一些它的方法。
package com.Olivia.inheritance;
public class AnimalInheritanceTest {
public static void main(String[] args) {
Cat cat = new Cat(false, "牛奶", 4, "黑色");
System.out.println("猫是素食动物吗?" + cat.isVegetarian());
System.out.println("猫吃 " + cat.getEats());
System.out.println("猫有 " + cat.getNoOfLegs() + " 条腿。");
System.out.println("猫的颜色是 " + cat.getColor());
}
}
结果:

猫的类没有getEats()方法,但程序仍然可以运行,因为它是从动物类中继承的。
重要的要点
- 代码重用是继承的最重要的优势,因为子类继承了超类的变量和方法。
超类的私有成员对子类来说是不可直接访问的。就像这个例子中,Animal类的变量noOfLegs对Cat类是不可访问的,但可以通过getter和setter方法来间接访问。
只有当超类和子类处于同一个包中时,超类的默认访问成员对子类才可访问。
超类的构造函数不会被子类继承。
如果超类没有默认构造函数,那么子类也需要定义一个显式构造函数。否则会在编译时抛出异常。在这种情况下,子类构造函数中对超类构造函数的调用是强制的,并且应该是子类构造函数中的第一条语句。
Java不支持多继承,一个子类只能继承一个类。Animal类隐式地继承了Object类,而Cat类继承了Animal类,但由于Java继承的传递性,Cat类也继承了Object类。
我们可以创建一个子类的实例,然后将其赋给超类变量,这被称为向上转型。下面是一个简单的向上转型的例子:
Cat c = new Cat(); //子类实例
Animal a = c; //向上转型,因为Cat也是Animal,所以没问题
当将超类的实例赋给子类变量时,这被称为向下转型。我们需要显式将其转换为子类。例如:
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类型
我们可以在子类中重写超类的方法。然而,我们应该始终在重写的方法上注解@Override。编译器将知道我们正在重写一个方法,如果超类方法发生了变化,我们将得到一个编译时错误,而不是在运行时得到不想要的结果。
我们可以使用super关键字调用超类的方法和访问超类的变量。当子类中有同名的变量/方法时,这很方便,但我们想要访问超类的变量/方法。在超类和子类中定义了构造函数,并且我们需要显式调用超类构造函数时,也会使用super关键字。
我们可以使用instanceof指令来检查对象之间的继承关系,让我们通过下面的例子来理解。
Cat c = new Cat();
Dog d = new Dog();
Animal an = c;
boolean flag = c instanceof Cat; //正常情况,返回true
flag = c instanceof Animal; // 返回true,因为c也是一个Animal
flag = an instanceof Cat; //返回true,因为a在运行时是Cat类型
flag = an instanceof Dog; //由于明显原因,返回false。
- 我们不能在Java中扩展最终(final)类。
如果你在代码中不打算使用超类,即你的超类只是用来保留可重用代码的基类,那么你可以将它们保留为抽象类,以避免客户类进行不必要的实例化。这还会限制基类的实例创建。
Java继承视频教程
我最近在YouTube上发布了两个视频,详细解释了继承,并提供了示例程序,你应该在下方观看它们。
点击观看YouTube视频。
您可以从我们的GitHub仓库中查看更多继承的示例。
参考资料:Oracle文档