Java 继承
继承可以定义为一个类获取另一个类的属性(方法和字段)的过程。 通过使用继承,信息可以按层次顺序进行管理。
继承其他属性的类称为子类(派生类,子类),继承属性的类称为超类(基类,父类)。
extends 关键字
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
类的继承格式
class 父类 { } class 子类 extends 父类 { }
示例代码
以下是演示 Java 继承的示例。 在此示例中,我们可以观察到两个类,即 Calculation 和 My_Calculation。
My_Calculation 使用extends 关键字继承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); } } 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 class Main { 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); } }
执行程序后,会产生如下结果
The sum of the given numbers:30
The difference between the given numbers:10
The product of the given numbers:200
在给定的程序中,当创建 My_Calculation 类的对象时,会在其中生成父类内容的副本。 这就是为什么使用子类的对象可以访问父类的成员。
父类引用变量可以保存子类对象,但是使用该变量我们只能访问父类的成员,因此要访问两个类的成员,建议始终为子类创建引用变量。
如果你考虑上面的程序,可以实例化下面给出的类。 但是使用父类引用变量(在本例中为 cal)我们不能调用方法 multiplication(),它属于子类 My_Calculation。
Calculation demo = new My_Calculation();
demo.addition(a, b);
demo.Subtraction(a, b);
注意
- 子类从其父类继承所有成员(属性、方法和嵌套类)。 构造函数不是成员,所以不被子类继承,但是可以从子类调用父类的构造函数。
super 关键字
super 关键字与 this 关键字类似。 以下是使用 super 关键字的场景。
如果父类和子类的成员具有相同的名称,可用 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; // 父类的display方法 public void display() { System.out.println("This is the display method of superclass"); } } public class Sub_class extends Super_class { int num = 10; // 子类的 display 方法 public void display() { System.out.println("This is the display method of subclass"); } public void my_method() { // 实例化子类 Sub_class sub = new Sub_class(); // 调用子类的 display() 方法 sub.display(); // 调用父类的 display() 方法 super.display(); // 打印子类的变量 num 的值 System.out.println("value of the variable named num in sub class:"+ sub.num); // 打印父类的变量 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(); } }
执行上面的程序,将得到以下结果
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 关键字来调用父类的参数化构造函数。
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(); } }
执行上面的程序,将得到以下结果
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 IS-A Animal
- Reptile IS-A Animal
- Dog IS-A Mammal
- 因此: Dog IS-A Animal
通过使用 extends 关键字,子类将能够继承父类的所有属性,但父类的私有属性除外。
我们可以通过使用 instanceof
运算符来确保 Mammal 实际上是 Animal。
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 {
}
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); } }
执行上面的程序,将得到以下结果
true
true
true
HAS-A 关系
这些关系主要基于使用情况。 这决定了某个类是否拥有(HAS_A)某事物。 这种关系有助于减少代码的重复性,降低代码的错误。
让我们看一个例子
public class Vehicle{}
public class Speed{}
public class Van extends Vehicle {
private Speed sp;
}
这表明 Van HAS-A Speed。 通过为 Speed 提供一个单独的类,我们不必将属于 speed 的整个代码放在 Van 类中,这使得在多个应用程序中重用 Speed 类成为可能。
在面向对象的特性中,用户不需要关心哪个对象在做真正的工作。 为了实现这一点,Van 类对 Van 类的用户隐藏了实现细节。 所以,基本上发生的情况是用户会要求 Van 类执行某个动作,而 Van 类要么自己完成工作,要么要求另一个类执行动作。
继承类型
在面向对象中各种类型的继承,如下所示。
要记住的一个非常重要的点是 Java 不支持多重继承。 这意味着一个类不能继承多个类。 因此以下是非法的
public class extends Animal, Mammal{}
然而,一个类可以实现一个或多个接口,这帮助 Java 摆脱了多重继承的不可能性。