上文写到

类的四种主动引用和三种被动引用

下面来说说接口的初始化

接口初始化的时候编译器仍然会给接口生成一个()的类构造器,用来初始化接口中的成员变量,这点在类的初始化上也有做到。真正不同的地方在于第三点,类的初始化执行之前要求父类全部都初始化完成了,但接口的初始化貌似对父接口的初始化不怎么感冒。
也就是说,子接口初始化的时候并不要求其父接口也完成初始化,只有在真正使用到父接口的时候它才会被初始化(比如引用接口上的常量的时候啦)。

下面分解一下一个类的加载全过程:加载->验证->准备->解析->初始化

首先是加载:这一块虚拟机要完成3件事:

1.通过一个类的全限定名来获取定义此类的二进制字节流。

2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

3.在java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口。

关于第一点,很灵活,很多技术都是在这里切入,因为它并没有限定二进制流从哪里来:

从class文件来->一般的文件加载
从zip包中来->加载jar中的类
从网络中来->Applet
……….
相比与加载过程的其他几个阶段,加载阶段可控性最强,因为类的加载器可以用系统的,也可以用自己写的,程序猿可以用自己的方式写加载器来控制字节流的获取。

获取二进制流获取完成后会按照jvm所需的方式保存在方法区中,同时会在java堆中实例化一个java.lang.Class对象与堆中的数据关联起来。

加载完成后就要开始对那些字节流进行检验了(其实很多步骤是跟上面交叉进行的,比如文件格式验证):

检验的目的:确保class文件的字节流信息符合jvm的口味,不会让jvm感到不舒服。假如class文件是由纯粹的java代码编译过来的,自然不会出现类似于数组越界、跳转到不存在的代码块等不健康的问题,因为一旦出现这种现象,编译器就会拒绝编译了。但是,跟之前说的一样,Class文件流不一定是从java源码编译过来的,也可能是从网络或者其他地方过来的,甚至你可以自己用16进制写,假如jvm不对这些数据进行校验的话,可能一些有害的字节流会让jvm完全崩溃。

检验主要经历几个步骤:文件格式验证->元数据验证->字节码验证->符号引用验证

文件格式验证:验证字节流是否符合Class文件格式的规范并 验证其版本是否能被当前的jvm版本所处理。ok没问题后,字节流就可以进入内存的方法区进行保存了。后面的3个校验都是在方法区进行的。

元数据验证:对字节码描述的信息进行语义化分析,保证其描述的内容符合java语言的语法规范。

字节码检验:最复杂,对方法体的内容进行检验,保证其在运行时不会作出什么出格的事来。

符号引用验证:来验证一些引用的真实性与可行性,比如代码里面引了其他类,这里就要去检测一下那些来究竟是否存在;或者说代码中访问了其他类的一些属性,这里就对那些属性的可以访问行进行了检验。(这一步将为后面的解析工作打下基础)

验证阶段很重要,但也不是必要的,假如说一些代码被反复使用并验证过可靠性了,实施阶段就可以尝试用-Xverify:none参数来关闭大部分的类验证措施,以简短类加载时间。

接着就上面步骤完成后,就会进入准备阶段了:

这阶段会为类变量(指那些静态变量)分配内存并设置类比那辆初始值的阶段,这些内存在方法区中进行分配。这里要说明一下,这一步只会给那些静态变量设置一个初始的值,而那些实例变量是在实例化对象时进行分配的。这里的给类变量设初始值跟类变量的赋值有点不同,比如下面:

public static int value=123;
在这一阶段,value的值将会是0,而不是123,因为这个时候还没开始执行任何java代码,123还是不可见的,而我们所看到的把123赋值给value的putstatic指令是程序被编译后存在于(),所以,给value赋值为123是在初始化的时候才会执行的。

这里也有个例外:

public static final int value=123;
这里在准备阶段value的值就会初始化为123了。这个是说,在编译期,javac会为这个特殊的value生成一个ConstantValue属性,并在准备阶段jm就会根据这个ConstantValue的值来为value赋值了。

完成上步后,就要进行解析了。解析好像是对类的字段,方法等东西进行转换,具体涉及到Class文件的格式内容,并没深入去了解。

初始化过程是类加载过程的最后一步:

在前面的类加载过程中,除了在加载阶段用户可以通过自定义类加载器参与之外,其他的动作完全有jvm主导,到了初始化这块,才开始真正执行java里面的代码。

这一步将会执行一些预操作,注意区分在准备阶段,已经为类变量执行过一次系统赋值了。

其实说白了,这一步就是执行程序的();方法的过程。下面我们来研究一下()方法:

()方法叫做类构造器方法,有编译器自动手机类中的所有类变量的赋值动作和静态语句块中的语句合并而成的,置于他们的顺序与在源文件中排列的一样。

();方法与类构造方法不一样,他不需要显示得调用父类的();方法,虚拟机会保证子类的();方法在执行前父类的这个方法已经执行完毕了,也就是说,虚拟机中第一个被执行的();方法肯定是java.lang.Object类的。

下面来个例子说明一下:

static class Parent{ public static int A=1; static{ A=2; }
}
static class Sub extends Parent{ public static int B=A;
}
public static void main(String[] args){ System.out.println(Sub.B);
}

首先Sub.B中对静态数据进行了引用,Sub类要进行初始化了。同时,其父类Parent要先进行初始化动作。Parent初始化后,A=2,所以B=2;上个过程相当于:

static class Parent{ <clinit>(){ public static int A=1; static{ A=2; } }
}
static class Sub extends Parent{ <clinit>(){ //jvm会先让父类的该方法执行完在执行这里 public static int B=A; }
}
public static void main(String[] args){ System.out.println(Sub.B);
}

();方法对类跟接口来说不是必须的,加入类或者接口中没有对类变量进行赋值且没有静态代码块,()方法就不会被编译器生成。
由于接口里面不能存在static{}这种静态代码块,但仍然可能存在变量初始化时的变量赋值操作,所以接口里面也会生成()构造器。但跟类的不同的是,执行子接口的()方法前并不需要执行父接口的()方法,当父接口中定义的变量被使用时,父接口才会被初始化。

另外,接口的实现类在初始化的时候也一样不会执行接口的()方法。

另外,jvm会保证一个类的()方法在多线程环境下能被正确地加锁同步。<因为初始化只会被执行一次>。

下面用个例子说明一下:

public class DeadLoopClass { static{ if(true){ System.out.println("要被 ["+Thread.currentThread()+"] 初始化了,下面来一个无限循环"); while(treu){}   } } public static void main(String[] args) { System.out.println("toplaile"); Runnable run=new Runnable(){ @Override public void run() { // TODO Auto-generated method stub System.out.println("["+Thread.currentThread()+"] 要去实例化那个类了"); DeadLoopClass d=new DeadLoopClass(); System.out.println("["+Thread.currentThread()+"] 完成了那个类的初始化工作"); }}; new Thread(run).start(); new Thread(run).start(); } }

这里面,运行的时候将会看到阻塞现象。


java接口的初始化相关推荐

  1. java 接口初始化_Java类的初始化 | 学步园

    类的初始化时机1.创建类的实例 2.访问类或接口的静态变量(static final常量除外,static final变量可以)3.调用类的静态方法 4.反射(Class.forName(packag ...

  2. java 接口初始化_Java类和接口的初始化

    类的初始化由执行类中静态代码块的初始化和类中声明的静态域的初始化两部分组成 接口的初始化由接口中声明的域(常量)的初始化组成 初始化的时机 类或接口T在以下任意情况发生之前会立即进行初始化:T是一个类 ...

  3. java安全接口调用_步骤3:调用Java接口

    本文档主要介绍了通过调用Java接口生成工作密钥和进行通用数据加解密的操作方法. 整体流程 初始化SDK.具体内容请参见 配置Java接口.具体内容请参见 初始化SDK 使用以下方法初始化SDK.hs ...

  4. Java系列笔记(1) - Java 类加载与初始化

    2019独角兽企业重金招聘Python工程师标准>>> 目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如 ...

  5. jmeter java接口_JMeter接口Java开发五步曲

    想做jmeter接口二次开发但不知道如何入手,要解决这个问题,我们可以分为5个步骤 第一步:了解jmeter处理java请求的流程 第二步:通过实现jmeter中的接口JavaSamplerClien ...

  6. java 接口 安全加密_Java中的安全加密

    java 接口 安全加密 上一次我写关于密码学的文章时 ,我概述了Apache Shiro加密API,并展示了如何使用其两个对称密码. 我还写道:"您不需要在应用程序中加密和解密敏感数据的更 ...

  7. Java接口与类之间继承,多态的练习,文字游戏,

    Java接口与类之间继承,多态的练习例题,文字游戏, 问题描述: 一.定义两个接口: public interface Assaultable可攻击的, 接口有一个抽象方法public abstrac ...

  8. jni 调用java接口_JNI 调用 JAVA 接口

    JNI 调用 JAVA 接口 介绍 JNI 是本地语言编程接口.它允许运行在JVM中的Java代码和用C.C++或汇编写的本地代码相互操作. 由于一些加密等情况的需要,需要在 so 层获取一些信息用于 ...

  9. java byte数组 初始化_Java根据byte数组,生成文件

    根据byte数组,生成文件 自己写的小案例,找个地方记录一下 package com.seesun2012.utils; import java.io.BufferedOutputStream; im ...

最新文章

  1. 【Smart_Point】C/C++ 中智能指针
  2. Java学习笔记-包装类
  3. Filter与Servlet区别
  4. 终极Java日志字典:开发人员最常记录的单词是什么?
  5. Go Concurrency Patterns: Context
  6. 微信开发 ---- 设置服务器配置
  7. G - Ordering Tasks(拓补排序)
  8. Python线程池(thread pool)创建及使用+实例代码
  9. Appscan的下载安装
  10. 电力载波通信了解笔记
  11. Darklabel多目标跟踪标注工具
  12. jeffery0207博客导航
  13. vue中prop验证、类型检查及注意事项
  14. react 打电话+阻止冒泡
  15. 【★】生成树算法终极解析!
  16. 【软件工程】------软件开发
  17. Web 开发学习笔记——关于互联网和互联网应用
  18. 2022-09-15 mysql列存储引擎-语法树转换
  19. cv2,PIL,plt,tensorflow方法图片显示及plt的的plt.colorbar()的使用需要注意
  20. 详解软件无线电(SDR)架构

热门文章

  1. Shell编程---------初学者入门
  2. SpringBoot入门教程(转)
  3. 用单层感知器完成逻辑或运算的学习过程
  4. dedecms织梦后台还原备份数据0记录空数据
  5. VS2010 MFC中设置HotKey
  6. 郎朗操刀古典音乐融入新科技游戏
  7. xshell 左边的会话管理器不见怎么办?
  8. 数据库多表查询中速度缓慢的解决办法
  9. 代码漏洞扫描常见漏洞
  10. 快手直播间数据采集截流软件脚本,实时采集引流精准获取客源【采集脚本+引流技术教程】