Java 中的继承示例
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 中实现继承。
超类:动物
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 是这里的基类。让我们创建一个继承自 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;
}
}
请注意,我们使用extends
关键字在 java 中实现继承。
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(); //subclass instance Animal a = c; //upcasting, it's fine since Cat is also an Animal
-
当将超类的实例分配给子类变量时,这称为向下转换。我们需要将其显式转换为子类。例如;
Cat c = new Cat(); Animal a = c; Cat c1 = (Cat) a; //explicit casting, works fine because "c" is actually of type Cat
请注意,由于显式转换,即使我们做错了,编译器也不会抱怨。下面是一些
ClassCastException
运行时会抛出异常的情况。Dog d = new Dog(); Animal a = d; Cat c1 = (Cat) a; //ClassCastException at runtime Animal a1 = new Animal(); Cat c2 = (Cat) a1; //ClassCastException because a1 is actually of type Animal at runtime
-
我们可以在子类中重写超类的方法。但是,我们应该始终使用@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 继承视频教程
我最近在 YouTube 上发布了两个视频,通过示例程序详细解释了继承,您应该在下面观看它们。
您可以从我们的GitHub 存储库中查看更多继承示例。
参考:Oracle 文档