反射与JVM

类的加载机制

Java程序运行需要使用某个类时,如果该类还没有加载到内存中,系统会通过加载、连接、初始化三个步骤来对该类进行初始化。下图为类加载的过程:

  1. ** 类加载:由类加载器完成,类的class文件读入内存后,就会创建一个java.lang.Class象。一旦某个类被载入JVM中 ,同一个类就不会再次被载入。
    2.
    连接:**把类的二进制数据合并到JRE中。
  2. 初始化: JVM负责对类进行初始化,也就是对静态属性进行初始化。在Java类中,对静态属性指定初始值的方式有两种:
  • 声明静态属性时指定初始值;
  • 使用静态初始化块为静态属性指定初始值。

类加载

在这里插入图片描述

  1. 什么是类加载:

将·Java编译过后的·class文件中的二进制代码加载到内存中去,这么一个过程就叫类加载。

  1. 类的生命周期:
    在一个生命周期中加载、连接、初始化都只进行一次,,只有使用可以多次。

在这里插入图片描述

加载

  1. 类的加载器:

在这里插入图片描述
逻辑上他们是继承关系,但实际上是采用组合实现的

  1. 类加载器加载类的来源:
  • 本地文件系统加载的.class文件(我们自己写的),绝大多数的加载都是这里来的。
  • 从iar文件中加载.class文件,这种也是比较常见的
  • 通过网络加载class文件
  • 动态加载一个Java源文件,先编译,后执行加载

不同的类加载器,加载相同的类的时,产生的类的class对象不一定一样的。

  1. 查找并加载类的二进制数据:

加载又分为以下三个步骤:

  • 根据类的全限定名(包名+类名)来获取类的二进制字节流;
  • 将类中的所有静态数据的存储结构都转化到方法区中去,作为程序运行时所需要的数据 结构;
    { 需要注意的:方法区也是堆,方法区中放置更多的是跟类相关的数据。
    哪些数据跟类相关?
    类的代码、静态域/静态属性、静态初始化、静态方法、常量池(字符串常量池) }
  • 在Java堆中生成一个代表这个类java.lang.Class对象,作为对方法区中这些数据的访问入口。

连接

验证
  1. 验证的作用:确保被加载的类的正确性。

验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证阶段大致会完成4个阶段的检验动作:

  • 文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
  • 元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。
  • 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
  • 符号引用验证:确保解析动作能正确执行。

验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

准备

负责给类的静态属性分配内存,并设置默认初始值,基本数据类型都赋值为0,引用类型都赋值为null。

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。对于该阶段有以下几点需要注意:

  1. 这时候进行内存分配的仅包括类变量(static),而不包括实例变量,实例变量会在对象实例化时随着对象一块分配在Java堆中;
  2. 这里所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。

假设一个类变量的定义为:public static int value = 3;

那么变量value在准备阶段过后的初始值为0,而不是3,因为这时候尚未开始执行任何Java方法,而把value赋值为3的putstatic指令是在程序编译后,存放于类构造器()方法之中的,所以把value赋值为3的动作将在初始化阶段才会执行。
这里还需要注意如下几点:

  • 对基本数据类型来说,对于类变量(static)和全局变量,如果不显式地对其赋值而直接使用,则系统会为其赋予默认的零值,而对于局部变量来说,在使用前必须显式地为其赋值,否则编译时不通过。
  • 对于同时被static和final修饰的常量,必须在声明的时候就为其显式地赋值,否则编译时不通过;而只被final修饰的常量则既可以在声明时显式地为其赋值,也可以在类初始化时显式地为其赋值,总之,在使用前必须为其显式地赋值,系统不会为其赋予默认零值。
  • 对于引用数据类型reference来说,如数组引用、对象引用等,如果没有对其进行显式地赋值而直接使用,系统都会为其赋予默认的零值,即null。
  • 如果在数组初始化时没有对数组中的各元素赋值,那么其中的元素将根据对应的数据类型而被赋予默认的零值。
  1. 如果类字段的字段属性表中存在ConstantValue属性,即同时被final和static修饰,那么在准备阶段变量value就会被初始化为ConstValue属性所指定的值。

假设上面的类变量value被定义为: public static final int value = 3;

编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为3。回忆上一篇博文中对象被动引用的第2个例子,便是这种情况。我们可以理解为static final常量在编译期就将其结果放入了调用它的类的常量池中。

初始化

JVM初始化一个类的步骤:

  1. 假如这个类还没有被加载和连接,则程序先加载并连接该类;
  2. 假如该类的直接父类还没有被初始化,则先初始化其直接父类;
  3. 假如类中有初始化语句,则系统依次执行这些初始化语句。

只有当对类的主动使用的时候才会导致类的初始化,类的主动引用包括以下六种:

  1. 创建类的实例,也就是new的方式;
  2. 访问某个类或接口的静态变量,或者对该静态变量赋值;
  3. 调用类的静态方法;
  4. 反射(如class.forName( “com.shengsiyuan.Test” ));
  5. 初始化某个类的子类,则其父类也会被初始化;
  6. Java虚拟机启动时被标明为启动类的类(Java Test),直接使用iava.exe命令来运行某个主类.。

但是类的被动引用不会导致类的初始化,如以下几种情况:

  1. 使用final修饰符的常量调用,不会初始北所在的类;
  2. 通过数组定义类引用,也不会初始化所在的类;
  3. 通过子类引用父类的静态变量,也不会导致子类初始化。

类缓存

使用标准iavaSE版本的类加载器,加载的类,类一日被加载完成,在一定时间范围内是有缓存效果的,但是也不是说就永远都不销毁,当然什么时候销毁,由垃圾回收器脱了算。

如下几种情况下, Java虚拟机将结束类的生命周期:

  • 执行了System.exit()方法;
  • 程序正常执行结束;
  • 程序在执行过程中遇到了异常或错误而异常终止;
  • 由于操作系统出现错误而导致Java虚拟机进程终止。

反射

  • Java的反射技术是java程序的特征之一,它允许运行中的 Java程序对自身进行检查,或者说"自审" ,并能直接操作程序的内部属性。
  • 使用反射可以获得Java类中各个成员的名称并显示出来。简单的说,反射就是让你可以通过名称来得到对象(类、属性 、方法)的技术。
  • 一句话:运行时探究和使用编译时未知的类。

反射机制

就是指的是,在Java中,可以在程序运行时期,动态的加载、探知和使用,在编译期,间,完全无法确定的类。

换句话说: Java在运行期去动态的载入一个只知道“类的全限定名”的类,并且获取其完整的数据结构[运行时数据],还可以参照这个完整的数据结构,我们拥有创建类的实例, 以及访问类的属性,访问类的方法的能力,我们把这种能力,也称之为"自省", “自宙”, " “内省"。

注解

  • 什么是注解?
    JDK1.5以后提供的一种和类、接口,、数组地位平等的一种新的特性。

  • 注解可以应用在以下的这些元素中:
    包,类,属性,方法,形参列表 …

  • 它的作用主要有3个:

  1. 第一个跟comment一样,对元素进行注释,说明;
  2. 第二个作用,跟其他的第三方达成一定的共识,或者达成一定的“约定”,比如: @Override注解就是我们代码跟编译器达成一个共识,由此注解的元素必须是一个重新实现的方法;
  3. 第三个作用,注解的内容可以在程序中被访问到,比如:完成ORM映射。

在这里插入图片描述


参考:
http://www.cnblogs.com/ityouknow/p/5603287.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值