注:原创作品,分享以供交流学习,转载请注明出处。
Java虚拟机(Inside JVM)
类加载器(ClassLoad)或者叫做类装载器
作用:把Class字节码程序加载到内存中
class Singleton
{
public static int counter1;
public static int counter2 = 0;
private static Singleton singleton = new Singleton();
public Singleton() {
counter1++;
counter2++;
}
static //静态代码块
{
}
public static Singleton getInstance()
{
return singleton;
}
}
public class MyTest {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
System.out.println("counter1 = " + singleton.counter1);
System.out.println("counter2 = " + singleton.counter2);
}
}
打印结果:
counter1 = 1
counter2 = 1
package com.supan.classload;
class Singleton
{
private static Singleton singleton = new Singleton();
public static int counter1;
public static int counter2 = 0;//其实counter1的值先是零而后再被初始化为0(静态变量不属于任何一个对象,而是属于这个类)
public Singleton() {
counter1++;
counter2++;
}
public static Singleton getInstance()
{
return singleton;
}
}
public class MyTest {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
System.out.println("counter1 = " + singleton.counter1);
System.out.println("counter2 = " + singleton.counter2);
}
}
打印结果:
counter1 = 1
counter2 = 0
只因为成员变量的定义的顺序不同,出现的结果就不一样,下面一一揭晓:
1,java虚拟机与程序的生命周期
在如下的几种情况下,java虚拟机将结束生命周期
1,执行System.exit()返回0表示正常结束,否则不正常(abnormal,变态,不正常)结束
2,程序正常正常执行结束
3,程序在执行过程中遇到了异常或错误而异常终止。也就是说如果你不用try catch 那么程序
会一层一层的把异常抛到main方法中,到导致jvm的异常结束
4,由于操作系统出现错误而导致java虚拟机终止
2,类的加载、链接于初始化
加载:查找并加载类的二进制数据(可以实现class文件到内存中)
链接:
验证:确保被加载类的正确性。(恶意用于可以手工的生成class文件而不用javac)
准备:为类的静态变量分配内存,并将其初始化为默认值
解析:把类的符号引用转换为直接引用。
初始化:为类的静态变量赋予正确的初始值。
3,,java程序对类的使用方式可分为两种
主动使用
被动使用
所有的java虚拟机实现必须在每个类或接口被java程序“首次主动使用”时才初始化他们
主动使用的六种方法:
1,创建类的实例:new一个实例
2,访问一个类的静态变量
3,调用类的静态方法
4,反射 Class.forName("com.mysql.jdbc.Driver")
5,初始化一个类的子类
6,java虚拟机启动时被表明为启动类的
除了上面的六种情况其余的都是被动使用。都不会导致类的初始化。
4,类的加载
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区
的方法区内,然后再堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构
类的加载方式:
1,从本地系统中直接加载
2,通过网络下载.class文件(用URLClassLoad来加载)
3,从zip.jar等归档文件中加载class文件
4,从专有数据库中提取class文件
5,将java云文件动态编译为class文件
5,类加载的最终产品是位于堆区中的Class对象
Class对象封装了类在方法区内的数据结构,并且向java程序员提供了访问方法
区内的数据结构的接口
6,两种类型的类加载器
1,java虚拟机自带的加载器
根类加载器啊(Bootstrap)用c++写的,无法获得该类
扩展类加载器(Extension)用java写的
系统类加载器(System)又称为应用加载器用java写的
2,用户自定义的类加载器
都是java.lang.ClassLoad的子类
用户可以定义类的加载方式,每一个类的对象都会包含着对定义它的ClassLoad
的引用。如果这个类是由根类加载器来加载的那么这个类的getClassLoad方法返回来
的是null
7,类加载器 并不需要等到某个类被“首次主动使用”时再去加载它,jvm规范
允许类加载器在预料某个类将要被使用时就预先加载它,如果再预先加载的guocheng
中遇到了class文件缺失或存在错误,类加载器必须在程序首次主动使用该类
时报告错误(LinkageError错误)
如果这个类一直没有被程序中东使用,那么累加载器 就不会报告错误。
8,用不同的jdk编译的同一个class文件,是不同的文件,可能会出现LinkedageError
9,类的验证的内容
类文件的结构检查:类文件的结构检查:确保类文件遵从java类文件的固定格
语义检查:确保类本身符合java语言的语法规定
字节码验证:
二进制兼容性的验证
例子:
package com.supan.classload;
public class MyTest {
public static void main(String[] args) throws Exception {
Class classzz = Class.forName("java.lang.String");
System.out.println(classzz.getClassLoader());
c c = new c();
System.out.println(c.getClass().getClassLoader());
}
}
class c
{
}
打印结果:
null
sun.misc.Launcher$AppClassLoader@1372a1a
表示String类是由根类加载器加载的c类是由系统类加载器加载的。