java基础之继承(二)

上篇我们介绍了java中的构造方法,了解了关键字this和super在继承中所起到的作用,this可以显式调用重载的构造方法,super可以显式的调用父类中的任意可见方法。了解方法重载和重写的区别,知道了关键字final的作用,本篇将以一段代码介绍实例化对象时内存的状态。 如果你能看懂以下代码,那本篇你就不用浪费时间了。

/*这是父类*/
public class Base {
    public Base(){
        print();
    }
    public void print(){
    }
}
//这是子类
public class Child extends Base {
    private int a = 2;
    public void print(){
        System.out.println(a);
    }
}
//main函数
public class Test2 {
    public static void main(String[] args){
        Base b = new Child();
        b.print();
    }
}
输出结果:
0
2

四、new关键字的背后       我们知道在java中所有的方法都是在类中的,包括main方法。所以程序开始做的第一件事情是:加载类,就是将类的信息加载到内存中,一个类的信息主要有:

  • 静态变量
  • 静态初始化代码块
  • 静态方法
  • 实例变量
  • 实例初始化代码块
  • 实例方法
  • 对继承自父类的信息的引用 类的加载过程如下:
  • 首先在内存堆中开辟内存以存放当前类
  • 对类中的属性赋默认初始值(int默认为0,boolean默认为false,引用类型默认为null)
  • 调用构造函数进行对象初始化(首先默认执行super调用父类构造函数)
  • 父类构造函数初始化完成之后回到子类完成子类的显式初始化
  • 最后将该对象赋值给引用对象 下面就介绍一下,Base b = new Child();这条语句,内存的实时状态。 内存主要有栈和堆构成,栈中主要存放局部变量,b这个引用就存放其中,堆中主要存放引用的实际内容

首先将Base加载到堆中的方法区,这就相当于一个模板,以后new对象时候就按照此模板来创建对象,然后将变量名b存放到栈中,

执行new语句,发现Child类并未加载到方法区,于是加载Child类到方法区,然后根据方法区中的Child类的模板new出child类的实例对象,它具有模板中所有信息,

接着执行child对象的构造方法,默认创建父类对象并执行父类的构造方法实现父类初始化,完成之后回到子类实现子类的初始化

最终完成对象的创建,将b引用堆中对象。 以上便是Base b = new Child();背后所做的事情 五、方法调用的细节 如果没有继承的概念,方法的调用就是非常简单的,但是有了继承的概念之后,就需要搞清楚检索方法的过程,jvm是怎么找到我们想要调用的方法的,然后执行的呢?

/*这是父类*/
public class Base {
    private String name = "walker";
    public void sayHello(){
        System.out.println("hello child");
    }
    public void showName(){
        System.out.println("my name is " + this.name);
    }
}
//这是子类
public class Child extends Base {
    public void sayHello(){
        System.out.println("hello child");
    }
}
//调用main函数
public class Test2 {
    public static void main(String[] args){
        Base b = new Child();
        b.sayHello();
        b.showName();
    }
}
输出结果:
hello child
my name is walker

这下我们从b.sayHello()说起,首先查看b的实际类型(发现是child类型),于是从child实例对象中查找此方法,找到了,然后直接执行输出hello child本条语句执行完成,接下来执行b.showName();,依然从child对象中查找,没有找到,于是jvm深入到父类对象中,找到并执行输出结果。 总结下,java中总是从当前对象的实际类型出发搜索方法,子类中没有找到的话就会深入父类中搜索,如果父类中也没有找到就会报错 之后为了改进这种搜索效率,使用了虚方法表,也就是将每个类的所有方法(包含父类的方法引用)存放到一张虚拟表中,每次调用方法时候,查找表以加快效率。 最后我们根据以上所有内容,解析本文刚开始的一段代码。 第一句:Base b = new Child();,加载Base类,创建局部变量b存放栈中,发现child类未加载于是去加载child类,按照以上介绍的加载过程,首先开辟了内存以存放类的内容,将private int a;初始化为0。执行new操作,并调用child类的构造方法,转去调用Base类的构造方法,调用函数print,于是判断出此对象的实际类型是child,在child类中查找print找到并执行输出还未显式初始化的a=0,然后返回Base构造方法中,结束父类构造方法,转回执行child构造方法,结束child构造方法完成属性的显式初始化,a=2,结束本条语句。 第二句:b.print();再次搜索print执行输出2,结束。 本文若有不当之处,还望大神不吝赐教,tk。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏PHP技术

12个非常实用的JavaScript小技巧

在这篇文章中将给大家分享12个有关于JavaScript的小技巧。这些小技巧可能在你的实际工作中或许能帮助你解决一些问题。 使用!!操作符转换布尔值 有时候我们...

3428
来自专栏Brian

Python进阶教程(二)

概述 在上一篇博客中,我们介绍了Python进阶教程(一),还有一些新的技巧没有翻译完,我们下面来继续我们的翻译。 Intermediate Python 中译...

3728
来自专栏菜鸟计划

angularjs filter详解

过滤器(filter)正如其名,作用就是接收一个输入,通过某个规则进行处理,然后返回处理后的结果。 主要用在数据的格式化上,例如获取一个数组中的子集,对数组中的...

3488
来自专栏程序员互动联盟

【答疑解惑】Java中重载和重写的区别

今天群里有网友搞不清楚一个问题: ? 重载和重写属于Java面向对象中多态基础知识点,下面就给大家说说多态。 什么叫做多态? 多态指的是在继承关系中子类继承父类...

2807
来自专栏cnblogs

[我的理解]Javascript的原型与原型链

一、原型与原型链的定义 原型:为其他对象提供共享属性的对象     注:当构造器创建一个对象,为了解决对象的属性引用,该对象会隐式引用构造器的"prototyp...

18410
来自专栏java学习

Java基础总结大全(3)

8、Map集合和Collection集合的区别? 1, Map中一次存储是键值对。 Collection中一次存储是单个元素。 2, Map的存储使用...

32910
来自专栏用户2442861的专栏

c++面试题

delete会调用对象的析构函数,和new对应free只会释放内存,new调用构造函数。malloc与free是C++/C语言的标准库函数,new/delet...

691
来自专栏每日一篇技术文章

Swift3.0 - 类和结构体的区别

结论: 在数据量比较大的排序中,结构体排序的速度比较慢,因为结构体是值类型,排序的时候,需要大量的赋值运算。而对象只需要交换地址即可。

541
来自专栏desperate633

深入理解javascript中的继承机制(3)属性复制对象之间的继承深复制原型继承原型继承与属性复制的混合使用

我们开始换一种思路实现继承,可不可以直接将父对象的属性直接复制给子对象,这样子对象不久也拥有了父对象的属性,相当于继承。

652
来自专栏小樱的经验随笔

记一次拿webshell踩过的坑(如何用PHP编写一个不包含数字和字母的后门)

这一串代码描述是这样子,我们要绕过A-Za-z0-9这些常规数字、字母字符串的传参,将非字母、数字的字符经过各种变换,最后能构造出 a-z 中任意一个字符,并且...

712

扫码关注云+社区