Java基础知识20--继承与多态
1.继承
1.1 继承概述
继承可以定义为一个类获取另一个类的属性(方法和字段)的过程。 通过使用继承,可以按层次顺序管理信息。
继承其他属性的类称为子类(派生类,子类),其属性被继承的类称为超类(基类,父类)。
关于继承如下 3 点请记住:
1. 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法, 子类是无法访问,只是拥有。
2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
3. 子类可以用自己的方式实现父类的方法。
java中的继承是单继承,即一个类只有一个父类。
extends是用于继承类属性的关键字。 以下是extends关键字的语法。
class Super { ..... ..... } class Sub extends Super { ..... ..... }
各种类型的继承:
继承的初始化顺序
2、先执行初始化对象中属性,再执行构造方法中的初始化。
基于上面两点,我们就知道实例化一个子类,java程序的执行顺序是:
父类对象属性初始化---->父类对象构造方法---->子类对象属性初始化--->子类对象构造方法
1.2 基础代码示例
以下是演示Java继承的示例。 在此示例中,您可以观察两个类,即Calculation和My_Calculation。
使用extends关键字,My_Calculation继承Calculation类的方法addition()和Subtraction()。
父类:Calculation
/** * @Author lucky * @Date 2022/1/19 10:53 */ public 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); } }
子类:MyCalculation
/** * @Author lucky * @Date 2022/1/19 10:54 */ public class MyCalculation 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; MyCalculation demo = new MyCalculation(); 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
在给定的程序中,当创建一个MyCalculation类的对象时,会在其中创建超类的内容的副本。 这就是为什么,使用子类的对象,您可以访问超类的成员。
如果考虑上述程序,可以实例化下面给出的类。 但是使用超类引用变量,您无法调用方法multiplication() ,它属于子类MyCalculation。
1.3 super关键字
super关键字与this关键字类似。 以下是使用super关键字的方案。
-
如果它们具有相同的名称,它用于differentiate the members超类的成员和子类的成员。
-
它用于从子类invoke the superclass构造函数。
使用案例:
父类:
public class SuperClass { int num = 20; // display method of superclass public void display() { System.out.println("This is the display method of superclass"); } }
子类:
public class SubClass extends SuperClass { int num = 10; // display method of sub class public void display() { System.out.println("This is the display method of subclass"); } public void my_method() { // 01 实例化子类 SubClass sub = new SubClass(); // 02 调用子类的display方法 sub.display(); // 03 调用父类的display方法 super.display(); // 04 打印子类的num值 System.out.println("value of the variable named num in sub class:"+ sub.num); // 05 打印父类的num值 System.out.println("value of the variable named num in super class:"+ super.num); } public static void main(String args[]) { SubClass obj = new SubClass(); 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
2.多态
多态是同一个行为具有多个不同表现形式或形态的能力。
Java之所以引入多态的概念,原因之一是它在类的继承问题上和C++不同,后者允许多继承,这确实给其带来的非常强大的功能,但是复杂的继承关系也给C++开发者带来了更大的麻烦,为了规避风险,Java只允许单继承,派生类与基类间有IS-A的关系(即“猫”is a “动物”)。这样做虽然保证了继承关系的简单明了,但是势必在功能上有很大的限制,所以,Java引入了多态性的概念以弥补这点的不足,此外,抽象类和接口也是解决单继承规定限制的重要手段。同时,多态也是面向对象编程的精髓所在。
2.1 多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
例如父类Animal,子类Cat,Dog。其中Animal可以是类也可以是接口,Cat和Dog是继承或实现Animal的子类。
Animal animal = new Cat();
即声明的是父类,实际指向的是子类的一个对象。
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
2.2 多态的特性与优点
2.2.1 优点
面向接口编程,可以降低程序的耦合性,即调用者不必关心调用的是哪个对象,只需要针对接口编程就可以了,被调用者对于调用者是完全透明的。让你更关注父类能做什么,而不去关心子类是具体怎么做的,你可以随时替换一个子类,也就是随时替换一个具体实现,而不用修改其他.
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
2.2.2 特性
-
对象类型和引用类型之间具有继承(类)/实现(接口)的关系;
-
对象类型不可变,引用类型可变;
-
方法具有多态性,属性不具有多态性;
-
引用类型变量发出的方法调用的到底是哪个类中的方法,必须在程序运行期间才能确定;
-
多态不能调用“只在子类存在但在父类不存在”的方法;
-
2.3 向上转型
理解多态,首先要知道“向上转型”。
我定义了一个子类Cat,它继承了Animal类,那么后者就是前者的父类。
(1)方式1
我可以通过用以下方式实例化一个Cat的对象,这个不难理解。
Cat c = new Cat();
(2)方式2
Animal a = new Cat();
方式2:因为子类是对父类的一个改进和扩充,所以一般子类在功能上较父类更强大,属性较父类更独特, 定义一个父类类型的引用指向一个子类的对象既可以使用子类强大的功能,又可以抽取父类的共性。 所以,父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,父类引用是无法调用的;
当父类中的一个方法只有在父类中定义而在子类中没有重写的情况下,才可以被父类类型的引用调用; 对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法,这就是动态连接。
2.4 多态的典型案例
父类:
public class Father { public void func1(){ System.out.println("I am Father'method func1: AAA"); } //这是父类中的func2()方法,因为下面的子类中重写了该方法,所以在父类类型的引用中调用时,这个方法将不再有效 //取而代之的是将调用子类中重写的func2()方法 public void func2(){ func3(); } public void func3(){ System.out.println("I am Father'method func3: CCC"); } }
子类:
public class Child extends Father{ //func1(int i)是对func1()方法的一个重载,主要不是重写! //由于在父类中没有定义这个方法,所以它不能被父类类型的引用调用, 所以在下面的main方法中father.func1(68)是不对的 public void func1(int i){ System.out.println("DDD"); } //func2()重写了父类Father中的func2()方法 //如果父类类型的引用中调用了func2()方法,那么必然是子类中重写的这个方法 public void func2(){ System.out.println("I am Child'method func1: BBB"); } public static void main(String[] args) { //多态的测试 Father father = new Child(); father.func1();//子类没有重写父类方法,则调用的是父类方法func1 father.func2();//子类重写了父类方法,则调用的是子类方法func2 Father father1 = new Father(); father1.func2(); //father.func1(68); //报错,多态不能调用“只在子类存在但在父类不存在”的方法; } }
控制台输出:
I am Father'method func1: AAA I am Child'method func1: BBB I am Father'method func3: CCC
上面的程序是个很典型的多态的例子。子类Child继承了父类Father,并重载了父类的func1()方法,重写了父类的func2()方法。重载后的func1(int i)和func1()不再是同一个方法,由于父类中没有func1(int i),那么,父类类型的引用father就不能调用func1(int i)方法。而子类重写了func2()方法,那么父类类型的引用father在调用该方法时将会调用子类中重写的func2()。
2.5 多态总结
(1)使用父类类型的引用指向子类的对象;
(2)该引用只能调用父类中定义的方法和变量;
(3)如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)
(4)变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。
参考文献:
https://www.cnblogs.com/ChrisMurphy/p/5054256.html
https://iowiki.com/java/java_inheritance.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)