继承
什么是继承
继承是面向对象的第二个特征
继承的定义
- 继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
- 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承可以理解为一个对象从另一个对象获取属性的过程。
- 如果类A是类B的父类,而类B是类C的父类,我们也称C是A的子类,类C是从类A继承而来的。在Java中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类。
(简而言之,java中不支持多继承,但是支持多重继承)
如何实现继承
在java语言中继承使用关键字extends来建立关系。
//从形状类中派生出矩形类
public class Rect extends Shape{
}
//从矩形类中派生出正方形类
public class Square extends Rect{
}
java术语
- 父类,超类: 继承关系中,被继承的类称为超类(SuperClass),也有叫做父类;其他语言中也有叫基类。
- 子类,派生类: 继承关系中,继承的类称为子类,也叫派生类。
Java中继承的特点
- Java只支持单一继承,但可以多层继承(多继承会导致调用的不确定性)
- 子类不能继承父类private属性和方法
- 子类不能继承父类的构造方法,但是可以通过super去访问
- super关键字和子类方法中访问变量
- super代表父类的一个标识,权且当作父类对象一个引用,可以使用该关键字调用父类的非私有属性和非私有方法。
- 当我们直接访问变量时,依据就近原则处理。
先在子类方法的局部范围找,有就使用。
若没有,再在子类的成员范围找,有就使用。
若没有,在父类的成员范围找,有就使用。
何时该使用继承
发现两个类的关系是 IS-A ,一个对象是另一个对象的一个分类。
Object
- Object类是所有Java类的祖先。每个类都使用Object作为超类。所有对象(包括数组)都实现这个类的方法。
- 在不明确给出超类的情况下,Java会自动把Object作为要定义类的超类。
- 可以使用类型为Object的变量指向任意类型的对象。(多态)
- Ojbect中包含所有类都有的方法,比如equals和toString方法。
继承带来的好处
- 继承简化了人们对事物的认识和描述,能清晰体现相关类间的层次结构关系。
- 继承提供了软件复用功能。若类B继承类A,那么建立类B时只需要再描述与基类(类A)不同的少量特征(数据成员和成员方法)即可。这种做法能减小代码和数据的冗余度,大大增加程序的复用性。
- 继承通过增强一致性来减少模块间的接口和界面,大大增加了程序的易维护性。
继承带来的疑问
继承中的构造方法
- 在继承过程中,子类继承了父类的非私有方法和非私有属性,那么构造方法也继承了吗?
在Java中,子类的构造过程中,必须调用其父类的构造函数(super()),是因为有继承关系存在时,子类要把父类的内容继承下来。 - 通过什么手段做到的?
当你new一个子类对象的时候,必须首先要new一个父类的对像出来,(子类构造函数的第一行必须是super()即调用父类的构造函数)这个父类对象位于子类对象的内部,所以说,子类对象比父类对象大,子类对象里面包含了一个父类的对象,这是内存中真实的情况.构造方法是new一个对象的时候,必须要调的方法,这是规定,要new父类对象出来,那么肯定要调用其构造方法,所以:
- 第一个规则
子类的构造过程中,必须调用其父类的构造方法。一个类,如果我们不写构造方法,那么编译器会帮我们加上一个默认的构造方法,所谓默认的构造方法,就是没有
参数的构造方法,但是如果你自己写了构造方法,那么编译器就不会给你添加了,所以有时候当你new一个子类对象的时候,肯定调用了子类的构造方法,但是在子类构造方法中我们并没有显示的调用基类的构造方法,就是没写,如:super();并没有这样写,但是这样就会调用父类没有参数的构造方法,如果父类中没有没有参数的构造方法就会出错。
- 第二个规则:
如果子类的构造方法中没有显示的调用基类构造方法,则系统默认调用基类
无参数的构造方法注意:如果子类的构造方法中既没有显示的调用基类构造方法,而基类中又没有默认无参的构造方法,则编译出错,所以,通常我们需要显示的:super(参数列表),来调用父类有参数的构造函数。
数据初始化顺序:父类成员>父类构造方法>子类成员>子类构造方法
重写
- 在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
- 若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
必须注意,子类方法的访问修饰权限不能严于父类;
重载和重写的区别
- 重写需要方法名,返回值,参数列表完全相同,重载需要方法名相同,参数列表不同,可以有不同的返回值
- 重写访问权限必须大于父类,而重载不做要求。
- 重写发生在子类与父类之间,而重载发生在本类中。
抽象类与抽象方法
- 在面向对象的领域一切都是对象,同时所有的对象都是通过类来描述的,但是并不是所有的类都是来描述对象的。如果一个类没有足够的信息来描述一个具体的对象,而需要其他具体的类来支撑它,那么这样的类我们称它为抽象类。
- 比如new Animal(),我们都知道这个是产生一个动物Animal对象,但是这个Animal具体长成什么样子我们并不知道,它没有一个具体动物的概念,所以他就是一个抽象类,需要一个具体的动物,如狗、猫来对它进行特定的描述,我们才知道它长成啥样。在面向对象领域由于抽象的概念在问题领域没有对应的具体概念,所以**用以表征抽象概念的抽
象类是不能实例化的**。
抽象类使用 abstract 关键字完成
如:
public abstract class Animal{
}
```
java中的抽象方法就是以abstract修饰的方法,这种方法只声明返回的数据类型、方法名称和所需的参数,没有方法体,也就是说抽象方法只需要声明而不需要实现。
如:
publc abstract void eat();
“`
使用抽象类和抽象方法时必须注意
- 抽象方法必须放在抽象类中。
- 抽象类不能用new实例化对象
- 抽象方法必须由子类来进行重写。
- 只要包含一个抽象方法的抽象类,该方法必须要定义成抽象类,不管是否还包含有其他方法。
- 抽象类中可以包含具体的方法,当然也可以不包含抽象方法。
- 子类中的抽象方法不能与父类的抽象方法同名。
- abstract不能与final并列修饰同一个类。(因为用final修饰的类不能被继承,而抽象方法必须被继承才能创建实例,不然这个类就没有存在的意义,所以这二者矛盾)
- abstract 不能与private、static、final或native并列修饰同一个方法。