java类在jvm中经历的几个阶段以及对象中的属性赋值和方法的执行顺序
2017-07-31 12:08
288 查看
本文基于个人的一些理解做的整理,如果有什么位置有问题,欢迎留言指教。
a) 加载类的实例
b) 加载类的静态变量
c) 加载类的静态方法
d) 实例化一个对象
e) 初始化时先初始化父类
f) 类初始化是类加载过程的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码。初始化阶段是执行类构造器()方法的过程。()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的。
静态属性的访问是基于类直接访问的。不会依附于某个实例,这也是静态代码块在实例化对象的时候只会执行一次的原因,而非静态属性是依附于当前的java对象实例的。
在jvm执行过程中静态资源是在对象初始化之前就完成了内存的分配,但是不同的是静态常量(final)的是在内存分配的同时完成了赋值操作,而静态变量在分配内存的时候并没有赋值。而在是初始化阶段的类初始化时进行赋值操作的。
在java类中属性的代码的执行顺序是从上往下的。并且是静态代码优先于非静态,另外就是子类实例化之前必须要实例化父类。
我们简单的看下上面的两段代码,曾经我一直对这个问题不是很理解,但是现在我感觉自己的思想还是比较清晰了。
介绍下我的理解
出现这种情况的原因是java代码是顺序执行的,在实例一中是先实例化了一个singleTon实例,那这个时候两个值都是默认值也就是0,然后在进行++操作之后都变成了1,但是顺序执行的过程中,count2又被重新赋值了,这个时候就把原有值覆盖掉了。
但是实例二的执行顺序是先进行赋值操作,然后在实例化singleTon对象,那这个时候已经完成了赋值操作了,后续的++是在赋值以后的基础上做的,这个时候也就看到的结果就很容易接受了。
注:想想这种问题很有可能在我们不经意间写错了代码的顺序,然后当代码执行的过程中就会出现一些很意外的现象,这时候我们就会很费劲,现在了解了这个执行顺序以后,就感觉思维清晰了很多了
记录一段代码。上面的代码块中被注释的代码是编译不通过的,再贴一段代码对比。下面代码编译都不通过
我们会发现final修饰的静态常量在声明的时候就必须给定初始值。但是final修饰的类变量并不用,不过类变量只支持构造赋值。这正好符号了静态属性是直接挂到类上的,而非静态属性是挂在实例对象上的。
jvm加载资源的几个阶段
jvm加载一个类需要经过加载、连接、初始、使用和卸载几个阶段。我们介绍下前3个阶段加载
加载是jvm加载二进制字节流转换成运行时数据结构的过程连接
连接又分为三个小阶段,分别是验证、准备和解析验证
验证解决要的事就是验证当前执行代码是否可以被当前jvm正常执行。比如jvm版本导致的问题就出现在这个阶段准备
jvm在准备阶段开始一些内存的分配,并且对一些静态资源进行赋值操作,静态变量在这个阶段会赋给默认值,而静态常量在这个阶段会赋给期望值。解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程初始化
在初始化阶段jvm会做以下几件事a) 加载类的实例
b) 加载类的静态变量
c) 加载类的静态方法
d) 实例化一个对象
e) 初始化时先初始化父类
f) 类初始化是类加载过程的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码。初始化阶段是执行类构造器()方法的过程。()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的。
java类中的方法和属性在jvm中的执行顺序
java属性分为静态属性、和非静态属性。静态属性的访问是基于类直接访问的。不会依附于某个实例,这也是静态代码块在实例化对象的时候只会执行一次的原因,而非静态属性是依附于当前的java对象实例的。
在jvm执行过程中静态资源是在对象初始化之前就完成了内存的分配,但是不同的是静态常量(final)的是在内存分配的同时完成了赋值操作,而静态变量在分配内存的时候并没有赋值。而在是初始化阶段的类初始化时进行赋值操作的。
在java类中属性的代码的执行顺序是从上往下的。并且是静态代码优先于非静态,另外就是子类实例化之前必须要实例化父类。
实例一 package com.example.classes; public class SingleTon { private static SingleTon singleTon = new SingleTon(); public static int count1; public static int count2 = 0; private SingleTon() { count1++; count2++; } public static SingleTon getInstance() { return singleTon; } public static void main(String[] args) { SingleTon singleTon = SingleTon.getInstance(); System.out.println("count1=" + singleTon.count1); System.out.println("count2=" + singleTon.count2); } } count1=1 count2=0
实例二 package com.example.classes; public class SingleTon { public static int count1; public static int count2 = 0; private static SingleTon singleTon = new SingleTon(); private SingleTon() { count1++; count2++; } public static SingleTon getInstance() { return singleTon; } public static void main(String[] args) { SingleTon singleTon = SingleTon.getInstance(); System.out.println("count1=" + singleTon.count1); System.out.println("count2=" + singleTon.count2); } } count1=1 count2=1
我们简单的看下上面的两段代码,曾经我一直对这个问题不是很理解,但是现在我感觉自己的思想还是比较清晰了。
介绍下我的理解
出现这种情况的原因是java代码是顺序执行的,在实例一中是先实例化了一个singleTon实例,那这个时候两个值都是默认值也就是0,然后在进行++操作之后都变成了1,但是顺序执行的过程中,count2又被重新赋值了,这个时候就把原有值覆盖掉了。
但是实例二的执行顺序是先进行赋值操作,然后在实例化singleTon对象,那这个时候已经完成了赋值操作了,后续的++是在赋值以后的基础上做的,这个时候也就看到的结果就很容易接受了。
注:想想这种问题很有可能在我们不经意间写错了代码的顺序,然后当代码执行的过程中就会出现一些很意外的现象,这时候我们就会很费劲,现在了解了这个执行顺序以后,就感觉思维清晰了很多了
public class SimpleField { private final BlockingQueue<Runnable> workQueue; public SimpleField(BlockingQueue<Runnable> workQueue) { this.workQueue = workQueue; } public void set(BlockingQueue<Runnable> workQueue) { // this.workQueue = workQueue; } }
记录一段代码。上面的代码块中被注释的代码是编译不通过的,再贴一段代码对比。下面代码编译都不通过
import java.util.concurrent.BlockingQueue; public class SimpleField { private static final BlockingQueue<Runnable> workQueue; public SimpleField(BlockingQueue<Runnable> workQueue) { this.workQueue = workQueue; } public void set(BlockingQueue<Runnable> workQueue) { this.workQueue = workQueue; } }
我们会发现final修饰的静态常量在声明的时候就必须给定初始值。但是final修饰的类变量并不用,不过类变量只支持构造赋值。这正好符号了静态属性是直接挂到类上的,而非静态属性是挂在实例对象上的。
相关文章推荐
- java.io 流的几个对象以及方法属性的使用
- load 和 initialize 方法的执行顺序以及类和对象的关系
- UITableView的全部属性、方法以及代理方法执行顺序
- load 和 initialize 方法的执行顺序以及类和对象的关系
- 关于java中子类,父类中,静态代码块: staic{},动态代码块:{},构造方法,类属性,对象属性等执行顺序做个总结:
- UITableView的全部属性、方法以及代理方法执行顺序
- Checklists学习日志之UITableView的全部属性、方法以及代理方法执行顺序
- UITableView的全部属性、方法以及代理方法执行顺序,常规的设置技巧
- UITableView的全部属性、方法以及代理方法执行顺序,看过之后肯定有收获---董鑫
- XMLHttpRequest对象的几种状态和几个重要属性以及常用的方法
- UItableview全部属性、方法以及代理方法执行顺序
- javascript面向对象(对象的创建以及属性和方法的添加)
- js赋值改变后原来的东西也改变了,影响了好几个其它使用同一个源数据的原因以及解决方法
- Java类成员变量、普通成员变量、初始化块、构造方法的初始化和执行顺序
- static方法,属性,代码块初始化顺序和执行顺序
- 再学Java 基础(3)类与对象【构造函数以及其执行顺序----经典讲解】重点!!!
- XMLHttpRequest对象三个属性,以及open,send方法
- java类的初始化块/执行顺序,实例化对象数据赋值
- JavaScript对象内联函数的使用,对象内部方法和属性的使用,以及事件冒泡的处理方式
- Server对象有那些属性方法以及怎样使用