详解 继承(上)—— 工具的抽象与分层
本篇博文讲解的知识点比较实用,但是,相关知识点太多,所以本人将内容分为上下两册,
那么,本人就不多废话,直接进入主题进行讲解了!
说到“继承”,大家可能都会想到我们日常中对于这个词的定义:将先人的 物品 或 意志 传承给后人,而后人也可以“择优继承”,并在先人的基础上产生 新的物品 或 新的意志。
上面这一段话,并不是为了瞎扯才写出来的,上述的思想就是本人对于JAVA中的“继承”的一种通俗的理解:
将父类的 成员 或 方法 传承给 子类 , 而子类也可以选择自己声明一个同名的成员,或者 一个同名、同返回值、同参数的方法,并在父类的基础上 定义 新的成员 或 新的方法 。
通过这样描述,可能大家会对于继承的优点就有了基本的认识。
那么,现在,本人来总结一下 继承的优点:
继承的优点:
- 提高了代码的复用性
- 提高了代码的维护性
- 让类与类之间产生了关系,是多态的前提
在这里,本人还要提出的一点是:
Object类 是 所有类的基类(即 父类)
这样一来,想必同学们对于这个知识点就有了大致的认识了,那么,现在本人来编写一段代码来实现一下上述的思想:
首先,先在com.mec.about_inheritance.classes包下,来编写一个 Parent.java 文件:
package com.mec.about_inheritance.classes;
public class Parent {
public int parentPublicMember;
private int parentPrivateMember;
protected int parentProtectedMember;
int parentNoneMember;
public Parent() {
parentPublicMember = 1;
parentPrivateMember = 2;
parentProtectedMember = 3;
System.out.println("Parent 无参构造方法");
}
public int parentPublicMethod() {
parentPrivateMethod();
System.out.println("执行Parent 类的 public 构造方法!");
return parentPrivateMember;
}
private void parentPrivateMethod() {
System.out.println("执行Parent 类的 private 构造方法!");
}
protected void parentProtectedMethod() {
System.out.println("执行Parent 类的 protected 构造方法!");
}
void parentNoneMethod() {
System.out.println("执行Parent 类的 无修饰 构造方法!");
}
}
现在,我们在本包(com.mec.about_inheritance.classes)下,来编写它的子类——Child.java :
package com.mec.about_inheritance.classes;
public class Child extends Parent {
public Child() {
this. //这里的代码我们还没敲完就能看到下图现象:
}
}
我们能够观察到:它的父类的所有 无修饰 和 用protected、public修饰词修饰的成员 和 方法,在本类中可以调用!
那么,现在我们创建一个新的包com.mec.about_inheritance.test,在这个包下建立 Parent类 的 包外子类 Son类:
package com.mec.about_inheritance.test;
import com.mec.about_inheritance.classes.Parent;
public class Son extends Parent {
public Son() {
this. //这里的代码我们还没敲完就能看到下图现象:
}
}
我们能够观察到:它的父类的所有 用protected、public修饰词修饰的成员 和 方法,在本类中可以调用!
那么,现在我们创建一个新的包com.mec.about_inheritance.test,在这个包下建立 Parent类 的 包外非子类 Demo类:
package com.mec.about_inheritance.demo;
import com.mec.about_inheritance.classes.Child;
import com.mec.about_inheritance.classes.Parent;
import com.mec.about_inheritance.test.Son;
public class Demo {
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
Son son = new Son();
parent. //这里的代码我们还没敲完就能看到下图现象:
}
}
我们能够观察到:它调用的类的所有 用public修饰词修饰的成员 和 方法,在本类中可以调用!
讲到这里,相信好多同学都已经懵了,毕竟本人也是从学习这个知识点的时期过来的,为了方便同学们对比这几种的区别,本人现在将其总结罗列到一张表中:
权限修饰符 总结:
继承关系 | 继承关系 | 非派生类引用关系 | 非派生类引用关系 | |
---|---|---|---|---|
包内子类 | 包外子类 | 包内其他类 | 包外其他类 | |
public | 能 | 能 | 能 | 能 |
private | 否 | 否 | 否 | 否 |
protected | 能 | 能 | 能 | 否 |
default (或 无修饰) | 能 | 否 | 能 | 否 |
那么,本人现在来介绍下,这些 权限修饰符 的一般使用标准吧:
1.凡是打算为子类继承的成员和方法,用 protected 修饰;
2.不打算被 包外的类 引用的 成员 和 方法 ,不用写任何 权限修饰符 。
我们之前说过,在我们构建一个比较大的JAVA工程时,一般都会用到 “构造方法”。
那么,现在,本人来讲解一下 继承关系 中的 构造方法 :
我们还是通过代码的运行结果来总结结论:
首先,在 com.mec.about_inheritance.constructor 包下建立 Grandfather 类:
package com.mec.about_inheritance.constructor;
public class Grandfather {
public Grandfather() {
System.out.println("执行爷爷构造方法!");
}
}
其次,我们在本包( com.mec.about_inheritance.constructor )下建立Parent 类:
package com.mec.about_inheritance.constructor;
public class Parent extends Grandfather {
public Parent() {
System.out.println("执行爸爸构造方法!");
}
}
然后,我们在本包( com.mec.about_inheritance.constructor )下建立Child 类:
package com.mec.about_inheritance.constructor;
public class Child extends Parent{
public Child() {
System.out.println("执行孩子构造方法!");
}
}
最后,我们建立一个新的包 com.mec.about_inheritance.constructor.test ,并在这个包下建立 Test类:
package com.mec.about_inheritance.constructor.test;
import com.mec.about_inheritance.constructor.Child;
public class Test {
public static void main(String[] args) {
new Child();
}
}
然后,我们来观察下运行结果:
由此,我们可以看出,构造方法 的执行顺序:
有当前类开始,根据继承关系,追溯到祖先类,再从上往下执行构造方法!
但是,本人在之前的博文中说过,若一个类没有定义无参构造方法,则JVM会默认执行一个无参构造方法。但是,在继承这里,正是由于这个原因,会出现一些错误,如下:
我们现在对 Grandfather类 进行如下改变:
package com.mec.about_inheritance.constructor;
public class Grandfather {
private int one;
private int two;
public Grandfather(int one, int two) {
this.one = one;
this.two = two;
System.out.println("执行爷爷构造方法!");
}
public int getOne() {
return one;
}
public void setOne(int one) {
this.one = one;
}
public int getTwo() {
return two;
}
public void setTwo(int two) {
this.two = two;
}
}
但是,就在这时,我们能够发现,Parent类那里竟然出现了错误:
错误提示说:父类Parent 的无参构造方法未定义,Parent类 无参构造方法必须执行另一种 父类 的构造方法。
简单来讲,就是说:因为Grandfather 类没有无参构造方法。要 Parent 执行 另一种 父类构造方法。
其实,Grandfather 类并不是没有构造方法,只是没有无参构造方法!
所以,这里执行 Grandfather 类的双参构造方法!
现在,本人对 Parent类 做如下改变:
package com.mec.about_inheritance.constructor;
public class Parent extends Grandfather {
public Parent() {
super(0, 0);
System.out.println("执行爸爸构造方法!");
}
}
可以看到,现在没有问题了!
由上面的代码展示,我们可以看出继承有如下特点:
继承的特点:
- Java只支持单继承,不支持多继承(即 一个类只能拥有一个父类)
- Java支持 多层继承(继承体系)
但是,虽然这样很方便,继承也是存在着条件的:
- 子类只能继承父类所有非私有的成员(成员方法和成员变量)
- 子类不能继承父类的构造方法,但是可以通过super(待会儿讲)关键字去访问父类构造方法
- 不要为了 部分功能 而去 继承
那么,在本篇博文的末尾,本人要提出的一点是:我们虽然可以用“继承”提高代码的复用性,
但是,“继承”同样存在很大的弊端:
继承的弊端: 使得 类的耦合性增强
这违背了我们的开发原则之一的 —— 高内聚,低耦合
(所谓“耦合”—— 类与类的关系
所谓 “内聚”—— 自己完成某件事情的能力)
相信看到这的同学们,一定对于super(0, 0) 这一行代码十分好奇吧,那么,请观看本人的下半篇博文——《详解 继承(下)—— super关键字 与 多态》