原文地址:https://blog.csdn.net/qq_36522306/article/details/80582758

前言:

最近研究了深入理解JVM这本书中的知识,对java中各部分执行的顺序有了比较深入的了解。首先我们得了解一下java中init和clinit的区别。

概念:
类型初始化方法<clinit>:JVM通过Classload进行类型加载时,如果在加载时需要进行类型初始化操作时,则会调用类型的初始化方法。类型初始化方法主要是对static变量进行初始化操作,对static域和static代码块初始化的逻辑全部封装在<clinit>方法中。
java.lang.Class.forName(String name, boolean initialize,ClassLoader loader),其中第二个参数就是是否需要初始化。

    Java类型初始化过程中对static变量的初始化操作依赖于static域和static代码块的前后关系,static域与static代码块声明的位置关系会导致java编译器生成<clinit>方法字节码。类型的初始化方法<clinit>只在该类型被加载时才执行,且只执行一次。
    对象实例化方法<init>:Java对象在被创建时,会进行实例化操作。该部分操作封装在<init>方法中,并且子类的<init>方法中会首先对父类<init>方法的调用。Java对象实例化过程中对实例域的初始化赋值操作全部在<init>方法中进行,<init>方法显式的调用父类的<init>方法,实例域的声明以及实例初始化语句块同样的位置关系会影响编译器生成的<init>方法的字节码顺序,<init>方法以构造方法作为结束。

下面引用自:https://blog.csdn.net/u013309870/article/details/72975536

init和clinit区别:

①init和clinit方法执行时机不同

init是对象构造器方法,也就是说在程序执行 new 一个对象调用该对象类的 constructor 方法时才会执行init方法,而clinit是类构造器方法,也就是在jvm进行类加载—–验证—-解析—–初始化,中的初始化阶段jvm会调用clinit方法。


②init和clinit方法执行目的不同

init is the (or one of the) constructor(s) for the instance, and non-static field initialization. 
clinit are the static initialization blocks for the class, and static field initialization. 
上面这两句是Stack Overflow上的解析,很清楚init是instance实例构造器,对非静态变量解析初始化,而clinit是class类构造器对静态变量,静态代码块进行初始化。看看下面的这段程序就很清楚了。


  1. class X {
  2. static Log log = LogFactory.getLog(); // <clinit>
  3. private int x = 1; // <init>
  4. X(){
  5. // <init>
  6. }
  7. static {
  8. // <clinit>
  9. }
  10. }

clinit详解

在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量和其他资源,或者可以从另外一个角度来表达:初始化阶段是执行类构造器<clinit>()方法的过程。


①<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问如下代码


  1. public class Test{
  2. static{
  3. i=0;//给变量赋值可以正常编译通过
  4. System.out.print(i);//这句编译器会提示"非法向前引用"
  5. }
  6. static int i=1;
  7. }

②虚拟机会保证在子类的<clinit>()方法执行之前,父类的<clinit>()方法已经执行完毕。 因此在虚拟机中第一个被执行的<clinit>()方法的类肯定是java.lang.Object。由于父类的<clinit>()方法先执行,也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作,如下代码中,字段B的值将会是2而不是1。


  1. static class Parent{
  2. public static int A=1;
  3. static{
  4. A=2;}
  5. static class Sub extends Parent{
  6. public static int B=A;
  7. }
  8. public static void main(String[]args){
  9. System.out.println(Sub.B);
  10. }
  11. }
  • ③接口中不能使用静态语句块,但仍然有变量初始化的赋值操作,因此接口与类一样都会生成<clinit>()方法。 但接口与类不同的是,执行接口的<clinit>()方法不需要先执行父接口的<clinit>()方法。 只有当父接口中定义的变量使用时,父接口才会初始化。 另外,接口的实现类在初始化时也一样不会执行接口的<clinit>()方法。

注意:接口中的属性都是static final类型的常量,因此在准备阶段就已经初始化话。

				<script>
					(function(){
						function setArticleH(btnReadmore,posi){
							var winH = $(window).height();
							var articleBox = $("div.article_content");
							var artH = articleBox.height();
							if(artH > winH*posi){
								articleBox.css({
									'height':winH*posi+'px',
									'overflow':'hidden'
								})
								btnReadmore.click(function(){
									if(typeof window.localStorage === "object" && typeof window.csdn.anonymousUserLimit === "object"){
										if(!window.csdn.anonymousUserLimit.judgment()){
											window.csdn.anonymousUserLimit.Jumplogin();
											return false;
										}else if(!currentUserName){
											window.csdn.anonymousUserLimit.updata();
										}
									}

									articleBox.removeAttr("style");
									$(this).parent().remove();
								})
							}else{
								btnReadmore.parent().remove();
							}
						}
						var btnReadmore = $("#btn-readmore");
						if(btnReadmore.length>0){
							if(currentUserName){
								setArticleH(btnReadmore,3);
							}else{
								setArticleH(btnReadmore,1.2);
							}
						}
					})()
				</script>
				</article>

java执行顺序之深入理解clinit和init的更多相关文章

  1. 【原创】Junit4详解二:Junit4 Runner以及test case执行顺序和源代码理解

    概要: 前一篇文章我们总体介绍了Junit4的用法以及一些简单的测试.之前我有个疑惑,Junit4怎么把一个test case跑起来的,在test case之前和之后我们能做些什么? Junit4执行 ...

  2. java执行顺序

    本文讨论Java中(静态)变量.(静态)代码块的执行顺序 首先创建3个类: 1.Foo类,用于打印变量 public class Foo { public Foo(String word) { Sys ...

  3. junit4X系列源码--Junit4 Runner以及test case执行顺序和源代码理解

    原文出处:http://www.cnblogs.com/caoyuanzhanlang/p/3534846.html.感谢作者的无私分享. 前一篇文章我们总体介绍了Junit4的用法以及一些简单的测试 ...

  4. 一条sql语句搞定基于mysql的sql执行顺序的基本理解

    对数据库基本操作是每个程序员基本功,如何理解并快速记住sql执行的顺序呢,其实一条复杂的sql就能搞定: SELECT DISTINCT <select_list> FROM <le ...

  5. 关于Unity物理事件的执行顺序的最新理解

    物体A: public class A:{ B b; void FixedUpdate(){ if(input.GetKeyDow(Keycode.I)) { collider.enable=fals ...

  6. 高手总结的CSS执行顺序及其优先权问题汇总

    今天在看一本书时又看到了”CSS优 先权“这个问题,感觉这个问题还是比较重要的,也算是样式的特异性吧,尤其是在面对较多.较深层.较复杂的样式属性时,理解CSS的加权计算方法对于重写 样式属性之类的问题 ...

  7. SQL语句中各个部分的执行顺序(转)

    原文链接:http://www.tuicool.com/articles/fERNv2 写在前面的话:有时不理解SQL语句各个部分执行顺序,导致理解上出现偏差,或者是书写SQL语句时随心所欲,所以有必 ...

  8. ASP.NET Page执行顺序【转】

    一.ASP.NET 母版页和内容页中的事件 母版页和内容页都可以包含控件的事件处理程序.对于控件而言,事件是在本地处理的,即内容页中的控件在内容页中引发事件,母版页中的控件在母版页中引发事件.控件事件 ...

  9. Spring filter和拦截器(Interceptor)的区别和执行顺序

    转载自:http://listenup.iteye.com/blog/1559553 1.Filter过滤器只过滤jsp文件不过滤action请求解决方案 解决办法:在web.xml中将filter的 ...

随机推荐

  1. 快速给一个表插入数据 用bulk_create()

  2. 【2017中国大学生程序设计竞赛 - 网络选拔赛】Friend-Graph

    [链接]http://acm.hdu.edu.cn/showproblem.php?pid=6152 [题意] 有一个队伍,如果队伍里有三个或三个以上的人互相认识 或者队伍里有三个或三个以上的人互相不 ...

  3. DUBBO+Zookeeper在Centos7中本地搭建及小案例

    环境: 1.centos7 2.jdk-7u76-linux-x64.tar.gz 2.tomcat:apache-tomcat-7.0.59.tar.gz 3.zookeeper-3.4.6.tar ...

  4. kubernetes(k8s)Pod污点与容忍

    污点(taints)与容忍(tolerations) 对于nodeAffinity无论是硬策略还是软策略方式,都是调度 pod 到预期节点上,而Taints恰好与之相反,如果一个节点标记为 Taint ...

  5. 奇技淫巧之Delphi和JavaScript互通

    http://www.raysoftware.cn/?p=305 Delphi2010以后增加了新的RTTI信息,也就是通过RTTI可以在运行时获取/调用对象的公开成员或者函数. ScriptCont ...

  6. tp5使用jwt生成token,做api的用户认证

    首先 composer 安装  firebase/php-jwt github:https://github.com/firebase/php-jwt composer require firebas ...

  7. CSS:CSS 尺寸 (Dimension)

    ylbtech-CSS:CSS 尺寸 (Dimension) 1.返回顶部 1. CSS 尺寸 (Dimension) CSS 尺寸 (Dimension) 属性允许你控制元素的高度和宽度.同样,它允 ...

  8. option click事件

    $("#m-s-type").on("change",function(){ var id = $(this).find("option:select ...

  9. 剑指offer——61平衡二叉树

    题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树.   题解: 方法一:使用深度遍历,判断每个节点是不是平衡二叉树,这种从上至下的方法会导致底层的节点重复判断多次 方法二:使用后序遍历判断,这种 ...

  10. 常用命令--sed

    sed -n '/2019-07-24/,/2019-07-25/p' my.log sed -n '/2019-07-25 16:51:23,699/,/2019-07-25 16:51:38,79 ...