zoukankan      html  css  js  c++  java
  • 类加载器深入解析

    类加载

    • 在JAVA代码中,类型(指类的本身比如class、interface、枚举,不代表对象比如new出来的实例)的加载(其中一种为:将已经存在的类class文件从磁盘上加载到内存中)、连接(将类与类关系处理好)与初始化过程(类的静态变量赋值)都是在程序运行期间RUNTIME )完成的。
    • 提供更大的灵活性,增加更多的可能性。

    类的加载、连接与初始化

    • 加载: 查找并加载类的二进制数据
    • 连接
      • 验证:确保被加载的类的正确性
      • 准备: 为类的静态变量分配内存,并将其初始化为默认值
      • 解析:把类中的符号引用转换为直接引用
        注: 调用方法 hello() ,这个方法的地址是0xaab,那么hello就是符号引用,0xaab 就是直接引用。在解析阶段,虚拟机会把所有的类名、方法名、字段名这些符号引用替换为具体的内存地址或偏移量。
    • 初始化:为类的静态变量赋予正确的初始值

    类的使用与卸载

    • 使用 : 类的实例进行调用
    • 卸载 : 类的卸载会在内存中卸载相关的内存空间

    类的加载、连接与初始化

    • Java程序对类的使用方式分为两种
      - 主动使用(七种)
      (1) 创建类的实例
      (2) 访问某个类或接口的静态变量,或者对该静态变量赋值
      (3) 调用类的静态方法
      (4) 反射
      (5) 初始化类的子类
      (6) Java虚拟机启动时被标明为启动类的类
      (7)JDK1.7 开始提供的动态语言支持:
      java.lang.invok.MethodHandle实例的解析结果REWF_getStatic,REF——putStatic
      注:除了上述七种情况,其他使用Java类的方式都被看作为被动使用,都不会导致类的初始化
      • 被动使用
    • 所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用”时才初始化他们
    类的加载

    类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区内,然后在内存中创建一个java.lang.Class对象(规范并未说明Class对象位于哪里,HotSpot虚拟机将其放在了方法区)用来封装类在方法区内的数据结构

    加载.class文件方式
    • 从本地系统中直接加载
    • 通过网络下载.class文件
    • 从zip、jar等归档文件中加载.calss文件
    • 从专有数据库中提取.class文件
    • 将Java源文件动态编译为.class文件 (动态代理 AOP)

    范例一

    class MyTest {
    	public static void main(String[] args) {
    		System.out.println(MyChild.str);
    	}
    
    }
    
    class MyParent {
    		public static String str = "This is MyParent's str";
    		static {
    			  System.out.println("This is MyParet.");
    		}
    }
    	
    class MyChild extends MyParent  {
    		public static String str1 = "This is MyChild's str1";
    		static {
    			  System.out.println("This is MyChild.");
    		}
    }
    

    执行结果

    This is MyParet.
    This is MyParent's str
    

    (1)对于静态变量来说,只有直接定义了该变量的类才会被初始化
    (2)上述代码只有主动使用了父类的静态变量并没有主动使用子类MyChild的静态变量;
    (3)上述讲到Java虚拟机只有对于主动使用接口和类的时候才会初始化他们;
    (4)所以虽然主动调用了MyChild.str 但是由于调用的是父类MyParent的静态变量,所以只会初始化父类MyParent。

    范例二

    class MyTest {
    	public static void main(String[] args) {
    		System.out.println(MyChild.str1);
    	}
    
    }
    
    class MyParent {
    		public static String str = "This is MyParent's str";
    		static {
    			  System.out.println("This is MyParet.");
    		}
    }
    	
    class MyChild extends MyParent  {
    		public static String str1 = "This is MyChild's str1";
    		static {
    			  System.out.println("This is MyChild.");
    		}
    }
    

    执行结果

    This is MyParet.
    This is MyChild.
    This is MyChild's str1
    

    (1)由于调用的是子类的str1,所以子类会被初始化
    (2)上述主动使用第五种方式:初始化一个类的子类,该类也会被初始化,所以MyParent由于子类MyChild被初始化了会先初始化。
    (3)当一个类在初始化时,要求其父类全部都已经初始化完成。

    本篇文章主要是整理学张龙老师的深入理解JVM课程的学习笔记

  • 相关阅读:
    Apache Spark探秘:利用Intellij IDEA构建开发环境
    Scala 安装
    Mac OS Git 安装
    Druid:一个用于大数据实时处理的开源分布式系统
    批量kill Linux环境下的任务
    Xshell如何设置,当连接断开时保留Session,保留原文字
    Superset
    mac连接Windows远程桌面
    IOS应用开发版本控制工具之Versions使用
    “不擅长编码?”-可视化编程插件来解决
  • 原文地址:https://www.cnblogs.com/yantt/p/12851448.html
Copyright © 2011-2022 走看看