Java 继承是 Java 面向对象编程(OOP)的一个重要概念。继承是一个过程,其中一个类(子类)获得另一个类(父类)的属性(方法和字段)。通过使用继承,信息在一个层次结构中变得易于管理。
继承中的类可以分为两类:
-
子类(Subclass 或 Derived class 或 Child class):继承其他类的属性的类。
-
父类(Superclass 或 Base class 或 Parent class):其属性被继承的类。
Java 继承的必要性
-
代码重用:继承的基本需求是为了重用特性。如果已经定义了一些功能,那么可以轻松地在其他类和包中使用它们。
-
扩展性:继承有助于扩展类的功能。如果有一个带有某些功能的基础类,那么可以通过继承在派生类中扩展它们。
-
方法重写:继承是实现多态性的概念之一,即方法重写。
-
实现抽象:另一个面向对象的概念——抽象也需要继承。
Java 继承的实现
在 Java 中实现(使用)继承使用 extends
关键字。这会将基类的属性(属性或/和方法)继承到派生类。extends
这个词意味着扩展功能,即特征的可扩展性。
继承语法
class Super {
.....
.....
}
class Sub extends Super {
.....
.....
}
Java 继承示例
以下示例展示了 Java 继承。在这个示例中,你可以看到两个类:Calculation
和 My_Calculation
。
使用 extends
关键字,My_Calculation
继承了 Calculation
类的方法 addition()
和 Subtraction()
。
将以下程序复制粘贴到名为 My_Calculation.java
的文件中:
class Calculation {
int z;
public void addition(int x, int y) {
z = x + y;
System.out.println("The sum of the given numbers:" + z);
}
public void Subtraction(int x, int y) {
z = x - y;
System.out.println("The difference between the given numbers:" + z);
}
}
public class My_Calculation extends Calculation {
public void multiplication(int x, int y) {
z = x * y;
System.out.println("The product of the given numbers:" + z);
}
public static void main(String args[]) {
int a = 20, b = 10;
My_Calculation demo = new My_Calculation();
demo.addition(a, b);
demo.Subtraction(a, b);
demo.multiplication(a, b);
}
}
编译并执行上述代码:
javac My_Calculation.java
java My_Calculation
执行程序后,会产生以下结果:
The sum of the given numbers:30
The difference between the given numbers:10
The product of the given numbers:200
在这个程序中,当创建 My_Calculation
类的对象时,基类的内容会被复制到派生类中。这就是为什么可以使用派生类的对象来访问基类的成员。
继承
父类的引用变量可以持有派生类的对象,但是使用该变量只能访问父类的成员,所以为了访问两个类的成员,建议总是创建指向派生类的引用变量。
如果你考虑上面的程序,可以像下面这样实例化类。但是使用父类的引用变量(如这里的 cal
),你不能调用属于派生类 My_Calculation
的方法 multiplication()
。
Calculation demo = new My_Calculation();
demo.addition(a, b);
demo.Subtraction(a, b);
注意:子类继承了父类的所有成员(字段、方法和嵌套类)。构造器不是成员,所以它们不会被子类继承,但是可以通过子类调用父类的构造器。
Java 继承:super
关键字
super
关键字与 this
关键字类似。以下是 super
关键字使用的场景:
区分成员
如果一个类继承了另一个类的属性,并且父类成员与子类成员具有相同的名称,我们可以使用 super
关键字来区分这些变量。
super.variable
super.method();
示例代码
下面的程序展示了 super
关键字的用法。
在给定的程序中,有两个类 Sub_class
和 Super_class
,它们都有一个名为 display()
的方法,但实现不同,并且都有一个名为 num
的变量,但值不同。我们在调用两个类的 display()
方法,并打印两个类中 num
变量的值。这里可以看到我们使用 super
关键字来区分父类和子类的成员。
将此程序复制粘贴到名为 Sub_class.java
的文件中。
class Super_class {
int num = 20;
public void display() {
System.out.println("This is the display method of superclass");
}
}
public class Sub_class extends Super_class {
int num = 10;
public void display() {
System.out.println("This is the display method of subclass");
}
public void my_method() {
Sub_class sub = new Sub_class();
sub.display();
super.display();
System.out.println("value of the variable named num in sub class:" + sub.num);
System.out.println("value of the variable named num in super class:" + super.num);
}
public static void main(String args[]) {
Sub_class obj = new Sub_class();
obj.my_method();
}
}
编译并执行上述代码:
javac Sub_class.java
java Sub_class
执行程序后,你会得到以下结果:
This is the display method of subclass
This is the display method of superclass
value of the variable named num in sub class:10
value of the variable named num in super class:20
调用父类构造器
如果一个类继承了另一个类的属性,子类会自动获得父类的默认构造器。但如果想调用父类的带参数构造器,则需要使用 super
关键字,如下所示:
super(values);
示例代码
下面的程序展示了如何使用 super
关键字来调用父类的带参数构造器。这个程序包含一个父类和一个子类,其中父类包含一个接受整数值的带参数构造器,我们使用 super
关键字来调用父类的带参数构造器。
将以下程序复制粘贴到名为 Subclass.java
的文件中:
class Superclass {
int age;
Superclass(int age) {
this.age = age;
}
public void getAge() {
System.out.println("The value of the variable named age in super class is: " + age);
}
}
public class Subclass extends Superclass {
Subclass(int age) {
super(age);
}
public static void main(String args[]) {
Subclass s = new Subclass(24);
s.getAge();
}
}
编译并执行上述代码:
javac Subclass.java
java Subclass
输出:
The value of the variable named age in super class is: 24
IS-A 关系
IS-A 是一种表示方式:这个对象是那个对象的一种类型。让我们看看 extends
关键字是如何实现继承的。
public class Animal {
}
public class Mammal extends Animal {
}
public class Reptile extends Animal {
}
public class Dog extends Mammal {
}
根据上面的例子,从面向对象的角度来看,以下陈述是正确的:
-
动物(Animal)是哺乳动物(Mammal)类的超类。
-
动物(Animal)是爬行动物(Reptile)类的超类。
-
哺乳动物(Mammal)和爬行动物(Reptile)是动物(Animal)类的子类。
-
狗(Dog)既是哺乳动物(Mammal)也是动物(Animal)类的子类。
现在,如果考虑到 IS-A 关系,我们可以这么说:
-
哺乳动物(Mammal)是一种动物(Animal)。
-
爬行动物(Reptile)是一种动物(Animal)。
-
-
通过使用 instanceof
操作符,我们可以确认哺乳动物确实是动物的一种。
示例
class Animal {
}
class Mammal extends Animal {
}
class Reptile extends Animal {
}
public class Dog extends Mammal {
public static void main(String args[]) {
Animal a = new Animal();
Mammal m = new Mammal();
Dog d = new Dog();
System.out.println(m instanceof Animal);
System.out.println(d instanceof Mammal);
System.out.println(d instanceof Animal);
}
}
输出:
true
true
true
既然我们已经了解了 extends
关键字,让我们看看 implements
关键字是如何用于实现 IS-A 关系的。
通常情况下,implements
关键字用于让类继承接口的属性。类永远不能扩展接口。
示例
public interface Animal {
}
public class Mammal implements Animal {
}
public class Dog extends Mammal {
}
请注意,在实际的类设计中,implements
关键字是用来实现接口的,而不是继承。接口中的方法必须在实现类中提供具体的实现。
Java 继承:instanceof
关键字
instanceof
关键字用于确定一个对象是否属于特定的类或实现了某个接口。这是一个非常有用的工具,可以帮助确定运行时对象的确切类型。下面的示例展示了如何使用 instanceof
关键字来检查 Mammal
是否实际上是一个 Animal
,以及 Dog
是否实际上是一个 Animal
。
interface Animal {}
class Mammal implements Animal {}
public class Dog extends Mammal {
public static void main(String[] args) {
Mammal m = new Mammal();
Dog d = new Dog();
System.out.println(m instanceof Animal);
System.out.println(d instanceof Mammal);
System.out.println(d instanceof Animal);
}
}
HAS-A 关系
HAS-A 关系主要是基于类的使用情况。它决定了一个类是否拥有另一个类的对象。这种关系有助于减少代码重复以及潜在的错误。
下面的示例展示了 Van
类拥有了 Speed
类的一个实例,这意味着 Van
类有一个 Speed
属性。
public class Vehicle {}
public class Speed {}
public class Van extends Vehicle {
private Speed sp;
}
通过将速度相关的逻辑封装在单独的 Speed
类中,我们不需要将所有与速度有关的代码都放在 Van
类内,这使得 Speed
类可以在多个应用中重用。
Java 继承的类型
在 Java 中,主要有三种类型的继承:单一继承、多级继承和层次继承。Java 不支持多重继承或多面继承。
1. 单一继承(Single Inheritance)
单一继承是指只有一个基类和一个派生类的继承。单一(或单层)继承只从一个基类继承数据到一个派生类。
class One {
public void printOne() {
System.out.println("printOne() method of One class.");
}
}
public class Main extends One {
public static void main(String[] args) {
Main obj = new Main();
obj.printOne();
}
}
2. 多级继承(Multilevel Inheritance)
多级继承是指一个基类被派生类继承,而这个派生类又被另一个派生类继承的情况。多级继承涉及到多个基类。
class One {
public void printOne() {
System.out.println("printOne() method of One class.");
}
}
class Two extends One {
public void printTwo() {
System.out.println("printTwo() method of Two class.");
}
}
public class Main extends Two {
public static void main(String[] args) {
Main obj = new Main();
obj.printOne();
obj.printTwo();
}
}
3. 层次继承(Hierarchical Inheritance)
层次继承是指只有一个基类但有多个派生类的情况。
class One {
public void printOne() {
System.out.println("printOne() Method of Class One");
}
}
class Two extends One {
public void printTwo() {
System.out.println("Two() Method of Class Two");
}
}
class Three extends One {
public void printThree() {
System.out.println("printThree() Method of Class Three");
}
}
public class Main {
public static void main(String[] args) {
Two obj1 = new Two();
Three obj2 = new Three();
obj1.printOne();
obj2.printOne();
}
}
注意事项
尽管 Java 不支持多重继承(一个类继承自多个基类),但它允许一个类实现一个或多个接口。这种方式帮助 Java 解决了多重继承的问题。例如:
public class MyClass implements InterfaceOne, InterfaceTwo {
}
在这种情况下,MyClass
可以同时实现 InterfaceOne
和 InterfaceTwo
接口中声明的方法。这种方式使得 Java 能够避免多重继承带来的问题,同时仍然允许一定程度上的“多重行为”通过接口实现。