java基础之类加载机制(一)

Sun公司设计java语言的目标是让Java程序不必经过修改就可以在各种各样的计算机(包括PC机和工作站)上运行。为了实现这一目标,Sun公司提供了一阵Java虚拟机(Java Virtual Machine,JVM)的机制,其工作原理及流程图为:

这里写图片描述
Java虚拟机是编译和运行Java程序等的各种命令及其运行环境的总称。Java源程序在编译之后生成后缀为“.class”的文件,该文件以字节码(bytecode)的方式进行编码。这种字节码实际上是一种伪代码,它包含各种指令,这些指令基本上是与平台无关的指令。Java虚拟机在字节码文件(及编译生成的后缀为.class的文件)的基础上解释这些字节码,及将这些字节码转行成为本地计算机的机器代码,并交给本地计算机执行。
这样,字节码实际上是一种与平台无关的伪代码,通过Java命令变成在各种平台上的机器代码。这些伪代码最终是在本地计算机平台上运行的,但Java程序就好像是在这些Java命令的基础上运行的,因此这些Java命令的集合好像是采用软件技术实现的一种虚拟计算机。这就是Java虚拟机名称的由来。


java程序需要被执行,还的被加载到内存中,于是一个叫做classloader的东东浮出水面,这就是我们的类加载器。在了解类加载器之前先来看一个程序:
public class Test {

    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance();
        System.out.println(singleton.a);
        System.out.println(singleton.b);
    }
}

class Singleton {
    public static Singleton singleton = new Singleton();
    public static int a;
    public static int b = 0;

    private Singleton() {
        a++;
        b++;
    }

    public static Singleton getInstance() {
        return singleton;
    }
}

请问运行结果是多少呢?是1,1吗?
请看输出:
1
0
我了个去啊,这也太奇怪了,为啥是1,0呢?要想知道结果的有原因,看来是有必要学习一下类的加载机制啦。请看我细细道来:
我们先使用从上往下的方式来分析,因为一般程序运行也是从上往下运行的。首先看这里public static Singleton singleton = new Singleton();这里实例化了一个Singleton 对象,实例化对象肯定的进入他的构造方法,于是我们再看构造方法

private Singleton() {
a++;
b++;
}
这里做a、b都使用了自加运算,于是这段构造方法结束后a=1,b=1这是没有疑义的。然后再回到

public static int a;
public static int b = 0;

代码又运行到上面所示,于是因为a这里没有显示赋值,所以a变成了1,而b这里显示的赋值为0,所以b的值被赋予了0值,到最后我们拿到了a=1,b=0的值。
我在这里有一个疑问,就是为什么a没有显示赋值就不会赋值呢,而b却编程了0,这就得看一下我们的类加载机制了。下面开始进入类加载机制的主题中来。
首先来看一下java虚拟机与程序的生命周期,在一下集中情况下,java虚拟机将结束生命周期:
1.调用System.exit()方法
2.程序遇到异常或者错误而终止
3.程序正常执行完毕
4.由于操作系统出错导致java虚拟机终止


再来看一下一个类被执行之前所经过的过程:
一、加载
查找并加载类的二进制数据
二、连接
连接分为三个阶段,分别是:

  1. 验证:确保被加载的类的正确性
  2. 准备:给类的静态变量分配内存,并将其初始化为默认值
  3. 解析:把类中的符号引用转换为直接引用

三、初始化
为类的静态变量赋予正确的初始值


通过一个类的加载过程我们再来看一下这个程序:

public static int a=3;

就是上面这段代码,他是怎么执行的呢?首先经过加载进内存,然后进入连接阶段,验证这段代码的正确性,然后给静态变量a开辟内存空间,然后再给a初始化默认值,因为int类型的默认值为0,所以a=0,此时再经过第三步的初始化操作,为类的静态变量赋予正确的初始值,此时应该给a赋值了,于是a=3。经过这么一番捣腾,a的值最终被确定为3,过程挺复杂吧。
通过上面这个例子就可以知道为什么第一个程序的结果是1,0了吧?


java程序对类的使用方式分为两种,一种是主动使用,一种是被动使用,所有的java虚拟机必须在每个类被“首次主动使用”的时候才初始化它们。那什么时候去主动使用、是时候是被动使用呢?java中有6中主动使用的方式,其他的都被视为被动使用:

  1. 通过new关键字实例化一个类
  2. 通过反射,如:class.forName
  3. 访问某个类或者接口的静态变量,或者对该静态变量赋值
  4. 初始化一个类的子类
  5. 调用类的静态方法
  6. java虚拟机启动时被表明为启动类的类(包含main方法,在命令窗口使用java xxx)

    除了以上6中情况,其他使用类的方式都被看着被动使用,都不会导致类的初始化


类的加载:类的加载指的是将类的二进制数据加载到内存中,将其放在运行时数据区的方法区内,然后再堆区创建一个java.lang.Class对象,用来封装来的方法区的数据结构
以上就是为甚我们可以通过类名.class类获取class对象的原因

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值