朋友,希望能帮助到你
- 1.反射的主要类
- 2.反射调用优化
- 3.Class类分析
- 4.Class常用方法
- 5.获取Class对象的方式
- 6.那些类型有Class对象
- 7.类加载
- 8.类加载阶段
1.反射的主要类
- Java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
- Java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
- Java.lang.reflect.Field:代表类的成员变量,File对象表示某个类的成员变量
- Java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
packagecom.polar;importjava.io.File;importjava.io.FileInputStream;importjava.lang.reflect.Constructor;importjava.lang.reflect.Field;importjava.lang.reflect.Method;importjava.util.Properties;publicclassApplication{@SuppressWarnings({"all"})publicstaticvoidmain(String[]args)throwsException{StringfilePath="src\\re.properties";//File file = new File(filePath);//file.createNewFile();Propertiesproperties=newProperties();properties.load(newFileInputStream(filePath));Stringclassfullpath=properties.get("classfullpath").toString();Stringmethod=properties.get("method").toString();/** * Java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象 * Java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法 * Java.lang.reflect.Field:代表类的成员变量,File对象表示某个类的成员变量 * Java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器 *///ClassClassaClass=Class.forName(classfullpath);Objecto=aClass.newInstance();//MethodMethodmethod1=aClass.getMethod(method);System.out.print("java.lang.reflect.Method调用方法:");method1.invoke(o);//FieldFieldname=aClass.getField("name");System.out.print("java.lang.reflect.Field获取成员变量:");System.out.println(name.get(o));//ConstructorConstructorconstructor=aClass.getConstructor();System.out.print("java.lang.reflect,Constructor获取无参构造器:");System.out.println(constructor);Constructorconstructor1=aClass.getConstructor(String.class);System.out.print("java.lang.reflect.Constructor获取含参构造器:");System.out.println(constructor1);}}2.反射调用优化
- 反射的优点:可以动态创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去可底层支持
- 反射的缺点:使用反射基本是解释执行,对执行速度有影响
代码演示传统方法和反射机制运行速度得差别
packagecom.polar;importjava.lang.reflect.Method;publicclassV{publicstaticvoidmain(String[]args)throwsException{V1();V2();}//传统调用publicstaticvoidV1(){//创建对象Bearbear=newBear();//使用System计时longstart=System.currentTimeMillis();for(inti=0;i<99999;i++){bear.Test();}longend=System.currentTimeMillis();System.out.println("传统方法耗时:"+(end-start));}//反射调用publicstaticvoidV2()throwsException{ClassaClass=Class.forName("com.polar.Bear");Objecto=aClass.newInstance();Methodtest=aClass.getMethod("Test");longstart=System.currentTimeMillis();for(inti=0;i<99999;i++){test.invoke(o);}longend=System.currentTimeMillis();System.out.println("反射方法耗时:"+(end-start));}}运行结果可知反射的确运行速度慢
对反射调用进行优化
- Method、Field、Constructor都可以使用setAccessible进行优化
- setAccessible作用是启动和禁用访问安全的开关
- 当setAccessible方法参数为true时,反射的对象在使用时关闭访问检查提高反射效率
- 当setAccessible方法参数为false时,反射的对象在使用时开启访问检查降低反射效率
代码演示反射优化
packagecom.polar;importjava.lang.reflect.Method;publicclassV{publicstaticvoidmain(String[]args)throwsException{V1();V2();V3();}//传统调用publicstaticvoidV1(){//创建对象Bearbear=newBear();//使用System计时longstart=System.currentTimeMillis();for(inti=0;i<99999;i++){bear.Test();}longend=System.currentTimeMillis();System.out.println("传统方法耗时:"+(end-start));}//反射调用publicstaticvoidV2()throwsException{ClassaClass=Class.forName("com.polar.Bear");Objecto=aClass.newInstance();Methodtest=aClass.getMethod("Test");longstart=System.currentTimeMillis();for(inti=0;i<99999;i++){test.invoke(o);}longend=System.currentTimeMillis();System.out.println("反射方法耗时:"+(end-start));}//反射调用优化publicstaticvoidV3()throwsException{ClassaClass=Class.forName("com.polar.Bear");Objecto=aClass.newInstance();Methodtest=aClass.getMethod("Test");test.setAccessible(true);//在调用方法时,关闭访问检查longstart=System.currentTimeMillis();for(inti=0;i<99999;i++){test.invoke(o);}longend=System.currentTimeMillis();System.out.println("反射优化后耗时:"+(end-start));}}优化后(优化效果。。。。。),但好歹也优化了,对,优化了。。。。。>_<
3.Class类分析
- Class也是类,因此也继承Object类
- Class类对象不是new出来的,而是系统创建的
- 一个Class对象在内存中只会存在一份,因为类只会加载一次,可通过比较哈希值
- 每个类的实例都会记得自己由那个Class实例生成
- 通过Class对象可以完整的得到一个类的完整结构,通过一系列的API方法
- Class对象是放在堆的
- 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(方法、变量名、方法名、访问权限等等)
4.Class常用方法
- 代码演示
packagecom.polar;importjava.lang.reflect.Field;publicclassmethodTest{publicstaticvoidmain(String[]args)throwsException{//Bear类所在路径StringclassFullPath="com.polar.Bear";//创建对应的Class对象Class<?>aClass=Class.forName(classFullPath);//输出Class类对象的归属System.out.println(aClass);//输出运输类型System.out.println(aClass.getClass());//输出包名System.out.println(aClass.getPackage().getName());//输出全类名System.out.println(aClass.getName());//创建对象实例Objecto=aClass.newInstance();System.out.println(o);//通过反射获取属性Fieldname=aClass.getField("name");System.out.println(name.get(o));//通过反射对属性进行复制name.set(o,"Polarbear");System.out.println(name.get(o));//通过反射获取所有字段得属性Field[]fields=aClass.getFields();//字段属性for(Fieldfield:fields){System.out.println(field.getName());}//字段属性的值for(Fieldfield:fields){System.out.println(field.get(o));}}}5.获取Class对象的方式
- Class.forName(编译阶段):已知类的全类名,多用于配置文件、读取类的全路径、加载类
- 类名.class(加载阶段):用于参数传递
- 对象.getClass(运行阶段):有对象实例
- 类的加载器阶获取对象
- 基本数据类型获取对对象
- 基本数据类型的包装类获取对象
packagecom.polarBear;publicclassDemo01{publicstaticvoidmain(String[]args)throwsException{//处于编译阶段,已知全类名StringclassAllPath="com.polarBear.Bear";Class<?>aClass=Class.forName(classAllPath);System.out.println(aClass);//处于加载阶段,多用于参数传递Class<Bear>bearClass=Bear.class;System.out.println(bearClass);//处于运行阶段,有对象实例Bearbear=newBear();Class<?extendsBear>aClass1=bear.getClass();System.out.println(aClass1);//通过加载器获取类的对象/** * 先得到类加载器 * 通过类加载得到Class对象 */ClassLoaderclassLoader=bear.getClass().getClassLoader();Class<?>aClass2=classLoader.loadClass(classAllPath);System.out.println(aClass2);System.out.println(aClass.hashCode());System.out.println(bearClass.hashCode());System.out.println(aClass1.hashCode());System.out.println(aClass2.hashCode());//基本数据类型获得Class类对象Class<Integer>integerClass=int.class;System.out.println(integerClass);//基本数据类型的包装类,通过 .TYPR 得到Class对象Class<Integer>type=Integer.TYPE;System.out.println(type);}}通过比较他们的哈希值可知是否为同一个对象
6.那些类型有Class对象
- 外部类、内部类
- interface:接口
- 数组
- enum:枚举
- annotation:注解
- 基本数据类型
- Void
7.类加载
- 反射机制是Java实现动态语言的关键,也就是通过反射实现类动态加载
- 动态加载:运行时加载需要类,如果运行时不用该类,则不报错,降低了依赖性
- 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
8.类加载阶段
- 加载Loading:JVM在该阶段的主要目的是将字节码文件从不同的数据源(class文件、jar包、网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
- 连接Linking:
1.验证Verifica:相当于连接得子阶段,目的是确保class文件字节流中包含得信息符合当前虚拟机的要求,使其不会威胁当前虚拟机的安全。验证内容包括:文件格式验证、元数据验证、字节码验证、符号引用验证。可以考虑关闭大部分的类验证,来缩短虚拟机类加载得时间。
2.准备Preparation:JVM会在该阶段对静态变量分配内存并进行默认初始化(0、0L、null、false)。这些变量所使用的内存都将在方法区中进行分配
3.解析Resolution:虚拟机将常量池内的符号引用替换为直接引用的过程 - 初始化Initialization:到了初始化阶段才真正开始执行类中定义的java程序,依次自动收集类中所有静态变量的赋值动作和静态代码块的语句,并进行合并