【Java基础】-【面向对象】-继承

继承是众多关系中的一种,它与组合都可以实现代码复用的思想,只是其原理截然不同:所谓组合,是指在新的类中持有其他类对象的引用,可以理解为‘我’使用‘你’来达到目的,而继承则是一种更为细致的关系,可以理解为父子关系,继承是面向对象程序设计的核心思想之一,在java中,支持的是单继承。

一个类A继承了另一个类B,B称之为基类(又叫父类),A成为子类,子类A自动拥有父类的所有(成员变量和方法),但这并不表明子类可以看到或随意使用父类的东西。

当你创建一个类的时候,实际上一定会使用到继承,因为,除非你已经指定了继承的父类,否则它一定是继承自Object类,Object类是所有类的直接或间接父类。

继承使用extends关键字实现,例如:

class Parents {
public Parents() {}
}

class Childs extends Parents {
public Childs() {}
}

有一些父类成员对于子类来说是不可见的、不可用的,虽然子类确实已经得到了父类的所有成员,但是如果父类中的成员变量 或者 方法被声明称了private权限,那么它就是对子类不可见的,子类无法使用私有的东西。

在继承的过程当中,子类对象内部其实包含了一个父类对象,在子类对象中使用super关键字可以调用父类对象中的可用成员,我们通过一个内存图来了解这个过程:

public class Test1 {
public static void main(String[] args) {

Childs c = new Childs();
c.setAge(21);
c.setSchools("SCHOOL");
c.getParentsAge();

}
}
class Parents {
int age = 45;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
class Childs extends Parents {
String schools;
public void setSchools(String schools) {
this.schools = schools;
}
public String getSchools() {
return schools;
}
public void getParentsAge() {
System.out.println(super.age);
}
}

如上所示的程序,一个父类有age成员变量,其子类自然也继承了这个变量(实际上这个变量是子类对象内部的父类对象的),同时这个子类对象还有一个自己的成员变量school,从main方法开始我们画内存:

上图中的两块内存分别是栈内存和堆内存,栈内存是专门存放局部变量的,堆内存是用来存放new出来的对象的,堆内存是动态分配内存。

那么根据代码中,我们首先new出来一个Childs对象c,c则是存放在栈中的,其内部存储了对象位于堆中的地址,也就是他指向了堆中的Childs对象。然后由于Childs对象是继承自Parents对象的,所以在实例化Childs对象的同时,实际上已经创建了一个Parents对象位于Childs对象的内部,然后我们为c进行赋值,最后我们在Childs对象的内部使用super关键字获取父类的年龄,结果是21。

到此,你所需要知道的是当创建了一个导出类(子类)的时候,该对象包含了一个基类的对象,这个子对象与你直接使用基类创建一个对象是一样的,唯一的区别就是一个来自内部,后者来自于外部。而基类子对象被包装在导出类对象的内部。

在继承关系中,还有一点需要非常注意的就是继承过程的构造器,java中规定,子类构造器中必须调用基类的构造器,这其实也很容易理解,因为上面我们已经说过,子类对象内部实际上包含着一个基类对象,也就是说,子类实例化的时候必须也要实例化一个基类对象,实例化必然调用对应的构造器!同时,在子类构造器中,写在第一行的(要么不写,系统默认调用基类的无参构造器,如果基类没有无参构造器,则编译出错!)、首先执行的必定是基类构造方法,有父才有子嘛!

我们可以使用super关键字调用父类的构造方法(必须写在第一行),如果子类未显式调用基类构造方法,同时基类没有无参构造方法,则编译出错!

继承关系中还有一个知识点需要特别说明,那就是“重写”(overwrite)的概念,所谓重写,就是子类中可以根据需要对从基类中继承的方法进行重新编写,自己定制内部逻辑。重写方法必须和被重写方法有相同的方法名参数列表返回类型!同时,重写的方法不能有比被重写方法更加严格的访问权限!在涉及到重写的时候,我们通常会使用@Override注解,这个注解可以让你及时纠正把重写不小心写成了重载(overload)。

最后一个概念就是向上转型,这个概念将会在介绍接口的时候更加详细的说明。首先,你要知道什么是向上转型。

继承技术最重要的方面是用来表现新类和基类之间的关系,这种关系可以用“新类是现有类的一种类型”这句话加以概括!所谓向上转型,就是说,既然我们可以将子类看作是基类的一种类型,那么我们就将一个基类引用指向一个子类对象,或者是将一个子类引用转换成一个基类引用。这个过程,导出类转换成基类的过程,在继承图上是向上移动的,因此我们称之为向上转型,如下图所示:

我们仔细理解一下这个转换,从下到上的过程总是一个较为专用类型转换成一个较为通用的类型,因此,这个转换过程总是安全的,可以理解为,子类是基类的一个超集,子类所含有的方法 大于等于 基类中的方法。

特别需要注意的一点:由于我们使用的是基类的引用指向子类的对象,在内存中,虽然我们确实在堆内存中是一个子类实例,但是对外暴露的引用确是一个基类引用,这样的话,实际上,这个引用指向的是子类对象中包含的父类对象,也就是说,这个基类引用是不可以访问子类新增加的成员的(属性和方法)。这些将在多态进行讲解。

最后,关于选择组合和继承关系,一个最清晰的判断办法就是在你的程序中是否需要从新类想基类进行项上转型,如果需要,则继承关系是必要的,如果不需要,则应该好好考虑一下是否真的需要继承。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值