Java——反射(reflection)详解
文章目录
- 反射(reflection)
- 引出反射
- Java Reflection
- java反射机制可以完成
- 反射相关的主要类:
- 反射优点和缺点
- 反射调用优化-关闭访问检查
- Class类
- 基本介绍
- Class类的常用方法:
- 获取Class 对象:
- 拓展:哪些类型有Class对象
- 类加载
- 基本说明
- 类加载时机
- 加载阶段
- 连接阶段-解析
- Initialiaztion(初始化)
- 通过反射获取类的结构信息
- 第一组:java.lang.Class 类
- 第二组: java.lang.reflect.Field 类
- 通过反射创建对象
- 通过反射访问类中的成员
- 访问属性
- 访问方法
- 应用案例
反射(reflection)
引出反射
- 使用Propertier 类,可以读写配置文件
Propertier properties = new Properties(); properties.load(new FileInputStream("src\\re.properties"))//原路径 String classfullPath = properties.get("classfullpath").toString();//得到类信息 String method = properties.get("method").toString();//得到方法信息 System.out.println("classfullpath="+ classfulllpath); System,out.println("method="+ method);
- 创建对象,传统的方法,行不通 ====> 反射机制
- 使用反射机制解决
//(1)加载类,返回Class类型的对象cls Class acalss = Class.forName(classfullpath); //(2)通过 cls 得到你加载的类 Cat 的对象实例 Object o = cls.newInstance(); System.out.println(o.getClass());// 运行类型 //(3)通过 cls 得到你加载的类 Cat 的methodName "hi" 的方法对象 // 即:在反射中,可以把方法视为对象(万物皆对象) Method method1 = cls.getMethod(methodName); //(4)通过method1 调用方法: 即通过方法对象来实现调用方法 method1.invoke(o); //传统方法 对象.方法(), 反射机制 方法.invoke(对象)说明:即通过外部文件配置,在不修改源码情况下,来控制程序,也符合设计模式的ocp原则(开闭原则:不修改源码,扩容功能)
Java Reflection
- 反射机制允许程序在执行期借助于Reflection API 取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。
- 加载完类之后,在堆中就产生了一个Class 类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过一个镜子看见类的结构,所以,形象的称之为:反射。
- Java反射机制原理示意图
java反射机制可以完成
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时的得到任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
反射相关的主要类:
- java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
- java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
- java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
- java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
反射优点和缺点
- 优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
- 缺点:使用反射基本是解释执行,对执行速度有影响。
反射调用优化-关闭访问检查
- Method和Field、Constructor对象都有setAccessible() 方法
- setAccessible作用和禁用访问安全检查的开关
- 参数值为true表示 反射的对象在使用时取消访问检查,提高反射的效率。参数值为fasle则表示反射的对象执行访问检查
Class类
基本介绍
- Class类也是类,因此也继承Object类
- Class类对象不是new出来的,而是系统创建的
- 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
- 每个类的实例都会记得自己是由哪个Class实例所生成的
- 通过Class对象可以完整地得到一个类的完成结构,通过一系列API
- Class对象时存放在堆的
- 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括 方法代码, 变量名, 方法名, 请求权限等等)
Class类的常用方法:
String classAllPath = "reflection.Car";//获取到Car 类对应的 Class 对象// <?>表示不确定的java 类型Class<?> aClass = Class.forName(classAllPath);//输出clsSystem.out.println(aClass); //显示aClass 对象,是哪个类的Class reflection.CarSystem.out.println(Class.class); //输出aClass 运行类型 java.lang.Class//3. 得到包名System.out.println(aClass.getPackage().getName());//4.全类名System.out.println(aClass.getName());//5.通过aClass 创建一个对象实例Car car =(Car) aClass.getConstructor().newInstance();System.out.println(car);//6. 通过反射获取属性 brandField color = aClass.getField("color");System.out.println(color.get(car));//7. 通过反射给属性赋值color.set(car,"黄色");System.out.println(color.get(car));//8. 遍历所有属性System.out.println("====================");Field[] fields = aClass.getFields();for( Field n : fields){System.out.println(n.getName());}
获取Class 对象:
public static void main(String[] args) throws Exception {//1.Class.forNameString classAllPath = "reflection.Car";Class<?> aClass1 = Class.forName(classAllPath);Object o = aClass1.getConstructor().newInstance();Field color = aClass1.getField("color");System.out.println(color.get(o));//2. 类名.classClass carClass2 = Car.class;System.out.println(carClass2);//3.对象.getClass(),应用场景,有对象实例Car car = new Car();Class aClass3 = car.getClass();System.out.println(aClass3);//4.通过类的加载器(4中类加载器)来获取到类的Class 对象// (1)先得到类加载器 carClassLoader classLoader = car.getClass().getClassLoader();// (2) 通过类加载器得到Class 对象Class<?> aClass4 = classLoader.loadClass(classAllPath);System.out.println(aClass4);// 上四个均为同一个对象System.out.println(aClass1.hashCode());System.out.println(carClass2.hashCode());System.out.println(aClass3.hashCode());System.out.println(aClass4.hashCode());//5.基本数据类型(int,char,boolean,float,double,byte,long,short)按如下方式得到Class类对象//Class aClass = 基本数据类型.classClass<Integer> integerClass = int.class;System.out.println(integerClass);Class<Character> characterClass = char.class;//6.基本数据类型对应的包装类,可以通过.type得到Class类对象//Class aClass = 包装类.TYPE;Class<Integer> integerClass1 = Integer.class;System.out.println(integerClass1);Class<Boolean> booleanClass = Boolean.class; }
拓展:哪些类型有Class对象
- 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
- interface: 接口
- 数组
- enum: 枚举
- annotation : 注解
- 基本数据类型
- void
类加载
基本说明
反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载.
- 静态加载:编译时加载相关的类, 如果没有则报错,依赖性太强
- 动态加载: 运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性 ( 反射动态加载)
类加载时机
- 当创建对象时(new) //静态加载
- 当子类被加载时 //静态加载
- 调用类中的静态成员时 //静态加载
- 通过反射 //动态加载
加载阶段
JVM 在该阶段的主要目的是将字节码从不同的数据源(可能是class 文件、也可能是jar包,甚至网络) 转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class 对象
public int n1 = 10; public static int n2 = 20; public static final int n3 = 30;// n1 是实例属性,不是静态变量,因此在准备阶段,是不会分配内存 // n2 是静态变量,分配内存 n2 是默认初始化 0,而不是20 // n3 是static final 是常量,他和静态变量不一样,因为一旦赋值就不变 n3 = 30
连接阶段-解析
虚拟机将常量池内的符号引用替换为直接引用的过程
Initialiaztion(初始化)
- 到初始化阶段,才真正开始执行类中定义的java 程序代码,此阶段是执行 () 方法的过程
- () 方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并.
- 虚拟机会保证一个类的() 方法在多线程环境中被正确地加锁、同步、如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的() 方法,其他线程都需要阻塞等待,知道活动线程执行() 方法完毕
通过反射获取类的结构信息
第一组:java.lang.Class 类
- getName:获取全类名
- getSimpleName:获取简单类名
- getFields: 获取所有public 修饰的属性, 包含本类一级父类的
- getDeclaredFields: 获取本类中所有属性
- getMethods: 获取所有public 修饰的方法,包含本类以及父类的
- getDeclaredMethods: 获取本类中所有方法
- getConstructors: 获取所有public 修饰的构造器,包含本类所有public
- getDeclaredConstructors: 获取本类中 所有的构造器
- getPackage: 以Package 形式返回 包信息
- getSuperClass: 以Class 形式返回父类信息
- getInterfaces: 以Class[] 形式返回接口信息
- getAnnotations: 以Annotation[] 形式返回注解信息
第二组: java.lang.reflect.Field 类
getModfiers:以int 形式返回修饰符
[说明: 默认修饰符 是0, public 是1 ,private 是 2, protected 是4, static 是8 ,final 是 16]
getType:
以Class 形式返回类型
getName: 返回属性名
通过反射创建对象
- 方式一: 调用类中的public 修饰的无参构造器
- 方式二: 调用类中的指定构造器
- Class类相关方法
- newInstance : 调用类中的无参构造器, 获取对应类的对象
- getConstructor(Class…cls): 根据参数列表,获取对应的public 构造器对象
- getDecalaredConstructor(Class…cls ): 根据参数列表,获取对应的构造器对象
- Constructor 类相关方法
- setAccessible: 暴破
- newInstance(Object…obj): 调用构造器
通过反射访问类中的成员
访问属性
- 根据属性名获取Field对象
Field f = cls 对象.getDeclareField(属性名);
- 暴力破解: f.setAccseeible(true); //f 是Field
- 访问 f.set(o, 值); syso(f.get(o)); //o表示对象
- 注意: 如果是静态属性,则set 和 get中的参数o, 可以写成null
Class<?> aClass = Class.forName("reflection.Student");Object o = aClass.getConstructor().newInstance();System.out.println(o.getClass());//3.使用反射得到 age 属性Field age = aClass.getField("age");age.set(o,100);System.out.println(o);//4.使用反射操作name 属性Field name = aClass.getDeclaredField("name"); // name.setAccessible(true);name.set(o,"Pink");// 因为name是static 属性,因此 o 也可以写出nullSystem.out.println(o);
访问方法
- 根据方法名和参数列表获取Method方法对象 : Method m = cls.getDeclaredMethod(方法名, xx.class);
- 获取对象 : Object o = clazz.newInstance();
- 暴破: m.setAccessible(true);
- 访问: Object returnValue = m.invlke(o, 实参列表);
- 注意: 如果是静态方法, 则invoke 的参数o, 也可以写成null;
//1.得到Boss类对应的Class对象Class<?> aClass = Class.forName("reflection.Boss");//2.创建对象Object o = aClass.getConstructor().newInstance();//3. 得到hi方法对象Method hi = aClass.getMethod("hi", String.class);//4. 调用System.out.println(hi.invoke(o,"Tom"));//5.调用private static 方法Method declaredMethod = aClass.getDeclaredMethod("say", int.class, String.class,char.class);declaredMethod.setAccessible(true);System.out.println(declaredMethod.invoke(o,20,"Jack",'w'));//在反射中,如果方法有返回值,统一按照 Object 返回
应用案例
Class<?> aClass = Class.forName("java.io.File");Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println("File类中的构造器为=" + declaredConstructor);}Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class);String FilePath ="E:\\myNew.txt";Object file = declaredConstructor.newInstance(FilePath);Method createNewFile = aClass.getMethod("createNewFile");//得到方法的对象createNewFile.invoke(file);
Java——反射(reflection)详解相关推荐
- java 反射机制详解
火星十一郎 海纳百川, 有容乃大,QQ:791909235,Tel:13137910179 posts - 774, comments - 556, trackbacks - 0, articles ...
- java反射机制详解篇一(基础)
反射基础 首先来看一下最常规的创建对象的方式: ObjectClass clazz = new ObjectClass(); 当程序执行到new ObjectClass的时候,java虚拟机会加载Ob ...
- C#反射(Reflection)详解
1. 什么是反射 2. 命名空间与装配件的关系 3. 运行期得到类型信息有什么用 4. 如何使用反射获取类型 5. 如何根据类型来动态创建对象 6. 如何获取方法以及动态调用方法 7. 动态创建委托 ...
- java反射 invoke详解
2019独角兽企业重金招聘Python工程师标准>>> JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法 ...
- java反射机制详解_Java反射机制详解
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反 ...
- java反射机制详解_JAVA反射机制详解_JSP/Java编程_互联网开发技术网_传播最新的编程技术_php361.com...
今天,下午在和朋友聊天的时候,聊起了反射这个话题. 我们就从下面这个段简单的代码开始吧. 这个代码输出什么,想必大部分的读者跟我一样,会很快地知道答案:0 1 2 3 4 5 6 7 8 9.事实也是 ...
- [转]Java反射机制详解
目录 1反射机制是什么 2反射机制能做什么 3反射机制的相关API ·通过一个对象获得完整的包名和类名 ·实例化Class类对象 ·获取一个对象的父类与实现的接口 ·获取某个类中的全部构造函数 - 详 ...
- Java 反射机制详解:私有方法调用头大?如何通过反射调用类中的私有方法?
文章目录 前言 一.私有方法在本类中直接调用 1.1.在本类中实例化,调用私有方法 1.2.尝试在其他类直接调用私有方法(错误示范) 二.使用反射实例化类强制调用私有方法 2.1.使用类加载器加载被调 ...
- Java反射体系详解
文章目录 1.获取一个类的对应的Class对象 (Class的C是大写) (1)调用Object提供的getClass方法 (2)类名称 . class (3)调用Class类提供的静态方法:Clas ...
- Java反射技术详解
前言 相信很多人都知道反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的,比如最初的很多注解框架,后来因为java反射影响性能,所以被运行时注解APT替 ...
最新文章
- 如何搭建以太坊私有链
- com.android.phone已停止 vivo,oppo,vivo应用程序终止通知不在android fcm中出...
- Bootstrap4+MySQL前后端综合实训-Day03-AM【折叠、模态框】
- 制作css开关,纯css实现开关效果
- docker安装ubuntu镜像
- 如何在没有安全启动或 TPM 2.0 的传统 BIOS 上安装 Windows 11
- Oozie分布式任务的工作流——Sqoop篇
- 码农小汪-Hibernate学习6-hibernate中Annocation修饰属性
- 子网掩码-掩码位-反掩码 对照表
- 身份证验证判断、身份证正则表达式、15位、18位身份证验证
- db2 删除索引_[收录量]史上最全的百度索引量下降原因分析及解
- 如何打造高绩效的研发团队
- 小米手机部和平台部组织调整 前者设参谋部、触控部
- 聊聊我的英语学习经验
- 使用pydub的坑-----Permission denied: 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\tmpmt80te3g.wav'
- 我的服务器被挖矿了,原因竟是。。。
- linux下fdisk命令实战案例之详解
- 2008年MBA全国联考英语考试大纲
- 当前市场主流蓝牙音频SOC
- 前世、叶伸伸北京个人演唱会成功举行 用歌声唱出音乐梦想