Java的运行原理

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    在Java中引入了虚拟机的概念即在机器和编译程序之间加入了一层抽象的虚拟的机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。编译程序只需要面向虚拟机生成虚拟机能够理解的代码然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在Java中这种供虚拟机理解的代码叫做字节码(ByteCode)class文件的内容它不面向任何特定的处理器只面向虚拟机。每一种平台的解释器是不同的但是实现的虚拟机是相同的。Java源程序经过编译器编译后变成字节码字节码由虚拟机解释执行虚拟机将每一条要执行的字节码送给解释器解释器将其翻译成特定机器上的机器码然后在特定的机器上运行。

    跨平台

    话说在北京一般都是讲北京话的上海一般都是将上海话广东广东话…
    现有一公文发出要全国执行该当如何——先统一翻译成普通话。各地在将普通话版本翻译成当地的方言。

    这里北京、上海就是不同类型的机器windowslinux…
    编译(javac)就是将公文翻译成普通话的过程而编译出的.class文件就是公文的普通话版本。
    在执行的时候各地的翻译就是jvm负责将.class转换成本地能够理解的方言来执行。

    .java→.class→机器码

    java编译器 (编译) → 虚拟机(解释执行) → 解释器(翻译) → 机器码

    Java虚拟机(JVM)

    Java虚拟机(JVM)是Java Virtual Machine的缩写,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能模拟来实现的。

    Java中类加载器把一个类装入JAVA虚拟机需要经过三个步骤来完成装载、链接、初始化其中链接又分来校验、准备、解析过程

    装载查找和导入.class文件

    链接检查装入.class文件的正确性然后java虚拟机为变量分配内存设置默认值

    初始化把符号引用变成直接引用。。。

    复制代码
    1 public class Main {
    2
    3 private static int size=1;
    4
    5 public static void main(String args[]) {
    6
    7 User u = new User();
    8
    9 u.setName(“李文水”);
    10
    11 u.setPwd(“159”);
    12
    13 String name = u.getName();
    14
    15 String pwd = u.getPwd();
    16
    17 u = null;
    18
    19 }
    20
    21 }
    22
    23 public class User {
    24
    25 private String name;
    26
    27 private String pwd;
    28
    29 public String getName() {
    30
    31 return name;
    32
    33 }
    34
    35 public void setName(String name) {
    36
    37 this.name = name;
    38
    39 }
    40
    41 public String getPwd() {
    42
    43 return pwd;
    44
    45 }
    46
    47 public void setPwd(String pwd) {
    48
    49 this.pwd = pwd;
    50
    51 }
    52
    53 }
    复制代码

    现在假设这两个java源文件已经被编译成了CLASS文件了我们来看看java虚拟机怎么执行的。

    Java虚拟机工作流程

    1.装载

    描叙Java虚拟机装载指定的CLASS文件

    结果形成这个CLASS类的实例对象

    过程java虚拟机使用类装载器定位到相应的CLASS文件然后读取这个CLASS文件一个线性二进制数据流将它传入java虚拟机中。紧接着虚拟机提取其中的类型信息。比如该类的类名方法名变量名修饰符方法的返回类型等等。还有一个重要的东西就是常量池。常量池保存了该类型的所有常量包括直接常量和对其他类型字段方法的符号引用将这些信息保存在一个叫做方法区的地方。最终形成CLASS类的实例这个实例存放在内存的堆区。它成为了java程序与内部数据结构之间的接口程序要访问该类型的信息程序就调用该类型对应的CLASS实例对象的方法。简而言之这个过程就是把一个类型的二进制数据解析为方法区中的内部数据结构并在堆上建立一个CLASS对象的过程。

    示例装载Main类

    Java虚拟机读取Main类的CLASS文件生产对应的java.lang.Class类的实例读取其中的类型信息比如修饰符 privatepublicstatic另外变量 sizenamepwdUserUser即为一个引用共同构成了这个类的常量池。将这些信息保存在方法区

    2.链接

    描述验证准备解析可选

    结果这个类型是正确的。这里不知道该怎么描述

    过程

    1)验证确定类型符合java语言的语义比如final类不能有子类final方法不能被覆盖确保在类型和超类型之间没有不兼容的方法声明比如两个方法拥有同样的名字参数完全相同但返回类型不同。

    2)准备java虚拟机为类变量分配内存设置默认值

    3)解析在类型的常量池中寻找类接口字段和方法的符合引用把这些符号引用替换成直接引用的过程。

    示例 连接Main类

    Java虚拟机为size分配内存并赋默认值0.找到常量池中User类的引用如果User类还没有被装载则装载并且连接该类然后将常量池中对User类的引用替换为直接引用。在此时User类并不会被初始化因为还没有用它。

    3.初始化

    描述初始化一些静态变量

    结果这个类型可以使用了

    过程可能会调用()方法这个方法只能够由java虚拟机调用来初始化该类的静态变量。在调用这个方法前必须确认该类的超类的() 方法已经被调用。

    示例初始化Main类

    Java虚拟机将Main类的静态变量赋值为1.

    4.使用执行该类代码了

    1.User u = new User();存放在内存的堆区

    创建了一个User类实例实际上是通过这个类的CLASS实例实例化的。方法如下

    User u=(User)Class.forName(“User”).newInstance();

    为了方便用C代替Class.forName(“User”)

    2.u.setName(“李文水”); u.setPwd(“159”);

    调用该类的方法为该类的变量赋值Java虚拟机内部调用是这样的通过方法区找到该方法利用CLASS实例的如下方法调用

    c.getMethod(“setName”).invoke(u,“李文水”);

    3.String name = u.getName() String pwd = u.getPwd();

    与第二步类似不同的是将取得的值分别赋给了变量name和pwd。关键是这个值保存在哪里和实例对象一样存放在堆区。这个时候我应该可以看出CLASS实例的作用了它就是起个中间作用将程序中的调用反应到堆区上数据的变化。

    4.u = null;

    这个步骤写出来的目的是了解一下Java虚拟机垃圾回收机制。没有什么实际意义

    Java虚拟机内部会根据一种规则(这个对象是否可以触及)来判断这两个类是否可以回收了具体形式如下

    当执行 u = null;时这条线就被斩断了因此User实例就不可以触及了所以java虚拟机就可以回收这个User实例了

    一步一个脚印方便自己复习欢迎大家指正非常感谢共同进步

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
    标签: Java