• Java 类加载


    1. 类加载流程

     

    2. 加载

    类加载过程的第⼀步,主要完成下⾯3件事情:

    (1)通过全类名获取定义此类的⼆进制字节流

    (2)将字节流所代表的静态存储结构转换为方法区的运行时数据结构(本质是C++的instanceKlass作为元数据来描述Java类)

    (3)在内存中⽣成⼀个代表该类的 Class 对象(在堆中,和方法区里的java_mirror对应),作为⽅法区这些数据的访问⼊⼝

    3. 验证

    验证类是否符合 JVM规范,安全性检查

    4. 准备

    为static变量分配空间,设置默认值

    5. 解析

    将常量池中的符号引用解析为直接引用

    public class Load2 {
        public static void main(String[] args) throws ClassNotFoundException, IOException {
        ClassLoader classloader = Load2.class.getClassLoader();
        // loadClass 方法不会导致类C的解析和初始化,由于懒加载,类D还没被用到,这样查看类C加载情况里类D只是一个符号
        Class<?> c = classloader.loadClass("cn.itcast.jvm.t3.load.C");
        // new C(); 会加载且解析且初始化,这样类C的加载情况里D的内存地址都有了
        System.in.read();
      }
    } 
    class C {   D d
    = new D(); }
    class D { }

    6. 初始化

    (1)初始化即调用<cinit>方法,虚拟机会保证该方法执行的线程安全

    补充:<cinit>方法是在类加载过程中执行的,而<init>是在对象实例化执行的

    <cinit>:父类静态变量初始化 > 父类静态代码块 > 子类静态变量初始化 > 子类静态代码块

    <init>:父类变量初始化 > 父类构造代码块 > 父类构造函数 > 子类变量初始化 > 子类构造代码块 > 子类构造函数

    (2)初始化是“懒惰的” (类开始加载的时机没有明确规定,但是初始化时机规定了)

    比如子类访问父类静态变量只有父类初始化,访问final常量(基本类型和字符串)不会初始化,loadClass不会初始化,创建类的数组不会初始化等

     应用:懒加载的单例模式

    class Singleton{
        //volatile关键字禁止指令重排
        private volatile static Singleton instance;
        private Singleton(){}
        public Singleton getInstance(){
            if(instance==null){
                //对.class加锁,获得的是所有类对象的锁
                synchronized (Singleton.class){
                    //双重检查,防止多个线程同时进入第一层检查(因单例模式只允许存在一个对象,故在创建对象之前无引用指向对象,所有线程均可进入第一层检查)
                    //当某一线程获得锁创建一个Singleton对象时,即已有引用指向对象,singleton不为空,从而保证只会创建一个对象
                    //假设没有第二层检查,那么第一个线程创建完对象释放锁后,后面进入对象也会创建对象,会产生多个对象
                    if(instance==null){
                        //singleton=new Singleton语句为非原子性,实际上会执行以下内容:
                        //(1)在堆上开辟空间;(2)属性初始化;(3)引用指向对象
                        //volatile关键字可保证singleton=new Singleton()语句执行顺序为123,引用指向对象时一定有对象了
                    }
                }
            }
            return instance;
        }
    }

    7. 类加载器

    (1)层级关系

     (2)双亲委派

    系统中的 ClassLoader 在协同工作的时候会默认使用双亲委派模型 ;

    即类加载时,首先会委派上级的类加载器的loadClass()方法,因此所有类加载器都会传到顶层启动类加载器,当父类加载器无法处理时,才有自己处理。

    (3)判断两个类完全相同

    包名,类名,类加载器均相同

    8. javap工具分析类结构

    javap -v HelloWorld.class

    9. HSDB工具

    HSDB是一个很强大的JVM运行时状态分析工具,根据线程id或name,可以查找类加载情况,内存地址,常量池内容等

    java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB

    10. 语法糖

    所谓的语法糖 ,其实就是指 java 编译器把 *.java 源码编译为 *.class 字节码的过程中,自动生成和转换的一些代码,主要是为了减轻程序员的负担,算是 java 编译器给我们的一个额外福利(给糖吃嘛)

    (1)默认构造器

    (2)自动拆装箱JDK5

    (3)泛型擦除:java 在编译泛型代码后会执行泛型擦除的动作,即泛型信息在编译为字节码之后就丢失了,实际的类型都当做了 Object 类型来处理(反射可以获得这些信息)

    (4)可变参数:转换为数组

    (5)foreach:转换为普通for循环

  • 相关阅读:
    jQuery UI vs EasyUI
    javascript数组元素的添加、删除与插入以及参数数组的使用
    ExtJS中get、getDom、getCmp、getBody、getDoc使用
    ASP.net 中 OutputCache 指令各个参数的作用
    母版页如何页面部分缓存
    Cache OutputCache ASP.NET缓存
    如何使用 @ OutputCache 指令的 VaryByCustom 属性来缓存不同版本的页面
    页面级缓存@ OutputCache
    存储过程DataGrid分页及注意点
    vs2005中 Global.asax 没有 Global.asax.cs 问题解决
  • 原文地址:https://www.cnblogs.com/Kinghao0319/p/14500756.html
Copyright © 2020-2023  润新知