java基础之反射机制
(一)Class类
要正确使用Java反射机制就得使用java.lang.Class这个类。它是Java反射机制的起源。当一个类被加载以后,Java虚拟机就会自动产生一个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息。
(二)类加载器
在加载阶段,java虚拟机需要完成以下3件事:
a.通过一个类的全限定名来获取定义此类的二进制字节流。
b.将定义类的二进制字节流所代表的静态存储结构转换为方法区的运行时数据结构。
c.在java堆中生成一个代表该类的java.lang.Class对象,作为方法区数据的访问入口。
虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部实现,以便让应用程序自己决定如何去获取所需要的类,实现这个动作的代码块被称为“类加载器”
(三)ClassLoader的类加载机制
对于class文件,ClassLoader将其Load到内存中的CodeSegment,运行环境找到main()方法开始执行。
ClassLoader并非一次性加载,而是在需要的时候加载即:运行期间动态的加载。
指令:-verbose:class 可以观察类的具体加载过程。
注意:static 语句块在加载后只执行一次, 动态语句块(dynamic语句块即格式:{ //代码语句 })每次new新的对象都会执行,等同于构造方法中的语句。
系统提供的类加载器主要有下面3个:
1).启动类加载器(Bootstarp ClassLoader)
这个ClassLoader由JVM自己控制。主要加载JVM自身工作需要的类:将%JAVA_HOME%\lib路径下或-Xbootclasspath参数指定路径下的、能被虚拟机识别的类库(仅按照文件名识别,如:rt.jar,名字不符合的类库不会被加载)加载至虚拟机内存中
启动类加载器无法被Java程序直接引用
2).扩展类加载器(Extension ClassLoader)
该类加载器由sun.misc.Launcher类的静态内部类ExtClassLoader实现。
负责加载java.ext.dirs参数(默认值是%JAVA_HOME%\jre\lib\ext,可由VM参数-Djava.ext.dirs指定)指定路径中的所有类库,开发者可以直接使用扩展类加载器。
3).应用程序类加载器(Application ClassLoader)
该类加载器由sun.misc.Launcher$AppClassLoader实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,也称为系统类加载器。
负责加载用户类路径(Classpath)上所指定的类库,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
注意:上述三个JDK提供的类加载器虽然是父子类加载器关系,但是没有使用继承,而是使用了组合关系。
理解ClassLoader类对象的getParent()方法:获得他的上级类加载器。
4).自定义类加载器
除了系统提供的类加载器之外,开发人员可以通过继承java.lang.ClassLoader类并重写该类的findClass方法的方式实现自己的类加载器
(四)双亲委派模型(保证类只被加载一次)
从JDK1.2开始,java虚拟机规范推荐开发者使用双亲委派模式(ParentsDelegation Model)进行类加载,其加载过程如下:
1).如果一个类加载器收到了类加载请求,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器去完成,每一个层次的加载器都是如此
2).因此所有的类加载请求都会传给顶层的启动类加载器,只有当父加载器反馈自己无法完成该加载请求(该加载器的搜索范围中没有找到对应的类)时,子加载器才会尝试自己去加载。
3).如果连最初发起类加载请求的类加载器也无法完成加载请求时,将会抛出ClassNotFoundException,而不再调用其子类加载器去进行类加载。
(五)反射机制
简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。
注意:使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。