java 反射机制_基础篇:深入解析JAVA反射机制
反射的概念
java 的放射机制:在程序运行时,程序有能力获取一个类的所有方法和属性;并且对于任意一个对象,可以调用它的任意方法或者获取其属性
通俗解析:java 文件需要编译成. class 文件才能被 jvm 加载使用, 对象的. class 数据在 jvm 里就是 Class;我们如果能拿到这个 Class对象,就能获取该 Class对应的对象类型,及在该类型声明的方法和属性值;还可以根据 Class创建相应的类型对象,通过 Field,Method 反过来操作对象
java 相关类介绍
类名 | 描述 |
---|---|
Class | 代表类的实体,在运行的 Java 应用程序中表示类或者接口 |
Field | 类的成员变量(成员变量也称为类的属性) |
Method | 类的方法 |
Constructor | 类的构造方法 |
获取 Class 的三种方法
- 1 通过已知的类型获取 class
// 根据Example 获取Class =》Example.classpublic Class getExample(){ Class clazz = Example.class;return clazz;}
- 2 通过实例对象获取 class
public Class getExampleByInstance(){ Example example = new Example(); // getClass是Object类里面的方法;《?》 是通配符 Class clazz = example.getClass();return (Class)clazz;}
- 3 通过 Class.forName 获取全路径指定类名的 class
/\*\* forName0 本地方法,C++实现,jvm调用 \* 1 className 是个类名 2 initialize 是否延迟加载 3 loader 加载器 \*/private static native Class forName0(String className, boolean initialize, ClassLoader loader, Class caller) throws ClassNotFoundException;
public static Class forName(String className) throws ClassNotFoundException { Class caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }// 两个forName方法最终都会调用forName0方法去加载class public static Class forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException { .... return forName0(name, initialize, loader, caller); }
// 示例:通过java.lang.Integer public Class getInteger()throws ClassNotFoundException{ Class clazz = Class.forName("java.lang.Integer");return (Class)clazz;}
JAVA 反射 API
- Class 常用操作方法
//获取所有的构造方法 / private publicpublic Constructor\[\] getDeclaredConstructors()//获取特定的构造方法 / private publicpublic Constructor getDeclaredConstructor(Class... parameterTypes) //获取类的父类public native Class getSuperclass() //获取类实现的接口private Class\[\] getInterfaces(boolean cloneArray) //获取在类内定义的内部类或接口public Class\[\] getDeclaredClasses()//获取所有的方法public Method\[\] getDeclaredMethods() throws SecurityException//根据方法名和参数获得特定的方法public Method getDeclaredMethod(String name, Class... parameterTypes) //获取类型的定义的所有属性public Field\[\] getFields() throws SecurityException// 根据属性命名获得特定的Fieldpublic Field getField(String name)
- Method 常用的操作方法
//获得方法的放回类型public Class getReturnType() //获得方法的传入参数类型public Class\[\] getParameterTypes() //obj是实例对象,args是方法,反过来由Method控制对象的方法调用public Object invoke(Object obj, Object... args)
- Field 常用的操作方法
//属性与obj相等则返回truepublic boolean equals(Object obj)//获得obj中对应的属性值public Object get(Object obj)//设置obj中对应属性值public void set(Object obj, Object value)
- Constructor
//根据传递的参数创建类的对象:initargs 构造方法参数public T newInstance(Object... initargs)
- 1 根据 class 创建对象
//方式一 clazz.newInstance()Class clazz = Example.class;Example example = clazz.newInstance();//方式二 先获取再由Constructor:clazz.getConstructors()/getConstructor(...) //再由Constructor.newInstance 方法构造对象-----------------------------------------public class Example { private int value; public Example(){ } // 如果只声明有参构造函数,clazz.newInstance()会报错 public Example(Integer value){ this.value = value; } static public void main(String\[\] args) throws Exception{ Class clazz = Example.class; //根据指定构造函数参数获取Constructor Constructor constructor = clazz.getConstructor(Integer.class); Example example = constructor.newInstance(100); System.out.println(example.value); }}
- 2 由 class 获取 Field,并操作实例的属性
public class Example { private int value , count; static public void main(String\[\] args) throws Exception{ Class clazz = Example.class; //获取所有的属性,getField只能获取public的属性 Field\[\] fs = clazz.getDeclaredFields(); //根据名称获取指定 Field Field value = clazz.getDeclaredField("value"); Example example = clazz.newInstance(); //使用反射机制可以打破封装性,导致了java对象的属性不安全 value.setAccessible(true); //setAccessible(true)让private的参数可赋值操作 //由Field反过去设置example的值 value.set(example,100); System.out.println(example.value); }}
- 3 由 class 获取 Method,并反射调用实例方法
public class Example { public static void main(String\[\] args) throws Exception { Class clazz = Example.class; Example example = clazz.newInstance(); Method\[\] methods = clazz.getDeclaredMethods(); //getDeclaredMethod和getMethod是:getMethod只能返回public的方法 Method method = clazz.getDeclaredMethod("hello", String.class); method.setAccessible(true); method.invoke(example, "cscw"); } private void hello(String name) { System.out.println(name + " Hello!"); }}-----cscw Hello!
反射机制应用的场景
1 动态拓展:假设有同一组类是实现相同的接口,并且类的加载方式不限制。当我们需要那种具体类实现的功能时,只需加载. class 文件,并获取对应的 Class对象。可以由 Class 或者 Constructor 实例化对象 instance;根据接口定义,可以获取 Class里的某一方法 Method,并配合 instance 反射调用功能方法
2 Spring 的 IOC 就是基于反射机制实现
3 JDK 的动态代理
反射和 JDK 动态代理
- 在 Java 的 java.lang.reflect 包下提供了一个 Proxy 类和一个 InvocationHandler 接口。通过这个类和接口可以生成 JDK 动态代理类或动态代理对象
public interface InvocationHandler { //所有方法都会调用此代理方法 Object invoke(Object var1, Method var2, Object\[\] var3) throws Throwable;} public class Proxy implements Serializable{ ... //根据interfaces和InvocationHandler生成代理对象 public static Object newProxyInstance(ClassLoader loader, Class\[\] interfaces, InvocationHandler h) ... }
JDK 的动态代理由 Proxy 和 InvocationHandler 实现;而被代理对象必须实现一个接口。代理对象由 Proxy 生成,可转为接口 interface 的实现类对象 OBJ。当调用 OBJ 的方法时,则会触发 InvocationHandler.invoke,参数依次为「代理对象」,「Method 对象」, 和「方法 Method 所需的参数」。在 invoke 方法可以加入拓展的逻辑,如日志记录操作;「并可以在 invoke 里利用反射的技术调用被代理对象方法」
示例
public class ExampleFactory implements InvocationHandler{ private T target; //被代理对象 public T bind(T obj){ target = obj;return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this); } /\*\* Object o 是代理对象; o的方法调用 -> ExampleFactory.invoke \* invoke(...) -> 在invoke方法里面 反射调用代理对象方法+增强逻辑 \*/ @Override public Object invoke(Object o, Method method, Object\[\] objects) throws Throwable { //增强逻辑 System.out.println("log start"); //反射调用被代理对象方法 Object result = method.invoke(target,objects); System.out.println("log end");return result; }}-----------public interface Face { void hello(String name);}---------//被代理对象必须实现一个接口,并由接口方法对方提供功能public class Example implements Face { public void hello(String name) { System.out.println(name + " Hello!"); } public static void main(String\[\] args) { //ExampleFactory 相当于一个中介人 ExampleFactory factory = new ExampleFactory<>(); //example 是代理对象 Face example = exampleProxy.bind(new Example()); example.hello("思婷"); }}-----log start思婷 Hello!log end
欢迎指正文中错误
java 反射机制_基础篇:深入解析JAVA反射机制相关推荐
- java peek函数_基础篇:JAVA.Stream函数,优雅的数据流操作
写在开头:本文是转载于掘金上的一篇文章,已获得原作者授权,我会在文章最后放上原作者和原文链接. 前言 平时操作集合数据,我们一般都是for或者iterator去遍历,不是很好看.java提供了Stre ...
- java的博_小博老师解析Java核心技术 ——I/O流
[引言] 我们在学习Java编程的时候,经常会遇到文件数据的各类操作,这类操作一般都会借助于JDK中的I/O流对象.我们知道JDK中I/O流的实现类有很多种类型,那么在实际操作中我们该如何取舍呢?今天 ...
- java参数化查询_小博老师解析Java核心技术 ——JDBC参数化查询(二)
[步骤阅读四]SQL注入 按照以上方式开发,确实已经完成了基本的用户登录业务需求,但是这么做的话可以会出现一个比较严重的问题,那就是容易被SQL注入.所谓SQL注入,就是在需要用户填写信息,并且这些信 ...
- invader的java学习第一天基础篇
invader的java学习第一天基础篇 一.java主要历史 ①java是Sun公司的产品,09年被Oracle公司收购. ②java语言之父:詹姆士高斯林 二.jdk.jre.jvm三者关系 jd ...
- 你所需要的java基础篇深入解析大汇总
java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...
- 东华大学2020考研计算机复试准备上机题解析答案_基础篇 前言
东华2020考研复试准备上机题解析答案_基础篇 前言 大家好,我是今年参加东华大学研究生入学考试的学生,前不久东华大学发布了关于复试上机的通知,还有题库供大家练习.我于是刷完了所有的题目,并且把题目和 ...
- java语言程序设计基础篇课后答案_《Java语言程序设计:基础篇》课后复习题答案-第十五章.pdf...
<Java语言程序设计:基础篇>课后复习题答案-第十五章 Chapter15Graphics 1. Theycoordinateshouldincreaseandthexcoordinat ...
- 学习笔记:Java 并发编程①_基础知识入门
若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 视频下载: ...
- Spring5源码 - 13 Spring事件监听机制_@EventListener源码解析
文章目录 Pre 概览 开天辟地的时候初始化的处理器 @EventListener EventListenerMethodProcessor afterSingletonsInstantiated 小 ...
最新文章
- JS 处理鼠标滚轮事件
- 整数划分递归相关问题
- C#_获取文件路径中的文件名_扩展名
- crosstool-ng 编译交叉工具链的常见错误及解决办法
- Java面试题:单例设计模式、适配器模式的不同方式
- 浅谈算法和数据结构: 二 基本排序算法
- 面试必考:秒杀系统的9个核心知识点,一次性打包给你
- 活动验证码/兑换码生成
- viper4android最新,蝰蛇音效viper4android rx-ViPER4Android FX开发版下载v2.6.0.2安卓正式版-西西软件下载...
- 固定表头和固定列表格解决方案
- linux下libreoffice增加字体,Linux下Libreoffice增加字体
- c++:过滤多余的空格
- form表单内子元素组件按钮button事件冲突 - Vue
- 智密-腾讯云直播 MLVB 插件优化教程:六步提升拉流速度+降低直播延迟
- 无线攻击及密码破解的四种方式详解
- IDEA中WEB项目结构和Artifacts设置
- 并行接口电路8255A的基本使用——三种工作方式的时序图的具体讲解
- SSM框架和SSH框架的详细对比
- 尝试在电脑端使用调试模式修改手机游戏的参数达到外挂效果
- 【半导体先进工艺制程技术系列】FinFET和UTB-SOI简介