这是我参与更文挑战的第5天,活动详情查看: 更文挑战
类继承
class 了解之后,我们考虑一个问题。如果两个 class,它们的变量和方法基本相同,仅仅是其中一个 class 会有一些自己特有的变量和方法,那么相同的那些变量和方法真的需要在两个 class 里都写一遍么?
比如一个表示学生的 class Student
,它相对于 class Person
只是多了一个分数 score
的成员变量,那还需要像下面这样,把 name
字段也定义一下么?
/**
* 学生
*
* @author 蜗牛
* @from 公众号:蜗牛互联网
*/
public class Student {
/**
* 名字
*/
String name;
/**
* 分数
*/
int score;
}
复制代码
这很明显带来了代码重复使用的问题!那能不能在 Student
中不写重复代码?
Java 里的继承这时候就派上用场了,继承是面向对象编程的一种强大机制,能够让子类继承父类的特征和行为,使得子类对象能够具有父类的实例变量和方法。
子类继承父类,父类派生子类。父类也叫基类,子类也叫派生类。
通常来讲,类的层次划分总是下一层比上一层更具体,并且包含上一层的特征,这样下层的类就能自动享有上层类的特点和性质。继承就是派生类自动地共享基类中成员变量和成员方法的机制。
在 Java 中,通过 extends
关键字实现继承,并且所有的类都是继承于 java.lang.Object
,所以这就是万物皆对象在 Java 里的真实写照。你可能会疑惑,自定义的类并没有 extends
关键字为什么还能继承 Object
呢?这是因为这个类在 java.lang
包里,Java 已经默认支持了。
package cn.java4u.oo;
/**
* 学生
*
* @author 蜗牛
* @from 公众号:蜗牛互联网
*/
public class Student extends Person {
/**
* 分数
*/
int score;
}
复制代码
知道了继承的基础概念后,我们看下继承有啥作用?
首先,继承是能够自动传播代码和重用代码的有力工具。它能在已有类上扩充新类,减少代码的重复冗余,也因为冗余度降低,一致性就得到了增强,从而提升了程序的可维护性。
其次,继承可以清晰体现出类与类之间的层次结构关系,提升了代码的可读性。
另外,继承是单方向的,即派生类可以继承和访问基类成员,但反过来就不行。而且 Java 只允许单一继承,也就是一个派生类不能同时继承多个基类,这和 C++ 是不同的。
在使用继承的时候,还要考虑到基类成员的访问控制权限。可以参考封装那块内容的访问权限控制介绍。
子类实例化过程
特别要说明的是,父类的构造方法是不能被子类继承的,即便它是 public
的。父类的构造方法负责初始化属于它的成员变量,而子类的构造方法只需考虑自己特有的成员变量即可,不必关注父类状况。
package cn.java4u.oo.inherit;
/**
* 定义父类
*
* @author 蜗牛
* @from 公众号:蜗牛互联网
*/
public class Parent {
/**
* 构造方法
*/
public Parent() {
System.out.println("这是父类 Parent 的构造方法");
}
}
package cn.java4u.oo.inherit;
/**
* 定义子类
*
* @author 蜗牛
* @from 公众号:蜗牛互联网
*/
public class Child extends Parent {
/**
* 构造方法
*/
public Child() {
System.out.println("这是子类 Child 的构造方法");
}
}
package cn.java4u.test;
import cn.java4u.oo.inherit.Child;
/**
* @author 蜗牛
* @from 公众号:蜗牛互联网
*/
public class InheritTest {
public static void main(String[] args) {
Child child = new Child();
}
}
复制代码
因此,在实例化子类的对象时,Java 先是执行父类的构造方法,然后执行子类的构造方法。如果父类还有更上级的父类,就会先调用更高父类的构造方法,再逐个依次地将所有继承关系的父类构造方法全部执行。如果父类的构造方法执行失败,则子类的对象也将无法实例化。
上边的代码运行后,会输出:
这是父类 Parent 的构造方法
这是子类 Child 的构造方法
复制代码
this 与 super
如果调用父类构造方法涉及到有参构造方法,可以使用 super
关键字来调用父类构造方法并传递参数。
说的 super
,它还有一个能力,就是父类和子类的成员如果同名了,子类中默认只能访问自己的那个成员,想要访问父类成员,就可以通过 super.成员名
的语法实现。但这有个前提,就是父类的这个成员不能是 private 的。
与 super
相对的关键字是 this
,super
是指向当前对象的父类,而 this
是指向当前对象自己。this
常用来区别成员变量和局部变量,比如下面这段代码,我加了个有参构造方法。
public class Parent {
int a;
/**
* 构造方法
*/
public Parent() {
System.out.println("这是父类 Parent 的构造方法");
}
public Parent(int a) {
this.a = a;
}
}
复制代码