一、Java程序是如何运行的

2018-03-02  本文已影响0人  四纪

Java中有一个虚拟机的概念,就是在机器和编译程序之间多了一层抽象的虚拟的机器,这个虚拟机在各个平台上都提供给编译程序一个共同的接口(这样就可以跨平台了吧?),编译程序只需要面向虚拟机,生成虚拟机能理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码。这种让虚拟机理解的代码叫字节码

JVM就是Java虚拟机的英文缩写,全名是Java VirtualMachine,它是怎么工作的呢?我们先写一串代码,然后介绍这个代码的运行过程。

public class Main {

    private static int size=1;

    public static void main(String args[]) {

        User u = new User();

        u.setName("Realsky");

        u.setPwd("110");

        String name = u.getName();

        String pwd = u.getPwd();

        u = null;

    }

}

class User {

    private String name;

    private String pwd;

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public String getPwd() {

        return pwd;

    }

    public void setPwd(String pwd) {

        this.pwd = pwd;

    }

}

装载

JVM装载指定的class文件,最终形成这个class类的实例对象。

JVM使用类装载器定位到相应的class文件,然后读取这个class文件(一个线性二进制工作流),把它传给JVM。然后JVM提取其中的类型信息,比如类的类名,方法名,变量名,修饰符,方法的返回类型等等。还要初始化常量池,里面保存了各种类型的所有常量。之后将这些东西放到一个叫方法区的地方,形成class类的实例,这个实例存放在内存的堆区,它成为java程序和内部数据结构之间的接口,程序要访问该类型的信息,就调用该类型对应的class实例对象的方法。

比如:装载Main类,读取Main类的class文件,生成对应的java.lang.Class类的实例,读取其中的类型信息,比如修饰符private,public,static,变量size,name,pwd,User共同构成了这个类的常量池,将这些信息保存在方法区。

连接

验证类,保证这个类是没有错误的。

确定类中类型符合Java语义,比如final类不能有子类,final方法不能被覆盖,等等。之后为类变量分配内存,设置默认值。最终在类型的常量类中寻找类、接口、字段和方法的复合引用替换成直接引用的过程。

比如:连接Main类,JVM为size分配内存,并设默认值0,找到常量池中User类的引用,如果User类还没有装载就装载并连接这个类,然后将常量池中对User类的引用替换为直接引用,这个时候User类还没有初始化,因为还没有用到它。

初始化

初始化一些静态变量,让这个类可以跑起来。

可能会调用()方法(这个方法只能由JVM来调用)来初始化该类的静态变量,调用这个方法之前,要确认超类的()方法已经调用完毕。

比如:初始化Main类,JVM将Main类的静态变量赋值为1.

使用

User u = new User(); 

创建一个User类实例,实际上是通过这个类的class实例实例化的,方法:

User u=(User)Class.forName("User").newInstance();

u.setName("RealSky"); u.setPwd("110");

调用类的方法, 为该类的变量复制。JVM的调用过程是,通过方法区找到这个方法,利用class实例的如下方法调用:

Class.forName("User").getMethod("setName").invoke(u,"RealSky");

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

和上一步类似,区别就是这个赋值给了其他变量,这个变量和实例对象一样,保存在堆区。而我们也发现了,class实例的作用就是起到一个中间作用,将程序中的调用放映到堆区上数据的变化。

u = null;

触发JVM的垃圾回收机制,使用完这个命令,User实例就没有被引用了,JVM就会回收这个实例。

上一篇下一篇

猜你喜欢

热点阅读