类的初始化和对象实例化
反射机制的目的就是通过类加载获取到字节码文件(运行中的类)的内部数据结构,再对这些获取的信息进行操作,如获取类对象、创建对象实例、获取方法名、调用方法、获取方法参数类型和方法返回类型等。
理解反射前要先了解类的加载及JVM内部的存储机制
类加载时通过 1. 加载
->2.链接 验证(完全性校验)、准备(为静态数据赋予初始值基本数字数据类型为0,boolea型为false,string为null,对象为null)、解析(将符号引用转化为地址引用,为了能够直接在内存中找到数据)
->3.类初始化 执行静态变量、方法并进行赋值
第一个加载过程中:将java文件转换为字节码class文件,在这个转变过程中 将java文件中的信息存到三个区域(堆、栈、方法区)
方法区(特殊的堆): 存放了类结构模板信息 1.代码块 (类的属性、方法、代码) 2.静态变量 3.常量池
堆: 存放了java.lang.class对象,该对象的作用是访问
方法区的数据结构从而操作类的信息
(反射就是完成这个过程),类的成员变量在对象实例化后通过方法区的数据结构信息存在该区,static成员变量则在类加载初始化后就存在该区了
栈: 存放 方法地址、局部变量等,
程序运行内存分析:
比如存在局部变量A a = new A; 过程中在
栈中创建a,通过new创建对象(调用构造器),
堆参照方法区中加载类的数据结构创建了A的对象,并且将A对象的地址赋值给了栈中的a(引用),而堆中的这个对象通过引用访问方法区中的数据信息,如给对象赋值某个字符串常量,就是通过A对象中的引用地址访问方法区中的常量池(对象中基本数据类型可直接赋值,无需引用)。如图高琪类加载机制
反射的作用
1).获取字节码文件信息,类名和方法名
2).获取该类名对应的字节码文件对象
3).获取指定的方法对象
4).创建该字节码文件对象
5).调用方法运行
JDK中有多个classLoader,如下:
类加载机制:
类加载器classloader:负责将类文件加载到内存
类主要是通过ClassLoader及其子类完成加载的,类的层次关系加载顺序如下
1.检查(自下而上):该过程中只要检查到某个classloader已经存在则认为该类已经加载了,保证此类所有classloader只加载一次
bootstraploader
(启动类加载器): 负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,加载jdk core中的核心类由C++实现
|
extension classloader(
标准扩展类加载器): 负责加载java平台中扩展功能的一些jar包,一般在JDK的目录“Java\jre7\lib\ext”目录下
该文件中得了类属于JDK自带引用类,可直接使用,eclipse目录中为JRE Syetem library
|
app classloader(
系统类加载器):负责加载classpath中指定的包,一般加载为用户自己定义的class,
|
other classloader:加载其他类型的class SecureClassLoader URLClassLoader等
各个classloader之间是用过getParent()方法在内存拿到引用对象的相互关联(非继承关系)。
在加载一个类时会先通过getParent()引用查找上级加载器是否加载过们,如果加载过则当前加载器不再加载
String str = "T"
Class c = class.forName(str); 获取类名为T的类对象
Object o = c.newInstace(); 为对象创建实例 //该两句实现了关键字new的加载类、生成实例的作用
Method[] methods = c.getMethods(); 获取类的方法成员
for(Method m:methods){
if(m.getName().equals("方法名")) 核对 m对象中的方法是否存在
m.invoke(o); 调用该方法
}
二、细节补充
(1)对比:forName和getClassLoader();
http://carl-java.iteye.com/blog/978680
class. forName除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。而classLoader只干一件事情,就是将.class文件加载到jvm中(即只链接,不做初始化),不会执行static中的内容,只有在newInstance才会去执行static块。
(2)对比:new 和 newInstance
newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。
newInstance()是实现IOC、反射、面对接口编程 和 依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口
newInstance()是实现IOC、反射、面对接口编程 和 依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口