JAVA继承大讲解~小码人快来透彻理解封装~老码人回顾学生时期的热血~
目录
一.引子:
假设你要写一个动物管理程序:有猫、狗、鱼……它们都有名字、年龄,都会吃饭、睡觉。
如果给每个动物类都重复写name、age和eat()、sleep(),代码会变得又臭又长,修改一个地方就得改十几个类。
这时候,Java 的继承就能帮我们“偷懒”——把公共部分抽到一个父类里,让子类自动拥有这些属性和方法。
今天我们就来搞懂 Java 继承的方方面面。首先我们先来看什么是继承:
二.什么是继承?
继承 是面向对象三大特性(封装、继承、多态)之一。
简单说,它允许我们定义一个新的类(称为子类或派生类),这个新的类可以直接获取现 有的类(属性和方法)的属性和方法。在设计继承的时候,我们把具有相同逻辑的属性或行为打包,管理,分类。
举个例子,小猫,小狗,鱼,鸭子,这些都是动物,都具有运动的特性,那么我们就可以在动物类中可以添加公共的属性和行为,如姓名和运动,让这些新的类继承动物类。抽象出来,就是子类继承父类后,可以复用父类的属性和方法。子类和父类是"is-a"的关系。
三.为什么要使用继承?
1.代码复用。继承可以实现属性和方法的共享,提高代码的复用性。我们在父类中定义的属性和方法,可以被子类继承过来使用。
2.利于代码的修改。我们只需要在父类中修改代码即可。
3.层次分明,逻辑清晰。通过继承关系,我们可以清楚的观察到各类之间的逻辑关系, 例如:狗是一种动物
四:继承的基本语法
1.extends关键字:在子类中标明父类是谁,例如狗类继承动物类:
class Animal{ public String name; } class Dog extends Animal{//Dog类中虽然没有任何东西,但是直接继承了动物类中的name属性 }2.继承的大原则:就近原则,字段或行为重名时,子类有就访问子类的,子类没有就访 问父类的,如果都没有就报错。
3.注意事项:
(1).子类会将父类中的成员变量和成员方法继承到子类中。
(2).子类继承父类后,必须添加自己的成员变量或成员方法,不然继承没有意义。
(3).当父类和子类有同名的成员变量的时候,会优先访问子类自己的成员变量。在子类 中只能通过super关键字(后面会讲)访问父类继承过来的成员
(4).继承的类叫做子类或派生类,被继承的类叫做父类或基类或超类
(5).当两个类的关系是is a的关系的时候,我们就可以把他设计成继承。
(6).Java中的继承是单继承,即一个类只能继承一个父类,但是一个父类可以被多个类 继承
(7).如果父类中有构造方法,那么子类在构造方法中的第一行必须使用super()方法先调 用父类的构造方法,给父类的属性赋值。
(8).Java中可以多层继承,例如猫咪可以继承猫科动物类,猫科动物类可以继承动物类
public class Animal { String name; public void run() { System.out.println(this.name + " is running"); } } public class Feline extends Animal { } public class Cat extends Feline { }
五.方法的重写
1.为什么需要方法的重写:父类的方法不适合子类,例如鱼也是动物,也可以继承动物 类,但是鱼的运动方式是游泳,而不是跑
2.重写的规则:重写是指在父类和子类中,方法名,返回值,参数列表都相同,用注解 @overread标注。
3.返回值类型也可以是原类型的子类
public class Animal { public String name; public Animal func(){ return null; } } public class Fish extends Animal{ @Override public Fish func(){ return null; } }4.重写的注意事项:
(1).静态的方法不能重写,因为静态的方法属于父类本身,而不是父类的对象。
(2).使用final标记的方法不能重写,final关键字本身就是不能改变的意思。
(3).子类中重写的方法的访问权限必须大于等于父类中的重写的方法。(4).被private修饰的方法不能重写
5.@override的作用:可以辅助我们进行编译检查。如果我们在重写的时候哪里写错 了,@override就会进行报错。例如,还是上面的代码,我们在子类的方法中加入一个 参数:
六.super关键字
当父类和子类中存在相同的属性和方法的时候,我们可以使用super关键字在子类中来访问父类的成员变量和方法。
1.super的三种用法:
(1).调用父类隐藏的成员变量
(2).调用父类中被重写的成员方法
(3).在子类的构造方法中调用父类的成员方法(只能在构造方法的第一行)
补充:子类一定会默认存在一个编译器生成的隐藏的不带参数的super(),如果我们写了 super(),那么编译器将不再默认生成。
2.super()的性质:
(1).直接性:当存在多重继承的时候,super()只能调用当前类直接继承的类的构造方法
(2).限制性:在构造方法中,super()必须放在第一行。
(3).默认性:即使不写super,编译器也会默认在第一行提供super();
(4).依赖对象:super()只能在非静态方法中使用
3.super()在内存中的操作原理:
在创建子类对象的时候,JVM会在堆中分配一块连续的地址空间,存放父类继承下来成员变量和成员方法。super就会在堆中跳过子类的属性,仅访问属于父类的那块内存区域。
七.构造器初始化顺序
发生继承之后,构造器的初始化顺序为:
父类的静态代码块--->子类的静态代码块--->父类的实例代码块--->父类的构造方法--->子类的实例代码块--->子类的构造方法
代码演示如下:父类Animal ,子类Fish
public class Animal { public String name; public Animal(String name) { System.out.println("Animal 中执行了 构造方法...."); this.name = name; } static { System.out.println("Animal 中执行了 静态代码块...."); } { System.out.println("Animal 中执行了 实例代码块...."); } public Animal func(){ return null; } } public class Fish extends Animal{ public Fish(String name) { super(name); System.out.println("Fish 中执行了 构造方法...."); } static { System.out.println("Fish 中执行了静态代码块.... "); } { System.out.println("Fish中执行了实例代码块...."); } @Override public Fish func(){//重写父类的方法 return null; } } public class Test { public static void main(String[] args) { Fish fish = new Fish("彩鳞"); } }运行结果如下:
八.访问控制符对继承的影响
这里我们回顾一下上篇文章中的各个访问控制符的权限:
1.由于子类的访问控制符的权限必须比父类的访问控制符的权限高,所以被private修饰 的类不能被继承。
2.被protected修饰的类可以被跨包继承
3.
private成员不被继承,但子类对象内存中仍然存在,只是无法直接访问
九.final关键字对继承的限制
final的三种用法:
1.修饰变量:被final修饰的变量不能被修改
2.修饰类:被final修饰的类不能被继承3.修饰方法:被final修饰的方法不能被重写
十.. 继承与组合的选择
我们先来了解一下组合:
1.组合的意义:组合是把多个类的对象作为自己的成员变量,拼装在一起,从而复用其 功能。例如:汽车包括车轮,发动机,我们就把发动机和车轮的对象作为一个新的类中 的成员变量。代码演示如下:
public class Engine { void star(){ System.out.println("发动机启动了"); } } public class Wheel { void rotate(){ System.out.println("车轮在旋转"); } } public class Car { Wheel[] wheels = new Wheel[4];//车轮 Engine engine = new Engine();//发动机 Car(){ for (int i = 0; i < 4; i++) { wheels[i] = new Wheel(); } } void drive(){ engine.star(); for(Wheel w : wheels){ w.rotate(); } System.out.println("汽车在行驶"); } } public class Test { public static void main(String[] args) { Car car = new Car(); car.drive(); } }运行结果如下:
我们发现:Car并没有继承轮胎和发动机,他是把这两个类的对象当作自己的部件,这就是组合的核心思想。
下面是组合和继承的对比
维度 继承 组合 关系 子类继承父类,is-a 整体包含部分,has-a 关键字 extends 无 代码复用 自动获得父类的属性和行为 需显式调用被包含对象的方法 耦合度 高(父类改动影响子类) 低(内部改动不影响外部) 灵活性 差(只能单继承) 好(可以创建多个对象)
十一.小结与实战演练
到此为止,我们的继承就介绍完了,各位看官现在可以去使用继承来完成一个实战案例:
1.动物类为父类,让小狗类,鱼类,鸭子类共同继承动物类
2.动物类中有姓名,年龄属性,跑动方法。子类中重写跑动方法。(注意,鸭子即可以跑步, 又可以游泳哦~)
3.父类中使用带参构造,子类在构造方法中使用super()调用父类的构造方法
期待大家在评论区讨论遇到的问题,发布自己的代码哟!
更多推荐






所有评论(0)