深入解析Java对象的初始化过程【看完这篇,你爸爸再也不用担心你不会实例Java 对象了】

这还是从一道Java 的面试题说起。不多说直接看这道面试题:

public class Base{

  private String baseName = "base";

  //构造方法

  public Base(){callName();}

 //对象方法

  public void callName(){

    System. out. println(baseName);

  }

  //静态内部类

static class Sub extends Base{

//静态内部类的字段

  private String baseName = "sub";

  //静态类中的方法,可以发现,是对父类中方法的重写

  public void callName(){

    System. out. println (baseName) ;

  }

}

//程序的入口

  public static void main(String[] args){

    Base b = new Sub();

  }

}

这段程序的输出。

【良言一句:同志们,别小看了这部分代码,接下来慢慢解析从类加载器开到最后的输出这么个漫长的过程JVM他是怎么处理的】

1、我们还是先从类加载开始说起。当这个类被编译通知后,会在相应的目录下生成两个.class 文件。一个是 Base.class,另外一个就是Base$Sub.class。这个时候类加载器将这两个.class  文件加载到内存

2、静态代码块优先执行,因此先执行Sub  类中的代码,Sub类中没有静态代码块

【注意-1】先后顺序,是先子在--->在父类,【注意-2】字段的值是放在构造器中,按代码顺序执行进行初始化操作

3、一切初始化(字节码文件该加载的都加载完成)完毕,进入main方法--看到这里的童鞋们,千万别眨眼,关键的地方上演了--左边Base b,在这里的代码中,等于就是说了一句废话,直接可跳跃,从 new Sub()开始,这个时候会调用Sub类的隐式构造函数。这个隐式构造函数是JVM无偿拱手让给你的。还原Sub  类中的构造函数的本质如下:

 public Sub(){

  super();//始终在构造函数中的第一行,为什么呢?这是因为在一些软件的升级中,要兼容老版本的一些功能,父类即原先的一些初始化信息也要保证被执行到,再执行当前

  baseName = "sub";

}

4、好了,这个时候执行super()这行代码也就是跑到父类中去执行了,这个我们要到父类中的构造方法中来瞧瞧。public Base(){callName();},同样,我们需要需要还原这段代码的本质:

public Base(){

  baseName = "base";//4.1 java里面没有字段的重写,只有方法名的重写,因此这个时候先给父类的字段baseName 分配好内存空间再给baseName 字段进行的赋值   

  callName();//4.2 callName()方法的调用。这里有一个执行细节需要大家注意:当在父类中方法的执行时,执行的原则是:子类有重写,执行子类,子类没有重写,则在执行父类)。这个时候调用的就是子类的callName 方法了,

}

5、子类的callName方法执行,打印输出的是子类的baseName 字段的值,而这个时候子类的构造函数中字段的赋值还未执行,因此这个时候输出的null

6、父类的构造函数执行完毕,这个时候又回到子类当中,从super()的下一行继续执行,这个时候才进行该字段baseName 分配好存储空间,随后赋其值。

这个过程的调用时序图如下所示:

你看,在第四步的时候还未进行初始化,就先打印其字段值,很显然这个时候输出的null。

最后附上其输出结果:

【谢谢观赏,此篇完毕】

时间: 2024-08-01 20:36:48

深入解析Java对象的初始化过程【看完这篇,你爸爸再也不用担心你不会实例Java 对象了】的相关文章

java的反射机制,看完这篇轻松应对高级框架(超详细总结)

导读:很多优秀的高级框架都是通过反射完成的,反射的重要性,由此可见一斑.反射机制可以使得程序更加灵活,只有学习好反射的基础语法,这样才能自己写出优秀的框架.好了一起打卡学习吧,别忘记了素质三连哦! 往期精彩回放:一文搞定Java的输入输出流等常见流 java多线程编程从入门到卓越(超详细总结) 一文搞定Java集合类,你还在为Java集合类而烦恼吗? 文章目录 1.反射机制概述 2.通过反射机制实例化对象 3.反射Field(属性)获取字节码 4.反射Mothod(方法) 5.反射Constru

java中对象的初始化过程

class Parent{ int num = 8;// ->3 Parent(){ //super(); // ->2 //显示初始化 // ->3 //构造代码段 // ->4 show(); // ->5 } {// ->4 System.out.println("Parent constructor code run->"); } public void show(){//被覆盖 System.out.println("num

一道题反映Java的类初始化过程

Java的类初始化过程: 1. 父类的static成员变量,static语句块. 2. 子类的static成员变量,static语句块. 3. 父类的普通成员变量,构造函数. 4. 子类的普通成员变量,构造函数. 注意:如果下面一句话没看懂,没关系,看下面的一个例子就明白了~ 如果子类覆盖了父类的成员函数,该成员函数又在上面过程3中的构造函数中被调用,则此时调用的是子类的那个成员函数,如果成员函数中还含有子类中没有被初始化的普通成员变量,则若是int类型,默认初始化为0,若为对象类型,默认初始化

Java中的初始化过程(转)

原文:http://www.cnblogs.com/mmbo/archive/2009/10/05/1578156.html 1.类成员自动初始化,基本类型总是最先初始化为0(boolean为false,(char)0),对象的引用初始化为null:2.类成员指定初始化,可以在类成员定义或构造器(包括其他方法)中给基本类型和非基本类型对象初始化,但这并不能阻止自动初始化首先进行:3.按类成员定义的顺序决定初始化的顺序:4.静态成员只有在第一次被访问时(class对象首次加载)才会被初始化,此后不

Java常见问题之初始化过程

假设有个名为Dog的类 对于静态字段: 1. 当首次创建类型为Dog的对象时,或者Dog类的静态字段/静态方法首次被访问时,Java解释器会查找类路径,以定位Dog.class文件. 2. 载入Dog.class,此时初始化所有静态字段,如果没有对静态字段进行显示初始化,则默认将所有基本类型字段都设置成标准初值,而引用字段被设置成null. 对于非静态字段: 1. 当创建类型为Dog的对象时,首先将在堆上为该对象分配存储空间,且存储空间会被清零,这就将所有基本类型字段都设置成了标准初值,而引用字

细谈 对象的初始化过程------内存中的实现过程?

今天对于内存的理解 又加深了一步: 对下面代码的理解: class Person { private String name="xiaohong"; private int age=23; private static String country="CN"; { System.out.println(name+" "+age); } public Person(String name,int age) { this.name = name; t

对象的初始化过程

对象的初始化过程: class Person{ private String name; private int age; ...//set,get person(String name,int age){ ... } } ... 例如 Person p = new Person("战士",30);1,因为new用到了Person.class.所以会先找到Person.class文件并加载到内存中. 2,执行该类中的static代码块,如果有的话,给Person. class类进行初始

如何更准确过滤信息?看完本篇你就知道

无论是使用Excel办公,还是浏览器搜寻关键字,都是需要通过条件过滤来实现.今天,手把手教你实现Java web项目--实现多条件过滤功能. 分页查询需求分析:在列表页面中,显示指定条数的数据,通过翻页按钮完成首页/上一页/下一页/尾页的查询数据分析:通过观察,页面上需要显示下面的几个数据:当前页:currentPage页面大小:pageSize总页数:totalPage首页:1上一页:prevPage下一页:nextPage尾页:endPage总条数:totalCount结果集:result

看完这篇你还敢说,不懂Spring中的IoC容器?

一. 什么是IoC 什么是耦合和内聚 耦合指的就是模块之间的依赖关系.模块间的依赖越多,则表示耦合度越高,相应的维护成本就越高.内聚指的是模块内功能之间的联系.模块内功能的联系越紧密,则表示内聚度越高,模块的职责也就越单一.所以在程序开发中应该尽量的降低耦合,提高内聚.也就是设计原则中的开闭原则和单一职责原则. 工厂模式 工厂模式就是用来解决程序间耦合的一种设计模式.可以把所有要创建的对象放在工厂的一个集合里,当需要使用这个对象的时候,直接从工厂里面取出来用就行. 工厂模式的优点: 一个调用者想