目录
反射问题的引出
Java程序在计算机中部署的三个阶段
反射的主要相关类
反射机制的优缺点
调优
反射常用类—Class
特点
常用方法
获取映射Class类对象的四种方式
类加载的三个阶段
加载阶段 Loading
链接阶段 Linking
验证 Verification
准备 Preparation
解析 Resolution
初始化阶段 Initialization
反射爆破
创建实例
操作属性
操作方法
读取一个下述配置文件中指定的信息,创建对象并且调用方法。
利用除反射之外的技术显然是无法在运行阶段动态加载Dog类并创建Dog实例对象的,但是利用Java的反射机制,就可以实现动态加载的效果,并且可以通过修改配置文件在不带便源码的情况下控制程序(例如将配置文件中的method换成别的方法名称,可以不改变源码而调用对象实例的更换的方法):
public class Reflect_ {public static void main(String[] args) {Properties pro = new Properties();try {pro.load(new FileInputStream("src\\test.properties"));String classPath = pro.getProperty("classPath");String methodName = pro.getProperty("method");//在运行时加载配置文件中Dog类的Class映射类Class> cls = Class.forName(classPath);Object dog = cls.newInstance(); //获得一个Dog的实例对象//获得Dog类的映射Class对象中的方法对象Method method = cls.getMethod(methodName);//调用通过映射创建的Dog实例对象中的hi方法method.invoke(dog);} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}
}
在弄清楚反射机制前,需要先对Java程序的三个部署阶段(编译阶段、加载阶段、运行阶段)进行学习:
与反向相关的类主要有四个:
优点:可以动态的加载使用对象(也是框架底层的核心),使用灵活
缺点:使用反射基本是解释执行,对程序的运行效率有影响
通过下述验证会发现用于反射动态加载类调用方法的效率大不如静态加载类:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class Reflect_02 {public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {tradition();reflection();}//传统方法调用hipublic static void tradition() {Cat cat = new Cat();long start = System.currentTimeMillis(); //获取当前系统的相对时间System.out.println(start);for (int i = 0; i < 900000000; i++) {cat.hi();}long end = System.currentTimeMillis();System.out.println(end-start);}public static void reflection() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {Class> cls = Class.forName("com.shuai.Cat");Cat cat = (Cat)cls.newInstance();Method hi = cls.getMethod("hi");//关闭访问检测,优化反射效率hi.setAccessible(true); //取消反射调用方法时检查long start = System.currentTimeMillis();for (int i = 0; i < 900000000; i++) {hi.invoke(cat);}long end = System.currentTimeMillis();System.out.println(end-start);}
}//静态加载类的tradition方法的运行时间:4ms
//通过反射动态加载类的reflection方法的运行时间:576ms
针对上述反射机制进行调优可以通过设置不进行反射检查,提高反射程序的运行效率:
在通过某个类的Class映射对象cls获得该类的方法或字段对象后,可以设置方法/字段.setAccessble(true);禁用访问安全检查的开关,提高程序的运行效率。
Class> cls = Class.forName(classPath);
cls.toString(); //显示自己是哪个类的Class对象
cls.getClass(); //运行类型
cls.getPackage().getName(); //获得关联类的包信息
cls.getName(); //获得映射类的名称
cls.newInstance(); //通过反射创建映射类的实例对象
cls.getField(字段名); //通过反射获取映射类的字段信息(private字段不能访问到)
field.set(通过反射创建的实例对象,值); //通过反射给对象字段赋值
field.get(通过反射创建的实例对象); //获取映射类的属性的值
cls.getMethod(方法名); //通过反射获得映射类的成员方法信息
method.invoke(通过反射创建的对象); //通过反射访问映射类的方法
clas.getConstructor(类.class,类.class...); //获得映射类的构造方法信息

JVM将类的字节码从不同的数据源(class文件,jar包,网络等)将数据转化为二进制字节流读入内存,并创建一个java.lang.Class对象
确保Class文件的字节流中包含的信息符合当前虚拟机的要求,包括:文件格式验证(是否以魔数0x cafebabe开头)、元数据验证、字节码验证、符号引用验证等。如果项目较大,需要加载的类很多,在此阶段也可以通过 -Xverify:none参数关闭大部分的类的验证机制,缩短虚拟机类加载的时间达到优化效果。
JVM在该阶段会对静态变量进行内存分配和默认初始化(初始化为对应数据类型的默认值),静态变量所使用的内存将在方法区中进行分配。
JVM将常量池内的符号引用替换为直接引用。
编译器按照代码语句在源文件中出现的顺序,依次自动收集类中所有的静态变量的赋值动作和静态代码块中的内容并进行合并生成
通过反射创建实例有两种方式:

